/*
* Copyright (C) 2019 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "core/EnumSet.hpp"
#include "core/StreamLogger.hpp"
#include "core/String.hpp"
#include "metadata/Exception.hpp"
#include "metadata/IAudioFileParser.hpp"
#include "metadata/Types.hpp"
namespace lms::metadata
{
std::ostream& operator<<(std::ostream& os, const Lyrics& lyrics)
{
os << "\tTitle display name: " << lyrics.displayTitle << std::endl;
os << "\tArtist display name: " << lyrics.displayArtist << std::endl;
os << "\tAlbum display name: " << lyrics.displayAlbum << std::endl;
os << "\tOffset: " << lyrics.offset.count() << "ms" << std::endl;
os << "\tLanguage: " << lyrics.language << std::endl;
os << "\tSynchronized: " << !lyrics.synchronizedLines.empty() << std::endl;
for (const auto& [timestamp, line] : lyrics.synchronizedLines)
os << "\t" << core::stringUtils::formatTimestamp(timestamp) << " '" << line << "'" << std::endl;
for (const auto& line : lyrics.unsynchronizedLines)
os << "\t'" << line << "'" << std::endl;
return os;
}
std::ostream& operator<<(std::ostream& os, const AudioProperties& audioProperties)
{
os << "\tBitrate: " << audioProperties.bitrate << " bps" << std::endl;
os << "\tBitsPerSample: " << audioProperties.bitsPerSample << std::endl;
os << "\tChannelCount: " << audioProperties.channelCount << std::endl;
os << "\tDuration: " << std::fixed << std::setprecision(2) << audioProperties.duration.count() / 1000. << "s" << std::endl;
os << "\tSampleRate: " << audioProperties.sampleRate << std::endl;
return os;
}
std::ostream& operator<<(std::ostream& os, const Artist& artist)
{
os << artist.name;
if (artist.mbid)
os << " (" << artist.mbid->getAsString() << ")";
if (artist.sortName)
os << " '" << *artist.sortName << "'";
return os;
}
std::ostream& operator<<(std::ostream& os, const Release& release)
{
os << release.name;
if (release.sortName != release.name)
os << " '" << release.sortName << "'";
os << std::endl;
for (std::string_view releaseType : release.releaseTypes)
std::cout << "\tRelease type: " << releaseType << std::endl;
if (release.mbid)
os << "\tRelease MBID = " << release.mbid->getAsString() << std::endl;
if (release.groupMBID)
os << "\tRelease Group MBID = " << release.groupMBID->getAsString() << std::endl;
if (release.mediumCount)
std::cout << "\tMediumCount: " << *release.mediumCount << std::endl;
std::cout << "\tIsCompilation: " << std::boolalpha << release.isCompilation << std::endl;
for (std::string_view label : release.labels)
std::cout << "\tLabel: " << label << std::endl;
for (std::string_view country : release.countries)
std::cout << "\tCountry: " << country << std::endl;
if (!release.barcode.empty())
std::cout << "\tBarcode: " << release.barcode << std::endl;
if (!release.comment.empty())
std::cout << "\tComment: " << release.comment << std::endl;
if (!release.artistDisplayName.empty())
std::cout << "\tDisplay artist: " << release.artistDisplayName << std::endl;
for (const Artist& artist : release.artists)
std::cout << "\tRelease artist: " << artist << std::endl;
return os;
}
std::ostream& operator<<(std::ostream& os, const Medium& medium)
{
if (!medium.name.empty())
os << medium.name;
os << std::endl;
if (medium.position)
os << "\tPosition: " << *medium.position << std::endl;
if (!medium.media.empty())
os << "\tMedia: " << medium.media << std::endl;
if (medium.trackCount)
std::cout << "\tTrackCount: " << *medium.trackCount << std::endl;
if (medium.replayGain)
std::cout << "\tReplay gain: " << *medium.replayGain << std::endl;
if (medium.release)
std::cout << "Release: " << *medium.release;
return os;
}
std::ostream& operator<<(std::ostream& os, Track::Advisory advisory)
{
switch (advisory)
{
case Track::Advisory::Clean:
os << "clean";
break;
case Track::Advisory::Explicit:
os << "Explicit";
break;
case Track::Advisory::Unknown:
os << "Unknown";
break;
}
return os;
}
const char* imageTypeToString(Image::Type type)
{
switch (type)
{
case Image::Type::Other:
return "Other";
case Image::Type::FileIcon:
return "FileIcon";
case Image::Type::OtherFileIcon:
return "OtherFileIcon";
case Image::Type::FrontCover:
return "FrontCover";
case Image::Type::BackCover:
return "BackCover";
case Image::Type::LeafletPage:
return "LeafletPage";
case Image::Type::Media:
return "Media";
case Image::Type::LeadArtist:
return "LeadArtist";
case Image::Type::Artist:
return "Artist";
case Image::Type::Conductor:
return "Conductor";
case Image::Type::Band:
return "Band";
case Image::Type::Composer:
return "Composer";
case Image::Type::Lyricist:
return "Lyricist";
case Image::Type::RecordingLocation:
return "RecordingLocation";
case Image::Type::DuringRecording:
return "DuringRecording";
case Image::Type::DuringPerformance:
return "DuringPerformance";
case Image::Type::MovieScreenCapture:
return "MovieScreenCapture";
case Image::Type::ColouredFish:
return "ColouredFish";
case Image::Type::Illustration:
return "Illustration";
case Image::Type::BandLogo:
return "BandLogo";
case Image::Type::PublisherLogo:
return "PublisherLogo";
case Image::Type::Unknown:
break;
}
return "Unknown";
}
std::ostream& operator<<(std::ostream& os, const Image& image)
{
os << "type = " << imageTypeToString(image.type) << std::endl;
if (!image.description.empty())
os << "\tdesc = " << image.description << std::endl;
os << "\tmimeType = " << image.mimeType << std::endl;
os << "\tsize = " << image.data.size() << std::endl;
return os;
}
void parseMetaData(IAudioFileParser& parser, const std::filesystem::path& file)
{
using namespace metadata;
const auto start{ std::chrono::steady_clock::now() };
std::unique_ptr