Make some properties mandatory

This commit is contained in:
badaix 2021-06-17 12:24:30 +02:00
parent 4c2636f358
commit 8a0d538eda
2 changed files with 100 additions and 44 deletions

View file

@ -19,10 +19,11 @@
#ifndef PROPERTIES_HPP #ifndef PROPERTIES_HPP
#define PROPERTIES_HPP #define PROPERTIES_HPP
#include <boost/optional.hpp>
#include <set> #include <set>
#include <string> #include <string>
#include <boost/optional.hpp>
#include "common/aixlog.hpp" #include "common/aixlog.hpp"
#include "common/json.hpp" #include "common/json.hpp"
@ -60,6 +61,31 @@ static std::ostream& operator<<(std::ostream& os, PlaybackStatus playback_status
} }
static PlaybackStatus playback_status_from_string(std::string& status)
{
if (status == "playing")
return PlaybackStatus::kPlaying;
else if (status == "paused")
return PlaybackStatus::kPaused;
else if (status == "stopped")
return PlaybackStatus::kStopped;
else
return PlaybackStatus::kUnknown;
}
static std::istream& operator>>(std::istream& is, PlaybackStatus& playback_status)
{
std::string status;
playback_status = PlaybackStatus::kUnknown;
if (is >> status)
playback_status = playback_status_from_string(status);
else
playback_status = PlaybackStatus::kUnknown;
return is;
}
enum class LoopStatus enum class LoopStatus
{ {
kNone = 0, kNone = 0,
@ -92,6 +118,30 @@ static std::ostream& operator<<(std::ostream& os, LoopStatus loop_status)
} }
static LoopStatus loop_status_from_string(std::string& status)
{
if (status == "none")
return LoopStatus::kNone;
else if (status == "track")
return LoopStatus::kTrack;
else if (status == "playlist")
return LoopStatus::kPlaylist;
else
return LoopStatus::kUnknown;
}
static std::istream& operator>>(std::istream& is, LoopStatus& loop_status)
{
std::string status;
if (is >> status)
loop_status = loop_status_from_string(status);
else
loop_status = LoopStatus::kUnknown;
return is;
}
class Properties class Properties
{ {
@ -104,11 +154,11 @@ public:
/// https://www.musicpd.org/doc/html/protocol.html#tags /// https://www.musicpd.org/doc/html/protocol.html#tags
/// The current playback status /// The current playback status
boost::optional<PlaybackStatus> playback_status; PlaybackStatus playback_status;
/// The current loop / repeat status /// The current loop / repeat status
boost::optional<LoopStatus> loop_status; boost::optional<LoopStatus> loop_status;
/// The current playback rate /// The current playback rate
boost::optional<float> rate; float rate;
/// A value of false indicates that playback is progressing linearly through a playlist, while true means playback is progressing through a playlist in some /// A value of false indicates that playback is progressing linearly through a playlist, while true means playback is progressing through a playlist in some
/// other order. /// other order.
boost::optional<bool> shuffle; boost::optional<bool> shuffle;
@ -136,14 +186,12 @@ public:
json toJson() const json toJson() const
{ {
json j; json j;
addTag(j, "playbackStatus", to_string(playback_status));
if (loop_status.has_value()) if (loop_status.has_value())
addTag(j, "loopStatus", boost::optional<std::string>(to_string(loop_status.value()))); addTag(j, "loopStatus", boost::optional<std::string>(to_string(loop_status.value())));
addTag(j, "rate", rate);
addTag(j, "shuffle", shuffle); addTag(j, "shuffle", shuffle);
addTag(j, "volume", volume); addTag(j, "volume", volume);
addTag(j, "rate", rate);
if (playback_status.has_value())
addTag(j, "playbackStatus", boost::optional<std::string>(to_string(playback_status.value())));
addTag(j, "position", position); addTag(j, "position", position);
addTag(j, "minimumRate", minimum_rate); addTag(j, "minimumRate", minimum_rate);
addTag(j, "maximumRate", maximum_rate); addTag(j, "maximumRate", maximum_rate);
@ -171,38 +219,20 @@ public:
boost::optional<std::string> opt; boost::optional<std::string> opt;
readTag(j, "loopStatus", opt);
if (opt.has_value())
{
if (*opt == "none")
loop_status = LoopStatus::kNone;
else if (*opt == "track")
loop_status = LoopStatus::kTrack;
else if (*opt == "playlist")
loop_status = LoopStatus::kPlaylist;
else
loop_status = LoopStatus::kUnknown;
}
else
loop_status = boost::none;
readTag(j, "shuffle", shuffle);
readTag(j, "volume", volume);
readTag(j, "rate", rate);
readTag(j, "playbackStatus", opt); readTag(j, "playbackStatus", opt);
if (opt.has_value()) if (!opt.has_value())
{
if (*opt == "playing")
playback_status = PlaybackStatus::kPlaying;
else if (*opt == "paused")
playback_status = PlaybackStatus::kPaused;
else if (*opt == "stopped")
playback_status = PlaybackStatus::kStopped; playback_status = PlaybackStatus::kStopped;
else else
playback_status = PlaybackStatus::kUnknown; playback_status = playback_status_from_string(opt.value());
}
readTag(j, "loopStatus", opt);
if (opt.has_value())
loop_status = loop_status_from_string(opt.value());
else else
playback_status = boost::none; loop_status = boost::none;
readTag(j, "rate", rate, 1.0f);
readTag(j, "shuffle", shuffle);
readTag(j, "volume", volume);
readTag(j, "position", position); readTag(j, "position", position);
readTag(j, "minimumRate", minimum_rate); readTag(j, "minimumRate", minimum_rate);
readTag(j, "maximumRate", maximum_rate); readTag(j, "maximumRate", maximum_rate);
@ -238,9 +268,18 @@ private:
} }
template <typename T> template <typename T>
void addTag(json& j, const std::string& tag, const boost::optional<T>& source) const void readTag(const json& j, const std::string& tag, T& dest, const T& def) const
{ {
try boost::optional<T> val;
readTag(j, tag, val);
if (val.has_value())
dest = val.value();
else
dest = def;
}
template <typename T>
void addTag(json& j, const std::string& tag, const boost::optional<T>& source) const
{ {
if (!source.has_value()) if (!source.has_value())
{ {
@ -248,7 +287,15 @@ private:
j.erase(tag); j.erase(tag);
} }
else else
j[tag] = source.value(); addTag(j, tag, source.value());
}
template <typename T>
void addTag(json& j, const std::string& tag, const T& source) const
{
try
{
j[tag] = source;
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {

View file

@ -161,6 +161,15 @@ TEST_CASE("Metatags")
TEST_CASE("Properties") TEST_CASE("Properties")
{ {
std::stringstream ss;
ss << PlaybackStatus::kPlaying;
REQUIRE(ss.str() == "playing");
PlaybackStatus playback_status;
ss >> playback_status;
REQUIRE(playback_status == PlaybackStatus::kPlaying);
REQUIRE(to_string(PlaybackStatus::kPaused) == "paused"); REQUIRE(to_string(PlaybackStatus::kPaused) == "paused");
auto in_json = json::parse(R"( auto in_json = json::parse(R"(
{ {
@ -174,9 +183,9 @@ TEST_CASE("Properties")
// std::cout << in_json.dump(4) << "\n"; // std::cout << in_json.dump(4) << "\n";
Properties props(in_json); Properties props(in_json);
// std::cout << props.toJson().dump(4) << "\n"; std::cout << props.toJson().dump(4) << "\n";
REQUIRE(props.playback_status.has_value()); REQUIRE(props.loop_status.has_value());
auto out_json = props.toJson(); auto out_json = props.toJson();
// std::cout << out_json.dump(4) << "\n"; // std::cout << out_json.dump(4) << "\n";
@ -192,7 +201,7 @@ TEST_CASE("Properties")
props.fromJson(in_json); props.fromJson(in_json);
// std::cout << props.toJson().dump(4) << "\n"; // std::cout << props.toJson().dump(4) << "\n";
REQUIRE(!props.playback_status.has_value()); REQUIRE(!props.loop_status.has_value());
out_json = props.toJson(); out_json = props.toJson();
// std::cout << out_json.dump(4) << "\n"; // std::cout << out_json.dump(4) << "\n";
@ -225,6 +234,6 @@ TEST_CASE("Librespot")
REQUIRE(m[4] == " "); REQUIRE(m[4] == " ");
REQUIRE(m[5] == "librespot_playback::player"); REQUIRE(m[5] == "librespot_playback::player");
REQUIRE(m[6] == "<Tunnel> (310573 ms) loaded"); REQUIRE(m[6] == "<Tunnel> (310573 ms) loaded");
for (const auto& match: m) for (const auto& match : m)
std::cerr << "Match: '" << match << "'\n"; std::cerr << "Match: '" << match << "'\n";
} }