Add Metatags class

This commit is contained in:
badaix 2021-05-18 09:05:36 +02:00
parent 2762687c88
commit f02ba7354b
2 changed files with 254 additions and 12 deletions

198
common/metatags.hpp Normal file
View file

@ -0,0 +1,198 @@
/***
This file is part of snapcast
Copyright (C) 2014-2021 Johannes Pohl
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#ifndef METATAGS_HPP
#define METATAGS_HPP
#include <boost/optional.hpp>
#include <string>
#include "common/aixlog.hpp"
#include "common/json.hpp"
using json = nlohmann::json;
class Metatags
{
public:
/// https://www.musicpd.org/doc/html/protocol.html#tags
/// the song file.
boost::optional<std::string> file;
/// the duration of the song
boost::optional<float> duration;
/// the artist name. Its meaning is not well-defined; see “composer” and “performer” for more specific tags.
boost::optional<std::vector<std::string>> artist;
/// same as artist, but for sorting. This usually omits prefixes such as “The”.
boost::optional<std::vector<std::string>> artist_sort;
/// the album name.
boost::optional<std::string> album;
/// same as album, but for sorting.
boost::optional<std::string> album_sort;
/// on multi-artist albums, this is the artist name which shall be used for the whole album. The exact meaning of this tag is not well-defined.
boost::optional<std::vector<std::string>> album_artist;
/// same as albumartist, but for sorting.
boost::optional<std::vector<std::string>> album_artist_sort;
/// the song title.
// boost::optional<std::string> title;
/// the decimal track number within the album.
// boost::optional<uint16_t> track;
/// a name for this song. This is not the song title. The exact meaning of this tag is not well-defined. It is often used by badly configured internet radio
/// stations with broken tags to squeeze both the artist name and the song title in one tag.
boost::optional<std::string> name;
/// the music genre.
// boost::optional<std::string> genre;
/// the songs release date. This is usually a 4-digit year.
boost::optional<std::string> date;
/// the songs original release date.
boost::optional<std::string> original_date;
/// the artist who composed the song.
// boost::optional<std::string> composer;
/// the artist who performed the song.
boost::optional<std::string> performer;
/// the conductor who conducted the song.
boost::optional<std::string> conductor;
/// “a work is a distinct intellectual or artistic creation, which can be expressed in the form of one or more audio recordings”
boost::optional<std::string> work;
/// “used if the sound belongs to a larger category of sounds/music” (from the IDv2.4.0 TIT1 description).
boost::optional<std::string> grouping;
/// a human-readable comment about this song. The exact meaning of this tag is not well-defined.
// boost::optional<std::string> comment;
/// the decimal disc number in a multi-disc album.
// boost::optional<uint16_t> disc;
/// the name of the label or publisher.
boost::optional<std::string> label;
/// the artist id in the MusicBrainz database.
boost::optional<std::string> musicbrainz_artist_id;
/// the album id in the MusicBrainz database.
boost::optional<std::string> musicbrainz_album_id;
/// the album artist id in the MusicBrainz database.
boost::optional<std::string> musicbrainz_album_artist_id;
/// the track id in the MusicBrainz database.
boost::optional<std::string> musicbrainz_track_id;
/// the release track id in the MusicBrainz database.
boost::optional<std::string> musicbrainz_release_track_id;
/// the work id in the MusicBrainz database.
boost::optional<std::string> musicbrainz_work_id;
/// https://www.freedesktop.org/wiki/Specifications/mpris-spec/metadata/
/// URI: The location of an image representing the track or album. Clients should not assume this will continue to exist when the media player stops giving
/// out the URL
boost::optional<std::string> art_url;
/// The track lyrics
boost::optional<std::string> lyrics;
/// The speed of the music, in beats per minute
boost::optional<uint16_t> bpm;
/// Float: An automatically-generated rating, based on things such as how often it has been played. This should be in the range 0.0 to 1.0
boost::optional<float> auto_rating;
/// A (list of) freeform comment(s)
boost::optional<std::vector<std::string>> comment;
/// The composer(s) of the track
boost::optional<std::vector<std::string>> composer;
/// Date/Time: When the track was created. Usually only the year component will be useful
boost::optional<std::string> content_created;
/// Integer: The disc number on the album that this track is from
boost::optional<uint16_t> disc_number;
/// Date/Time: When the track was first played
boost::optional<std::string> first_used;
/// List of Strings: The genre(s) of the track
boost::optional<std::vector<std::string>> genre;
/// Date/Time: When the track was last played
boost::optional<std::string> last_used;
/// List of Strings: The lyricist(s) of the track
boost::optional<std::vector<std::string>> lyricist;
/// String: The track title
boost::optional<std::string> title;
/// Integer: The track number on the album disc
boost::optional<uint16_t> track_number;
/// URI: The location of the media file.
boost::optional<std::string> url;
/// Integer: The number of times the track has been played.
boost::optional<uint16_t> use_count;
/// Float: A user-specified rating. This should be in the range 0.0 to 1.0.
boost::optional<float> user_rating;
void fromJson(const json& j)
{
addTag(j, "file", file);
addTag(j, "duration", duration);
addTag(j, "artist", artist);
addTag(j, "artistSort", artist_sort);
addTag(j, "album", album);
addTag(j, "albumSort", album_sort);
addTag(j, "albumArtist", album_artist);
addTag(j, "albumArtistSort", album_artist_sort);
addTag(j, "title", title);
addTag(j, "name", name);
addTag(j, "genre", genre);
addTag(j, "date", date);
addTag(j, "originalDate", original_date);
addTag(j, "composer", composer);
addTag(j, "performer", performer);
addTag(j, "conductor", conductor);
addTag(j, "work", work);
addTag(j, "grouping", grouping);
addTag(j, "comment", comment);
addTag(j, "discNumber", disc_number);
addTag(j, "label", label);
addTag(j, "musicbrainzArtistId", musicbrainz_artist_id);
addTag(j, "musicbrainzAlbumId", musicbrainz_album_id);
addTag(j, "musicbrainzAlbumArtistId", musicbrainz_album_artist_id);
addTag(j, "musicbrainzTrackTd", musicbrainz_track_id);
addTag(j, "musicbrainzReleaseTrackId", musicbrainz_release_track_id);
addTag(j, "musicbrainzWorkId", musicbrainz_work_id);
addTag(j, "art_url", art_url);
addTag(j, "lyrics", lyrics);
addTag(j, "bpm", bpm);
addTag(j, "autoRating", auto_rating);
addTag(j, "comment", comment);
addTag(j, "composer", composer);
addTag(j, "contentCreated", content_created);
addTag(j, "discNumber", disc_number);
addTag(j, "firstUsed", first_used);
addTag(j, "genre", genre);
addTag(j, "lastUsed", last_used);
addTag(j, "lyricist", lyricist);
addTag(j, "title", title);
addTag(j, "trackNumber", track_number);
addTag(j, "url", url);
addTag(j, "artUrl", art_url);
addTag(j, "useCount", use_count);
addTag(j, "userRating", user_rating);
}
private:
template <typename T>
void addTag(const json& j, const std::string& tag, boost::optional<T>& dest)
{
try
{
if (!j.contains(tag))
dest = boost::none;
else
dest = j[tag].get<T>();
}
catch (const std::exception& e)
{
LOG(ERROR) << "failed to read tag: '" << tag << "': " << e.what() << '\n';
}
}
};
#endif

View file

@ -19,6 +19,7 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "common/aixlog.hpp"
#include "common/metatags.hpp"
#include "common/utils/string_utils.hpp"
#include "server/streamreader/stream_uri.hpp"
@ -102,3 +103,46 @@ TEST_CASE("Uri")
REQUIRE(uri.query["bitrate"] == "320");
REQUIRE(uri.query["killall"] == "false");
}
TEST_CASE("Metatags")
{
Metatags meta;
meta.fromJson(json::parse(R"({
"STREAM": "Spotify",
"album": "tru.",
"albumArtist": [
"Cro"
],
"albumArtistSort": [
"Cro"
],
"artist": [
"Cro"
],
"artistSort": [
"Cro"
],
"contentCreated": "2017-09-08",
"discNumber": 1,
"duration": 144.77,
"file": "Cro - tru. (2017)/01 - kapitel 1.mp3",
"genre": [
"Hip-Hop"
],
"label": "Chimperator Productions",
"musicbrainzAlbumArtistId": "b2ea6506-645e-4935-8d82-84c3a95fe7f0",
"musicbrainzAlbumId": "621ca91c-bf60-428f-bdad-3b985dd5610c",
"musicbrainzArtistId": "b2ea6506-645e-4935-8d82-84c3a95fe7f0",
"musicbrainzReleasetrackId": "4b24ea6c-eacf-4ae5-a0c3-9387fb99bb5b",
"musicbrainzTrackId": "fa7ef8b1-04cf-47e2-bcd3-9397f470dad5",
"originalDate": "2017",
"title": "kapitel 1",
"track": 1
})"));
REQUIRE(meta.album.has_value());
REQUIRE(meta.album.value() == "tru.");
REQUIRE(meta.genre.has_value());
REQUIRE(meta.genre->size() == 1);
REQUIRE(meta.genre.value().front() == "Hip-Hop");
}