WIP
This commit is contained in:
@@ -266,6 +266,12 @@ Track::getCopyrightURL() const
|
||||
return _copyrightURL != "" ? boost::make_optional<std::string>(_copyrightURL) : boost::none;
|
||||
}
|
||||
|
||||
std::vector<Wt::Dbo::ptr<Artist>>
|
||||
Track::getArtists() const
|
||||
{
|
||||
return std::vector<Wt::Dbo::ptr<Artist>>(_artists.begin(), _artists.end());
|
||||
}
|
||||
|
||||
Wt::Dbo::ptr<TrackFeatures>
|
||||
Track::getTrackFeatures() const
|
||||
{
|
||||
|
||||
+27
-27
@@ -96,33 +96,33 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
void setMBID(const std::string& MBID) { _MBID = MBID; }
|
||||
void setCopyright(const std::string& copyright) { _copyright = std::string(copyright, 0, _maxCopyrightLength); }
|
||||
void setCopyrightURL(const std::string& copyrightURL) { _copyrightURL = std::string(copyrightURL, 0, _maxCopyrightURLLength); }
|
||||
void setArtist(Wt::Dbo::ptr<Artist> artist) { _artist = artist; }
|
||||
void setArtists(std::vector<Wt::Dbo::ptr<Artist>>& artists);
|
||||
void setRelease(Wt::Dbo::ptr<Release> release) { _release = release; }
|
||||
void eraseClusters() { _clusters.clear(); }
|
||||
void eraseFeatures() { /*_trackFeatures.reset();*/ }
|
||||
|
||||
std::size_t getScanVersion() const { return _scanVersion; }
|
||||
boost::optional<std::size_t> getTrackNumber() const;
|
||||
boost::optional<std::size_t> getTotalTrackNumber() const;
|
||||
boost::optional<std::size_t> getDiscNumber() const;
|
||||
boost::optional<std::size_t> getTotalDiscNumber() const;
|
||||
std::string getName() const { return _name; }
|
||||
boost::filesystem::path getPath() const { return _filePath; }
|
||||
std::chrono::milliseconds getDuration() const { return _duration; }
|
||||
boost::optional<int> getYear() const;
|
||||
boost::optional<int> getOriginalYear() const;
|
||||
Wt::WDateTime getLastWriteTime() const { return _fileLastWrite; }
|
||||
Wt::WDateTime getAddedTime() const { return _fileAdded; }
|
||||
const std::vector<unsigned char>& getChecksum() const { return _fileChecksum; }
|
||||
bool hasCover() const { return _hasCover; }
|
||||
const std::string& getMBID() const { return _MBID; }
|
||||
boost::optional<std::string> getCopyright() const;
|
||||
boost::optional<std::string> getCopyrightURL() const;
|
||||
Wt::Dbo::ptr<Artist> getArtist() const { return _artist; }
|
||||
Wt::Dbo::ptr<Release> getRelease() const { return _release; }
|
||||
std::size_t getScanVersion() const { return _scanVersion; }
|
||||
boost::optional<std::size_t> getTrackNumber() const;
|
||||
boost::optional<std::size_t> getTotalTrackNumber() const;
|
||||
boost::optional<std::size_t> getDiscNumber() const;
|
||||
boost::optional<std::size_t> getTotalDiscNumber() const;
|
||||
std::string getName() const { return _name; }
|
||||
boost::filesystem::path getPath() const { return _filePath; }
|
||||
std::chrono::milliseconds getDuration() const { return _duration; }
|
||||
boost::optional<int> getYear() const;
|
||||
boost::optional<int> getOriginalYear() const;
|
||||
Wt::WDateTime getLastWriteTime() const { return _fileLastWrite; }
|
||||
Wt::WDateTime getAddedTime() const { return _fileAdded; }
|
||||
const std::vector<unsigned char>& getChecksum() const { return _fileChecksum; }
|
||||
bool hasCover() const { return _hasCover; }
|
||||
const std::string& getMBID() const { return _MBID; }
|
||||
boost::optional<std::string> getCopyright() const;
|
||||
boost::optional<std::string> getCopyrightURL() const;
|
||||
std::vector<Wt::Dbo::ptr<Artist>> getArtists() const;
|
||||
Wt::Dbo::ptr<Release> getRelease() const { return _release; }
|
||||
std::vector<Wt::Dbo::ptr<Cluster>> getClusters() const;
|
||||
bool hasTrackFeatures() const;
|
||||
Wt::Dbo::ptr<TrackFeatures> getTrackFeatures() const;
|
||||
bool hasTrackFeatures() const;
|
||||
Wt::Dbo::ptr<TrackFeatures> getTrackFeatures() const;
|
||||
|
||||
std::vector<std::vector<Wt::Dbo::ptr<Cluster>>> getClusterGroups(std::vector<Wt::Dbo::ptr<ClusterType>> clusterTypes, std::size_t size) const;
|
||||
|
||||
@@ -148,7 +148,7 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
Wt::Dbo::field(a, _copyright, "copyright");
|
||||
Wt::Dbo::field(a, _copyrightURL, "copyright_url");
|
||||
Wt::Dbo::belongsTo(a, _release, "release", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::belongsTo(a, _artist, "artist", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::hasMany(a, _artists, Wt::Dbo::ManyToMany, "track_artist", "", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::hasMany(a, _clusters, Wt::Dbo::ManyToMany, "track_cluster", "", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::hasMany(a, _playlistEntries, Wt::Dbo::ManyToOne, "track");
|
||||
Wt::Dbo::hasOne(a, _trackFeatures);
|
||||
@@ -181,11 +181,11 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
std::string _copyright;
|
||||
std::string _copyrightURL;
|
||||
|
||||
Wt::Dbo::ptr<Artist> _artist;
|
||||
Wt::Dbo::ptr<Release> _release;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;
|
||||
Wt::Dbo::ptr<Release> _release;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Artist>> _artists;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<TrackListEntry>> _playlistEntries;
|
||||
Wt::Dbo::weak_ptr<TrackFeatures> _trackFeatures;
|
||||
Wt::Dbo::weak_ptr<TrackFeatures> _trackFeatures;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -72,7 +72,20 @@ AvFormat::parse(const boost::filesystem::path& p, bool debug)
|
||||
std::cout << "TAG = " << tag << ", VAL = " << value << std::endl;
|
||||
|
||||
if (tag == "ARTIST")
|
||||
items.insert( std::make_pair(MetaData::Type::Artist, stringTrim( value) ));
|
||||
{
|
||||
if (items.find(MetaData::Type::Artists) == items.end())
|
||||
items[MetaData::Type::Artists] = std::set<std::string>{ stringTrim( value) };
|
||||
}
|
||||
else if (tag == "ARTISTS")
|
||||
{
|
||||
std::vector<std::string> strings {splitString(value, "/;")}; // Picard separator is '/'
|
||||
|
||||
std::set<std::string> artists;
|
||||
for (const std::string& string : strings)
|
||||
artists.insert(stringTrim(string));
|
||||
|
||||
items[MetaData::Type::Artists] = std::move(artists);
|
||||
}
|
||||
else if (tag == "ALBUM")
|
||||
items.insert( std::make_pair(MetaData::Type::Album, stringTrim( value) ));
|
||||
else if (tag == "TITLE")
|
||||
@@ -133,7 +146,13 @@ AvFormat::parse(const boost::filesystem::path& p, bool debug)
|
||||
else if (tag == "MUSICBRAINZ ARTIST ID"
|
||||
|| tag == "MUSICBRAINZ_ARTISTID")
|
||||
{
|
||||
items.insert( std::make_pair(MetaData::Type::MusicBrainzArtistID, stringTrim(value)) );
|
||||
std::vector<std::string> strings {splitString(value, "/")};
|
||||
|
||||
std::set<std::string> mbids;
|
||||
for (const std::string& string : strings)
|
||||
mbids.insert(stringTrim(string));
|
||||
|
||||
items[MetaData::Type::MusicBrainzArtistID] = std::move(mbids);
|
||||
}
|
||||
else if (tag == "MUSICBRAINZ ALBUM ID"
|
||||
|| tag == "MUSICBRAINZ_ALBUMID")
|
||||
@@ -152,7 +171,7 @@ AvFormat::parse(const boost::filesystem::path& p, bool debug)
|
||||
}
|
||||
else if (_clusterTypeNames.find(tag) != _clusterTypeNames.end())
|
||||
{
|
||||
std::vector<std::string> clusterNames = splitString(value, ";,\\");
|
||||
std::vector<std::string> clusterNames = splitString(value, "/,;");
|
||||
|
||||
if (!clusterNames.empty())
|
||||
{
|
||||
@@ -167,7 +186,7 @@ AvFormat::parse(const boost::filesystem::path& p, bool debug)
|
||||
}
|
||||
catch(Av::MediaFileException& e)
|
||||
{
|
||||
return items;
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
return items;
|
||||
|
||||
+34
-31
@@ -22,54 +22,57 @@
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace MetaData
|
||||
{
|
||||
using Clusters = std::map<std::string /* type */, std::set<std::string> /* names */>;
|
||||
|
||||
enum class Type
|
||||
struct Artist
|
||||
{
|
||||
// Name Type of the value
|
||||
Artist, // string
|
||||
Title, // string
|
||||
Album, // string
|
||||
Clusters, // Clusters, ex: { "genre", {"death metal", "brutal death"} }, { "albumgrouping", {"metal"} }
|
||||
Duration, // std::chrono::milliseconds
|
||||
TrackNumber, // size_t
|
||||
DiscNumber, // size_t
|
||||
TotalTrack, // size_t
|
||||
TotalDisc, // size_t
|
||||
Year, // int
|
||||
OriginalYear, // int
|
||||
HasCover, // bool
|
||||
AudioStreams, // vector<AudioStream>
|
||||
MusicBrainzArtistID, // string
|
||||
MusicBrainzAlbumID, // string
|
||||
MusicBrainzTrackID, // string
|
||||
MusicBrainzRecordingID, // string
|
||||
AcoustID, // string
|
||||
Copyright, // string
|
||||
CopyrightURL, // string
|
||||
std::string name;
|
||||
std::string musicBrainzArtistID;
|
||||
};
|
||||
|
||||
// Used by Streams
|
||||
struct Album
|
||||
{
|
||||
std::string name;
|
||||
std::string musicBrainzAlbumID;
|
||||
}
|
||||
|
||||
struct AudioStream
|
||||
{
|
||||
// TODO codec?
|
||||
std::size_t bitRate;
|
||||
unsigned bitRate;
|
||||
};
|
||||
|
||||
// Type and associated data
|
||||
// See enum Type's comments
|
||||
using Items = std::map<Type, boost::any>;
|
||||
using Clusters = std::map<std::string /* type */, std::set<std::string> /* names */>;
|
||||
struct Track
|
||||
{
|
||||
std::vector<Artist> artists;
|
||||
boost::optional<Artist> albumArtist;
|
||||
std::string title;
|
||||
std::string musicBrainzTrackID;
|
||||
std::string musicBrainzRecordID;
|
||||
boost::optional<Album> album;
|
||||
Clusters clusters;
|
||||
std::chrono::milliseconds duration {};
|
||||
boost::optional<std::size_t> trackNumber;
|
||||
boost::optional<std::size_t> totalTrack;
|
||||
boost::optional<std::size_t> discNumber;
|
||||
boost::optional<std::size_t> totalDisc;
|
||||
boost::optional<int> year;
|
||||
boost::optional<int> originalYear;
|
||||
bool hasCover {false};
|
||||
std::vector<AudioStream> audioStreams;
|
||||
std::string acoustId;
|
||||
std::string copyright;
|
||||
std::string copyrightURL;
|
||||
};
|
||||
|
||||
class Parser
|
||||
{
|
||||
public:
|
||||
virtual boost::optional<Items> parse(const boost::filesystem::path& p, bool debug = false) = 0;
|
||||
virtual boost::optional<Track> parse(const boost::filesystem::path& p, bool debug = false) = 0;
|
||||
|
||||
void setClusterTypeNames(const std::set<std::string>& clusterTypeNames) { _clusterTypeNames = clusterTypeNames; }
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ namespace MetaData
|
||||
boost::optional<Items>
|
||||
TagLibParser::parse(const boost::filesystem::path& p, bool debug)
|
||||
{
|
||||
TagLib::FileRef f(p.string().c_str(),
|
||||
TagLib::FileRef f {p.string().c_str(),
|
||||
true, // read audio properties
|
||||
TagLib::AudioProperties::Average);
|
||||
TagLib::AudioProperties::Average};
|
||||
|
||||
if (f.isNull())
|
||||
return boost::none;
|
||||
@@ -47,13 +47,12 @@ TagLibParser::parse(const boost::filesystem::path& p, bool debug)
|
||||
Items items;
|
||||
|
||||
{
|
||||
TagLib::AudioProperties *properties = f.audioProperties();
|
||||
const TagLib::AudioProperties *properties {f.audioProperties() };
|
||||
|
||||
std::chrono::milliseconds duration(properties->length() * 1000);
|
||||
items.insert( std::make_pair(MetaData::Type::Duration, duration) );
|
||||
items[MetaData::Type::Duration] = std::chrono::milliseconds {properties->length() * 1000};
|
||||
|
||||
MetaData::AudioStream audioStream = { .bitRate = static_cast<std::size_t>(properties->bitrate() * 1000) };
|
||||
items.insert( std::make_pair(MetaData::Type::AudioStreams, std::vector<MetaData::AudioStream>(1, audioStream ) ));
|
||||
MetaData::AudioStream audioStream {.bitRate = static_cast<std::size_t>(properties->bitrate() * 1000)};
|
||||
items[MetaData::Type::AudioStreams] = std::vector<MetaData::AudioStream> {audioStream};
|
||||
}
|
||||
|
||||
// Not that good embedded pictures handling
|
||||
@@ -71,7 +70,7 @@ TagLibParser::parse(const boost::filesystem::path& p, bool debug)
|
||||
if (f.tag())
|
||||
{
|
||||
MetaData::Clusters clusters;
|
||||
TagLib::PropertyMap properties = f.file()->properties();
|
||||
const TagLib::PropertyMap& properties {f.file()->properties()};
|
||||
|
||||
for(auto property : properties)
|
||||
{
|
||||
@@ -93,7 +92,23 @@ TagLibParser::parse(const boost::filesystem::path& p, bool debug)
|
||||
}
|
||||
|
||||
if (tag == "ARTIST")
|
||||
items.insert( std::make_pair(MetaData::Type::Artist, stringTrim( values.front().to8Bit(true))));
|
||||
{
|
||||
// Lower priority than ARTISTS
|
||||
if (items.find(MetaData::Type::Artists) == items.end())
|
||||
items[MetaData::Type::Artists] = std::vector<std::string>{ stringTrim( values.front().to8Bit(true)) };
|
||||
}
|
||||
else if (tag == "ARTISTS")
|
||||
{
|
||||
// Higher priority than ARTISTS
|
||||
std::vector<std::string> strings {splitString(values.front().to8Bit(), "/;")}; // Picard separator is '/'
|
||||
|
||||
std::vector<std::string> artists;
|
||||
for (const std::string& string : strings)
|
||||
artists.emplace_back(stringTrim(string));
|
||||
|
||||
items[MetaData::Type::Artists] = std::move(artists);
|
||||
}
|
||||
|
||||
else if (tag == "ALBUM")
|
||||
items.insert( std::make_pair(MetaData::Type::Album, stringTrim( values.front().to8Bit(true))));
|
||||
else if (tag == "TITLE")
|
||||
@@ -104,7 +119,15 @@ TagLibParser::parse(const boost::filesystem::path& p, bool debug)
|
||||
items.insert( std::make_pair(MetaData::Type::MusicBrainzTrackID, stringTrim( values.front().to8Bit(true))));
|
||||
}
|
||||
else if (tag == "MUSICBRAINZ_ARTISTID")
|
||||
items.insert( std::make_pair(MetaData::Type::MusicBrainzArtistID, stringTrim( values.front().to8Bit(true))));
|
||||
{
|
||||
std::vector<std::string> strings {splitString(values.front().to8Bit(), "/")}; // Picard separator is '/'
|
||||
|
||||
std::vector<std::string> mbids;
|
||||
for (const std::string& string : strings)
|
||||
mbids.emplace_back(stringTrim(string));
|
||||
|
||||
items[MetaData::Type::MusicBrainzArtistID] = std::move(mbids);
|
||||
}
|
||||
else if (tag == "MUSICBRAINZ_ALBUMID")
|
||||
items.insert( std::make_pair(MetaData::Type::MusicBrainzAlbumID, stringTrim( values.front().to8Bit(true))));
|
||||
else if (tag == "MUSICBRAINZ_TRACKID")
|
||||
@@ -113,25 +136,25 @@ TagLibParser::parse(const boost::filesystem::path& p, bool debug)
|
||||
items.insert( std::make_pair(MetaData::Type::AcoustID, stringTrim( values.front().to8Bit(true))));
|
||||
else if (tag == "TRACKTOTAL")
|
||||
{
|
||||
auto totalTrack = readAs<std::size_t>(values.front().to8Bit(true));
|
||||
auto totalTrack {readAs<std::size_t>(values.front().to8Bit(true)) };
|
||||
if (totalTrack)
|
||||
items[MetaData::Type::TotalTrack] = *totalTrack;
|
||||
}
|
||||
else if (tag == "TRACKNUMBER")
|
||||
{
|
||||
// Expecting 'Number/Total'
|
||||
auto strings = splitString(values.front().to8Bit(), "/");
|
||||
std::vector<std::string> strings {splitString(values.front().to8Bit(), "/")};
|
||||
|
||||
if (!strings.empty())
|
||||
{
|
||||
auto number = readAs<std::size_t>(strings[0]);
|
||||
auto number {readAs<std::size_t>(strings[0])};
|
||||
if (number)
|
||||
items.insert( std::make_pair(MetaData::Type::TrackNumber, *number ));
|
||||
|
||||
// Lower priority than TRACKTOTAL
|
||||
if (strings.size() > 1 && items.find(MetaData::Type::TotalTrack) == items.end())
|
||||
{
|
||||
auto totalTrack = readAs<std::size_t>(strings[1]);
|
||||
auto totalTrack {readAs<std::size_t>(strings[1])};
|
||||
if (totalTrack)
|
||||
items[MetaData::Type::TotalTrack] = *totalTrack;
|
||||
}
|
||||
|
||||
@@ -475,7 +475,7 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
|
||||
}
|
||||
|
||||
// ***** Artist
|
||||
Artist::pointer artist;
|
||||
std::set<Artist::pointer> artists;
|
||||
{
|
||||
std::string artistName;
|
||||
std::string artistMusicBrainzID;
|
||||
|
||||
@@ -153,14 +153,16 @@ getSimilarArtists(Wt::Dbo::Session& session, Database::IdType artistId, std::siz
|
||||
if (!track)
|
||||
continue;
|
||||
|
||||
auto trackArtist = track->getArtist();
|
||||
if (!trackArtist || trackArtist.id() == artistId)
|
||||
continue;
|
||||
for (auto trackArtist : track->getArtists())
|
||||
{
|
||||
if (!trackArtist || trackArtist.id() == artistId)
|
||||
continue;
|
||||
|
||||
if (std::find(res.begin(), res.end(), trackArtist.id()) != res.end())
|
||||
continue;
|
||||
if (std::find(res.begin(), res.end(), trackArtist.id()) != res.end())
|
||||
continue;
|
||||
|
||||
res.push_back(trackArtist.id());
|
||||
res.push_back(trackArtist.id());
|
||||
}
|
||||
|
||||
if (res.size() == maxCount)
|
||||
break;
|
||||
|
||||
+2
-2
@@ -55,7 +55,7 @@ bool readList(const std::string& str, const std::string& separators, std::list<s
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
splitString(std::string string, std::string separators)
|
||||
splitString(const std::string& string, const std::string& separators)
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
|
||||
@@ -65,7 +65,7 @@ splitString(std::string string, std::string separators)
|
||||
}
|
||||
|
||||
std::string
|
||||
joinStrings(std::vector<std::string> strings, std::string delimiter)
|
||||
joinStrings(const std::vector<std::string>& strings, const std::string& delimiter)
|
||||
{
|
||||
return boost::algorithm::join(strings, delimiter);
|
||||
}
|
||||
|
||||
+2
-2
@@ -34,10 +34,10 @@ bool
|
||||
readList(const std::string& str, const std::string& separators, std::list<std::string>& results);
|
||||
|
||||
std::vector<std::string>
|
||||
splitString(std::string string, std::string separators);
|
||||
splitString(const std::string& string, const std::string& separators);
|
||||
|
||||
std::string
|
||||
joinStrings(std::vector<std::string> strings, std::string delimiter);
|
||||
joinStrings(const std::vector<std::string>& strings, const std::string& delimiter);
|
||||
|
||||
std::string
|
||||
stringTrim(const std::string& str, const std::string& whitespaces = " \t");
|
||||
|
||||
+126
-105
@@ -1,13 +1,129 @@
|
||||
#include <stdlib.h>
|
||||
#include <chrono>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <Wt/WDate.h>
|
||||
|
||||
#include "av/AvInfo.hpp"
|
||||
#include "metadata/AvFormat.hpp"
|
||||
#include "metadata/TagLibParser.hpp"
|
||||
|
||||
|
||||
void parse(MetaData::Parser& parser, const boost::filesystem::path& file)
|
||||
{
|
||||
parser.setClusterTypeNames( {"MOOD", "GENRE"} );
|
||||
|
||||
boost::optional<MetaData::Items> items {parser.parse(file, true)};
|
||||
if (!items)
|
||||
{
|
||||
std::cerr << "Parsing failed" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "Items:" << std::endl;
|
||||
for (auto item : (*items))
|
||||
{
|
||||
switch (item.first)
|
||||
{
|
||||
case MetaData::Type::Title:
|
||||
std::cout << "Title: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::Artists:
|
||||
for (const std::string& artist : boost::any_cast<std::set<std::string>>(item.second))
|
||||
std::cout << "Artist: " << artist << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::Album:
|
||||
std::cout << "Album: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::Clusters:
|
||||
for (const auto& cluster : boost::any_cast<MetaData::Clusters>(item.second))
|
||||
{
|
||||
std::cout << "Cluster: " << cluster.first << std::endl;
|
||||
for (const auto name : cluster.second)
|
||||
{
|
||||
std::cout << "\t" << name << std::endl;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MetaData::Type::Duration:
|
||||
std::cout << "Duration: " << boost::any_cast<std::chrono::milliseconds>(item.second).count() / 1000 << "s" << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::TrackNumber:
|
||||
std::cout << "Track: " << boost::any_cast<std::size_t>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::TotalTrack:
|
||||
std::cout << "TotalTrack: " << boost::any_cast<std::size_t>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::DiscNumber:
|
||||
std::cout << "Disc: " << boost::any_cast<std::size_t>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::TotalDisc:
|
||||
std::cout << "TotalDisc: " << boost::any_cast<std::size_t>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::Year:
|
||||
std::cout << "Year: " << std::to_string(boost::any_cast<int>(item.second)) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::OriginalYear:
|
||||
std::cout << "Original year: " << std::to_string(boost::any_cast<int>(item.second)) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::HasCover:
|
||||
std::cout << "HasCover = " << std::boolalpha << boost::any_cast<bool>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::AudioStreams:
|
||||
for (const auto& audioStream : boost::any_cast<std::vector<MetaData::AudioStream> >(item.second))
|
||||
std::cout << "Audio stream: " << audioStream.bitRate << " bps" << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::MusicBrainzArtistID:
|
||||
for (const std::string& mbid : boost::any_cast<std::set<std::string>>(item.second))
|
||||
std::cout << "MusicBrainzArtistID: " << mbid << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::MusicBrainzAlbumID:
|
||||
std::cout << "MusicBrainzAlbumID: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::MusicBrainzTrackID:
|
||||
std::cout << "MusicBrainzTrackID: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::MusicBrainzRecordingID:
|
||||
std::cout << "MusicBrainzRecordingID: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::AcoustID:
|
||||
std::cout << "AcoustID: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::Copyright:
|
||||
std::cout << "Copyright: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::CopyrightURL:
|
||||
std::cout << "CopyrightURL: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
@@ -18,116 +134,21 @@ int main(int argc, char *argv[])
|
||||
|
||||
try
|
||||
{
|
||||
MetaData::TagLibParser parser;
|
||||
Av::AvInit();
|
||||
boost::filesystem::path file {argv[1]};
|
||||
|
||||
parser.setClusterTypeNames( {"MOOD", "GENRE"} );
|
||||
|
||||
boost::optional<MetaData::Items> items = parser.parse(argv[1], true);
|
||||
if (!items)
|
||||
{
|
||||
std::cerr << "Parsing failed" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
std::cout << "Using av:" << std::endl;
|
||||
MetaData::AvFormat parser;
|
||||
parse(parser, file);
|
||||
}
|
||||
|
||||
std::cout << "Items:" << std::endl;
|
||||
for (auto item : (*items))
|
||||
{
|
||||
switch (item.first)
|
||||
{
|
||||
case MetaData::Type::Title:
|
||||
std::cout << "Title: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::Artist:
|
||||
std::cout << "Artist: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::Album:
|
||||
std::cout << "Album: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::Clusters:
|
||||
for (const auto& cluster : boost::any_cast<MetaData::Clusters>(item.second))
|
||||
{
|
||||
std::cout << "Cluster: " << cluster.first << std::endl;
|
||||
for (const auto name : cluster.second)
|
||||
{
|
||||
std::cout << "\t" << name << std::endl;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MetaData::Type::Duration:
|
||||
std::cout << "Duration: " << boost::any_cast<std::chrono::milliseconds>(item.second).count() / 1000 << "s" << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::TrackNumber:
|
||||
std::cout << "Track: " << boost::any_cast<std::size_t>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::TotalTrack:
|
||||
std::cout << "TotalTrack: " << boost::any_cast<std::size_t>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::DiscNumber:
|
||||
std::cout << "Disc: " << boost::any_cast<std::size_t>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::TotalDisc:
|
||||
std::cout << "TotalDisc: " << boost::any_cast<std::size_t>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::Year:
|
||||
std::cout << "Year: " << std::to_string(boost::any_cast<int>(item.second)) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::OriginalYear:
|
||||
std::cout << "Original year: " << std::to_string(boost::any_cast<int>(item.second)) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::HasCover:
|
||||
std::cout << "HasCover = " << std::boolalpha << boost::any_cast<bool>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::AudioStreams:
|
||||
for (auto& audioStream : boost::any_cast<std::vector<MetaData::AudioStream> >(item.second))
|
||||
std::cout << "Audio stream: " << audioStream.bitRate << " bps" << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::MusicBrainzArtistID:
|
||||
std::cout << "MusicBrainzArtistID: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::MusicBrainzAlbumID:
|
||||
std::cout << "MusicBrainzAlbumID: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::MusicBrainzTrackID:
|
||||
std::cout << "MusicBrainzTrackID: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::MusicBrainzRecordingID:
|
||||
std::cout << "MusicBrainzRecordingID: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::AcoustID:
|
||||
std::cout << "AcoustID: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::Copyright:
|
||||
std::cout << "Copyright: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
case MetaData::Type::CopyrightURL:
|
||||
std::cout << "CopyrightURL: " << boost::any_cast<std::string>(item.second) << std::endl;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
std::cout << "Using TagLib:" << std::endl;
|
||||
MetaData::TagLibParser parser;
|
||||
parse(parser, file);
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
|
||||
@@ -2,9 +2,11 @@ bin_PROGRAMS = lms-metadata
|
||||
|
||||
lms_metadata_SOURCES = \
|
||||
$(srcdir)/LmsMetadata.cpp \
|
||||
$(top_srcdir)/src/av/AvInfo.cpp \
|
||||
$(top_srcdir)/src/metadata/AvFormat.cpp \
|
||||
$(top_srcdir)/src/metadata/TagLibParser.cpp \
|
||||
$(top_srcdir)/src/utils/Logger.cpp \
|
||||
$(top_srcdir)/src/utils/Utils.cpp \
|
||||
$(top_srcdir)/src/metadata/TagLibParser.cpp
|
||||
$(top_srcdir)/src/utils/Utils.cpp
|
||||
|
||||
lms_metadata_CXXFLAGS=-std=c++14 -Wall -I$(top_srcdir)/src -D_REENTRANT
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ std::ostream& operator<<(std::ostream& os, const Database::Track::pointer& track
|
||||
auto genreClusters = track->getClusterGroups({genreClusterType}, 1);
|
||||
for (auto genreCluster : genreClusters)
|
||||
os << genreCluster.front()->getName() << " - ";
|
||||
if (track->getArtist())
|
||||
os << track->getArtist()->getName() << " - ";
|
||||
for (auto artist : track->getArtists())
|
||||
os << artist->getName() << " - ";
|
||||
if (track->getRelease())
|
||||
os << track->getRelease()->getName() << " - ";
|
||||
os << track->getName() << "]";
|
||||
|
||||
Reference in New Issue
Block a user