Merge branch 'v0.21.x'

This commit is contained in:
Max Kellermann 2019-07-29 11:15:04 +02:00
commit 991bbea875
7 changed files with 69 additions and 14 deletions

6
NEWS
View File

@ -12,6 +12,12 @@ ver 0.22 (not yet released)
- ffmpeg: new plugin based on FFmpeg's libavfilter library - ffmpeg: new plugin based on FFmpeg's libavfilter library
- hdcd: new plugin based on FFmpeg's "af_hdcd" for HDCD playback - hdcd: new plugin based on FFmpeg's "af_hdcd" for HDCD playback
ver 0.21.12 (not yet released)
* decoder
- opus: ignore case in replay gain tag names
* Windows
- support backslash in relative URIs loaded from playlists
ver 0.21.11 (2019/07/03) ver 0.21.11 (2019/07/03)
* input * input
- tidal: deprecated because Tidal has changed the protocol - tidal: deprecated because Tidal has changed the protocol

View File

@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd" package="org.musicpd"
android:installLocation="auto" android:installLocation="auto"
android:versionCode="34" android:versionCode="35"
android:versionName="0.21.11"> android:versionName="0.21.12">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/>

View File

@ -22,6 +22,7 @@
#include "lib/xiph/XiphTags.hxx" #include "lib/xiph/XiphTags.hxx"
#include "tag/Handler.hxx" #include "tag/Handler.hxx"
#include "tag/ParseName.hxx" #include "tag/ParseName.hxx"
#include "util/ASCII.hxx"
#include "ReplayGainInfo.hxx" #include "ReplayGainInfo.hxx"
#include "util/NumberParser.hxx" #include "util/NumberParser.hxx"
#include "util/StringView.hxx" #include "util/StringView.hxx"
@ -44,7 +45,7 @@ ScanOneOpusTag(StringView name, StringView value,
ReplayGainInfo *rgi, ReplayGainInfo *rgi,
TagHandler &handler) noexcept TagHandler &handler) noexcept
{ {
if (rgi != nullptr && name.Equals("R128_TRACK_GAIN")) { if (rgi != nullptr && name.EqualsIgnoreCase("R128_TRACK_GAIN")) {
/* R128_TRACK_GAIN is a Q7.8 fixed point number in /* R128_TRACK_GAIN is a Q7.8 fixed point number in
dB */ dB */
@ -52,7 +53,8 @@ ScanOneOpusTag(StringView name, StringView value,
const auto l = ParseInt64(value, &endptr, 10); const auto l = ParseInt64(value, &endptr, 10);
if (endptr > value.begin() && endptr == value.end()) if (endptr > value.begin() && endptr == value.end())
rgi->track.gain = double(l) / 256.; rgi->track.gain = double(l) / 256.;
} else if (rgi != nullptr && name.Equals("R128_ALBUM_GAIN")) { } else if (rgi != nullptr &&
name.EqualsIgnoreCase("R128_ALBUM_GAIN")) {
/* R128_ALBUM_GAIN is a Q7.8 fixed point number in /* R128_ALBUM_GAIN is a Q7.8 fixed point number in
dB */ dB */

View File

@ -25,6 +25,9 @@
#include "util/UriUtil.hxx" #include "util/UriUtil.hxx"
#include "song/DetachedSong.hxx" #include "song/DetachedSong.hxx"
#include <algorithm>
#include <string>
#include <string.h> #include <string.h>
static void static void
@ -66,6 +69,22 @@ playlist_check_translate_song(DetachedSong &song, const char *base_uri,
base_uri = nullptr; base_uri = nullptr;
const char *uri = song.GetURI(); const char *uri = song.GetURI();
#ifdef _WIN32
if (!PathTraitsUTF8::IsAbsolute(uri) && strchr(uri, '\\') != nullptr) {
/* Windows uses the backslash as path separator, but
the MPD protocol uses the (forward) slash by
definition; to allow backslashes in relative URIs
loaded from playlist files, this step converts all
backslashes to (forward) slashes */
std::string new_uri(uri);
std::replace(new_uri.begin(), new_uri.end(), '\\', '/');
song.SetURI(std::move(new_uri));
uri = song.GetURI();
}
#endif
if (base_uri != nullptr && !uri_has_scheme(uri) && if (base_uri != nullptr && !uri_has_scheme(uri) &&
!PathTraitsUTF8::IsAbsolute(uri)) !PathTraitsUTF8::IsAbsolute(uri))
song.SetURI(PathTraitsUTF8::Build(base_uri, uri)); song.SetURI(PathTraitsUTF8::Build(base_uri, uri));

View File

@ -23,6 +23,7 @@
#include "event/Thread.hxx" #include "event/Thread.hxx"
#include "decoder/DecoderList.hxx" #include "decoder/DecoderList.hxx"
#include "decoder/DecoderPlugin.hxx" #include "decoder/DecoderPlugin.hxx"
#include "decoder/DecoderAPI.hxx" /* for class StopDecoder */
#include "input/Init.hxx" #include "input/Init.hxx"
#include "input/InputStream.hxx" #include "input/InputStream.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
@ -126,10 +127,16 @@ try {
MyChromaprintDecoderClient client; MyChromaprintDecoderClient client;
if (plugin->file_decode != nullptr) { if (plugin->file_decode != nullptr) {
plugin->FileDecode(client, Path::FromFS(c.uri)); try {
plugin->FileDecode(client, Path::FromFS(c.uri));
} catch (StopDecoder) {
}
} else if (plugin->stream_decode != nullptr) { } else if (plugin->stream_decode != nullptr) {
auto is = InputStream::OpenReady(c.uri, client.mutex); auto is = InputStream::OpenReady(c.uri, client.mutex);
plugin->StreamDecode(client, *is); try {
plugin->StreamDecode(client, *is);
} catch (StopDecoder) {
}
} else { } else {
fprintf(stderr, "Decoder plugin is not usable\n"); fprintf(stderr, "Decoder plugin is not usable\n");
return EXIT_FAILURE; return EXIT_FAILURE;

View File

@ -21,6 +21,7 @@
#include "event/Thread.hxx" #include "event/Thread.hxx"
#include "decoder/DecoderList.hxx" #include "decoder/DecoderList.hxx"
#include "decoder/DecoderPlugin.hxx" #include "decoder/DecoderPlugin.hxx"
#include "decoder/DecoderAPI.hxx" /* for class StopDecoder */
#include "DumpDecoderClient.hxx" #include "DumpDecoderClient.hxx"
#include "input/Init.hxx" #include "input/Init.hxx"
#include "input/InputStream.hxx" #include "input/InputStream.hxx"
@ -116,10 +117,16 @@ try {
DumpDecoderClient client; DumpDecoderClient client;
if (plugin->file_decode != nullptr) { if (plugin->file_decode != nullptr) {
plugin->FileDecode(client, Path::FromFS(c.uri)); try {
plugin->FileDecode(client, Path::FromFS(c.uri));
} catch (StopDecoder) {
}
} else if (plugin->stream_decode != nullptr) { } else if (plugin->stream_decode != nullptr) {
auto is = InputStream::OpenReady(c.uri, client.mutex); auto is = InputStream::OpenReady(c.uri, client.mutex);
plugin->StreamDecode(client, *is); try {
plugin->StreamDecode(client, *is);
} catch (StopDecoder) {
}
} else { } else {
fprintf(stderr, "Decoder plugin is not usable\n"); fprintf(stderr, "Decoder plugin is not usable\n");
return EXIT_FAILURE; return EXIT_FAILURE;

View File

@ -207,7 +207,6 @@ TEST_F(TranslateSongTest, Insecure)
TEST_F(TranslateSongTest, Secure) TEST_F(TranslateSongTest, Secure)
{ {
DetachedSong song1(uri1, MakeTag1b()); DetachedSong song1(uri1, MakeTag1b());
auto s1 = ToString(song1);
auto se = ToString(DetachedSong(uri1, MakeTag1c())); auto se = ToString(DetachedSong(uri1, MakeTag1c()));
const SongLoader loader(nullptr, nullptr); const SongLoader loader(nullptr, nullptr);
@ -226,14 +225,12 @@ TEST_F(TranslateSongTest, InDatabase)
loader)); loader));
DetachedSong song2(uri2, MakeTag2b()); DetachedSong song2(uri2, MakeTag2b());
auto s1 = ToString(song2);
auto se = ToString(DetachedSong(uri2, MakeTag2c())); auto se = ToString(DetachedSong(uri2, MakeTag2c()));
EXPECT_TRUE(playlist_check_translate_song(song2, nullptr, EXPECT_TRUE(playlist_check_translate_song(song2, nullptr,
loader)); loader));
EXPECT_EQ(se, ToString(song2)); EXPECT_EQ(se, ToString(song2));
DetachedSong song3("/music/foo/bar.ogg", MakeTag2b()); DetachedSong song3("/music/foo/bar.ogg", MakeTag2b());
s1 = ToString(song3);
se = ToString(DetachedSong(uri2, MakeTag2c())); se = ToString(DetachedSong(uri2, MakeTag2c()));
EXPECT_TRUE(playlist_check_translate_song(song3, nullptr, EXPECT_TRUE(playlist_check_translate_song(song3, nullptr,
loader)); loader));
@ -249,7 +246,6 @@ TEST_F(TranslateSongTest, Relative)
/* map to music_directory */ /* map to music_directory */
DetachedSong song1("bar.ogg", MakeTag2b()); DetachedSong song1("bar.ogg", MakeTag2b());
auto s1 = ToString(song1);
auto se = ToString(DetachedSong(uri2, MakeTag2c())); auto se = ToString(DetachedSong(uri2, MakeTag2c()));
EXPECT_TRUE(playlist_check_translate_song(song1, "/music/foo", EXPECT_TRUE(playlist_check_translate_song(song1, "/music/foo",
insecure_loader)); insecure_loader));
@ -262,7 +258,6 @@ TEST_F(TranslateSongTest, Relative)
/* legal because secure=true */ /* legal because secure=true */
DetachedSong song3("bar.ogg", MakeTag1b()); DetachedSong song3("bar.ogg", MakeTag1b());
s1 = ToString(song3);
se = ToString(DetachedSong(uri1, MakeTag1c())); se = ToString(DetachedSong(uri1, MakeTag1c()));
EXPECT_TRUE(playlist_check_translate_song(song3, "/foo", EXPECT_TRUE(playlist_check_translate_song(song3, "/foo",
secure_loader)); secure_loader));
@ -270,9 +265,28 @@ TEST_F(TranslateSongTest, Relative)
/* relative to http:// */ /* relative to http:// */
DetachedSong song4("bar.ogg", MakeTag2a()); DetachedSong song4("bar.ogg", MakeTag2a());
s1 = ToString(song4);
se = ToString(DetachedSong("http://example.com/foo/bar.ogg", MakeTag2a())); se = ToString(DetachedSong("http://example.com/foo/bar.ogg", MakeTag2a()));
EXPECT_TRUE(playlist_check_translate_song(song4, "http://example.com/foo", EXPECT_TRUE(playlist_check_translate_song(song4, "http://example.com/foo",
insecure_loader)); insecure_loader));
EXPECT_EQ(se, ToString(song4)); EXPECT_EQ(se, ToString(song4));
} }
TEST_F(TranslateSongTest, Backslash)
{
const SongLoader loader(reinterpret_cast<const Database *>(1),
storage);
DetachedSong song1("foo\\bar.ogg", MakeTag2b());
#ifdef _WIN32
/* on Windows, all backslashes are converted to slashes in
relative paths from playlists */
auto se = ToString(DetachedSong(uri2, MakeTag2c()));
EXPECT_TRUE(playlist_check_translate_song(song1, nullptr,
loader));
EXPECT_EQ(se, ToString(song1));
#else
/* backslash only supported on Windows */
EXPECT_FALSE(playlist_check_translate_song(song1, nullptr,
loader));
#endif
}