2018-03-06 23:09:15 +01:00
|
|
|
#ifndef TAG_PARSER_TAG_H
|
|
|
|
#define TAG_PARSER_TAG_H
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2015-09-06 19:57:33 +02:00
|
|
|
#include "./tagtarget.h"
|
2018-03-07 01:17:50 +01:00
|
|
|
#include "./tagvalue.h"
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
#include <c++utilities/io/binaryreader.h>
|
|
|
|
|
2019-03-13 19:06:42 +01:00
|
|
|
#include <cstdint>
|
2015-04-22 19:22:01 +02:00
|
|
|
#include <string>
|
2018-03-07 01:17:50 +01:00
|
|
|
#include <type_traits>
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2018-03-06 23:09:15 +01:00
|
|
|
namespace TagParser {
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Specifies the tag type.
|
|
|
|
*
|
|
|
|
* \sa Tag::type()
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
enum class TagType : unsigned int {
|
2015-04-22 19:22:01 +02:00
|
|
|
Unspecified = 0x00, /**< The tag type is unspecified. */
|
2018-06-03 20:38:32 +02:00
|
|
|
Id3v1Tag = 0x01, /**< The tag is a TagParser::Id3v1Tag. */
|
|
|
|
Id3v2Tag = 0x02, /**< The tag is a TagParser::Id3v2Tag. */
|
|
|
|
Mp4Tag = 0x04, /**< The tag is a TagParser::Mp4Tag. */
|
|
|
|
MatroskaTag = 0x08, /**< The tag is a TagParser::MatroskaTag. */
|
|
|
|
VorbisComment = 0x10, /**< The tag is a TagParser::VorbisComment. */
|
|
|
|
OggVorbisComment = 0x20 /**< The tag is a TagParser::OggVorbisComment. */
|
2015-04-22 19:22:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Specifies the field.
|
|
|
|
*
|
|
|
|
* These "known" fields are used to specify a field without using
|
2021-07-02 03:00:50 +02:00
|
|
|
* the field identifier used by the underlying tag type.
|
2015-04-22 19:22:01 +02:00
|
|
|
*
|
|
|
|
* Not all fields are supported by all tag types (see Tag::supportsField()).
|
|
|
|
*
|
2019-01-01 23:38:39 +01:00
|
|
|
* Mapping proposed by HAK: https://wiki.hydrogenaud.io/index.php?title=Tag_Mapping
|
|
|
|
*
|
2015-04-22 19:22:01 +02:00
|
|
|
* \sa Tag::type()
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
enum class KnownField : unsigned int {
|
2018-03-21 20:40:51 +01:00
|
|
|
Invalid = std::numeric_limits<unsigned int>::max(), /**< invalid field name, do not map this value when subclassing Tag */
|
2015-04-22 19:22:01 +02:00
|
|
|
Title = 0, /**< title */
|
|
|
|
Album, /**< album/collection */
|
|
|
|
Artist, /**< artist/band */
|
|
|
|
Genre, /**< genre */
|
|
|
|
Comment, /**< comment */
|
|
|
|
Bpm, /**< beats per minute */
|
|
|
|
Bps, /**< beats per second */
|
|
|
|
Lyricist, /**< lyricist */
|
|
|
|
TrackPosition, /**< track/part number and total track/part count */
|
|
|
|
DiskPosition, /**< disk number and total disk count */
|
|
|
|
PartNumber, /**< track/part number */
|
|
|
|
TotalParts, /**< total track/part count */
|
|
|
|
Encoder, /**< encoder */
|
|
|
|
RecordDate, /**< record date */
|
|
|
|
Performers, /**< performers */
|
|
|
|
Length, /**< length */
|
|
|
|
Language, /**< language */
|
|
|
|
EncoderSettings, /**< encoder settings */
|
|
|
|
Lyrics, /**< lyrics */
|
|
|
|
SynchronizedLyrics, /**< synchronized lyrics */
|
|
|
|
Grouping, /**< grouping */
|
|
|
|
RecordLabel, /**< record label */
|
|
|
|
Cover, /**< cover */
|
|
|
|
Composer, /**< composer */
|
|
|
|
Rating, /**< rating */
|
2015-07-27 23:10:35 +02:00
|
|
|
Description, /**< description */
|
2019-01-01 23:38:39 +01:00
|
|
|
Vendor, /**< vendor */
|
|
|
|
AlbumArtist, /**< album artist */
|
2020-04-22 23:54:10 +02:00
|
|
|
ReleaseDate, /**< release date */
|
2022-04-05 23:30:37 +02:00
|
|
|
Subtitle, /**< subtitle */
|
|
|
|
LeadPerformer, /** lead performer */
|
|
|
|
Arranger, /** the person who arranged the piece */
|
|
|
|
Conductor, /** conductor */
|
|
|
|
Director, /** director */
|
|
|
|
AssistantDirector, /** assistant director */
|
|
|
|
DirectorOfPhotography, /** director of photography */
|
|
|
|
SoundEngineer, /** sound engineer */
|
|
|
|
ArtDirector, /** art director */
|
|
|
|
ProductionDesigner, /** production designer */
|
|
|
|
Choregrapher, /** choregrapher */
|
|
|
|
CostumeDesigner, /** costume designer */
|
|
|
|
Actor, /** actor */
|
|
|
|
Character, /** character */
|
|
|
|
WrittenBy, /** written by */
|
|
|
|
ScreenplayBy, /** screenplay by */
|
|
|
|
EditedBy, /** edited by */
|
|
|
|
Producer, /** producer */
|
|
|
|
Coproducer, /** coproducer */
|
|
|
|
ExecutiveProducer, /** executive producer */
|
|
|
|
DistributedBy, /** distributed by */
|
|
|
|
MasteredBy, /** mastered by */
|
|
|
|
EncodedBy, /** encoded by */
|
|
|
|
MixedBy, /** mixed by */
|
|
|
|
RemixedBy, /** remixed by */
|
|
|
|
ProductionStudio, /** production studio */
|
|
|
|
ThanksTo, /** thanks to */
|
|
|
|
Publisher, /** publisher */
|
|
|
|
Mood, /** mood */
|
|
|
|
OriginalMediaType, /** original media type */
|
|
|
|
ContentType, /** content type */
|
|
|
|
Subject, /** subject */
|
|
|
|
Keywords, /** keywords */
|
|
|
|
Summary, /** summary */
|
|
|
|
Synopsis, /** synopsis */
|
|
|
|
InitialKey, /** initial key */
|
|
|
|
Period, /** period */
|
|
|
|
LawRating, /** law rating */
|
|
|
|
EncodingDate, /** encoding date */
|
|
|
|
TaggingDate, /** tagging date */
|
|
|
|
OriginalReleaseDate, /** original release date */
|
|
|
|
DigitalizationDate, /** digitalization date */
|
|
|
|
WritingDate, /** writing date */
|
|
|
|
PurchasingDate, /** purchasing date */
|
|
|
|
RecordingLocation, /** recording location */
|
|
|
|
CompositionLocation, /** composition location */
|
|
|
|
ComposerNationality, /** composer nationality */
|
|
|
|
PlayCounter, /** play counter */
|
|
|
|
Measure, /** measure */
|
|
|
|
Tuning, /** tuning */
|
|
|
|
ISRC, /** International Standard Recording Code */
|
|
|
|
MCDI, /** binary dump of the TOC of the CDROM that this item was taken from */
|
|
|
|
ISBN, /** International Standard Book Number */
|
|
|
|
Barcode, /** barcode */
|
|
|
|
CatalogNumber, /** catalog number */
|
|
|
|
LabelCode, /** label code */
|
|
|
|
LCCN, /** Library of Congress Control Number */
|
|
|
|
IMDB, /** Internet Movie Database ID */
|
|
|
|
TMDB, /** The Movie DB “movie_id” or “tv_id” identifier for movies/TV shows */
|
|
|
|
TVDB, /** The TV Database “Series ID” or “Episode ID” identifier for TV shows */
|
|
|
|
PurchaseItem, /** purchase item URL */
|
|
|
|
PurchaseInfo, /** purchase info */
|
|
|
|
PurchaseOwner, /** purchase owner */
|
|
|
|
PurchasePrice, /** purchase price */
|
|
|
|
PurchaseCurrency, /** purchase currency */
|
|
|
|
Copyright, /** copyright */
|
|
|
|
ProductionCopyright, /** production copyright */
|
|
|
|
License, /** license */
|
|
|
|
TermsOfUse, /** terms of use */
|
2015-04-22 19:22:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
2018-06-03 20:38:32 +02:00
|
|
|
* \brief The first valid entry in the TagParser::KnownField enum.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
|
|
|
constexpr KnownField firstKnownField = KnownField::Title;
|
|
|
|
|
|
|
|
/*!
|
2018-06-03 20:38:32 +02:00
|
|
|
* \brief The last valid entry in the TagParser::KnownField enum.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
2022-04-05 23:30:37 +02:00
|
|
|
constexpr KnownField lastKnownField = KnownField::TermsOfUse;
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
/*!
|
2018-06-03 20:38:32 +02:00
|
|
|
* \brief The number of valid entries in the TagParser::KnownField enum.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
|
|
|
constexpr unsigned int knownFieldArraySize = static_cast<unsigned int>(lastKnownField) + 1;
|
|
|
|
|
|
|
|
/*!
|
2020-04-22 23:54:10 +02:00
|
|
|
* \brief Returns whether the specified \a field is deprecated and should not be used anymore.
|
|
|
|
*/
|
|
|
|
constexpr bool isKnownFieldDeprecated(KnownField field)
|
|
|
|
{
|
2021-02-01 17:11:08 +01:00
|
|
|
CPP_UTILITIES_UNUSED(field)
|
|
|
|
return false;
|
2020-04-22 23:54:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the next known field skipping any deprecated fields. Returns KnownField::Invalid if there is not next field.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
|
|
|
constexpr KnownField nextKnownField(KnownField field)
|
|
|
|
{
|
2020-04-22 23:54:10 +02:00
|
|
|
const auto next = field == lastKnownField ? KnownField::Invalid : static_cast<KnownField>(static_cast<int>(field) + 1);
|
|
|
|
return isKnownFieldDeprecated(next) ? nextKnownField(next) : next;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
class TAG_PARSER_EXPORT Tag {
|
2015-04-22 19:22:01 +02:00
|
|
|
public:
|
|
|
|
virtual ~Tag();
|
|
|
|
|
|
|
|
virtual TagType type() const;
|
2021-01-30 21:53:06 +01:00
|
|
|
virtual std::string_view typeName() const;
|
2015-04-22 19:22:01 +02:00
|
|
|
std::string toString() const;
|
|
|
|
virtual TagTextEncoding proposedTextEncoding() const;
|
|
|
|
virtual bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
|
|
|
virtual const TagValue &value(KnownField field) const = 0;
|
2016-08-14 22:50:45 +02:00
|
|
|
virtual std::vector<const TagValue *> values(KnownField field) const;
|
2015-04-22 19:22:01 +02:00
|
|
|
virtual bool setValue(KnownField field, const TagValue &value) = 0;
|
2016-08-14 22:50:45 +02:00
|
|
|
virtual bool setValues(KnownField field, const std::vector<TagValue> &values);
|
2015-04-22 19:22:01 +02:00
|
|
|
virtual bool hasField(KnownField field) const = 0;
|
|
|
|
virtual void removeAllFields() = 0;
|
|
|
|
const std::string &version() const;
|
2021-03-20 21:26:25 +01:00
|
|
|
std::uint64_t size() const;
|
2015-04-22 19:22:01 +02:00
|
|
|
virtual bool supportsTarget() const;
|
|
|
|
const TagTarget &target() const;
|
2022-05-03 23:48:24 +02:00
|
|
|
TagTarget &target();
|
2015-04-22 19:22:01 +02:00
|
|
|
void setTarget(const TagTarget &target);
|
2016-05-26 01:59:22 +02:00
|
|
|
virtual TagTargetLevel targetLevel() const;
|
2021-01-30 21:53:06 +01:00
|
|
|
std::string_view targetLevelName() const;
|
2016-05-26 01:59:22 +02:00
|
|
|
bool isTargetingLevel(TagTargetLevel tagTargetLevel) const;
|
|
|
|
std::string targetString() const;
|
2021-03-20 21:26:25 +01:00
|
|
|
virtual std::size_t fieldCount() const = 0;
|
2015-04-22 19:22:01 +02:00
|
|
|
virtual bool supportsField(KnownField field) const = 0;
|
|
|
|
virtual TagDataType proposedDataType(KnownField field) const;
|
|
|
|
virtual bool supportsDescription(KnownField field) const;
|
|
|
|
virtual bool supportsMimeType(KnownField field) const;
|
2018-07-13 12:25:00 +02:00
|
|
|
virtual bool supportsMultipleValues(KnownField field) const;
|
2021-03-20 21:26:25 +01:00
|
|
|
virtual std::size_t insertValues(const Tag &from, bool overwrite);
|
2016-08-05 01:46:31 +02:00
|
|
|
virtual void ensureTextValuesAreProperlyEncoded() = 0;
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
protected:
|
|
|
|
Tag();
|
|
|
|
|
|
|
|
std::string m_version;
|
2021-03-20 21:26:25 +01:00
|
|
|
std::uint64_t m_size;
|
2015-04-22 19:22:01 +02:00
|
|
|
TagTarget m_target;
|
|
|
|
};
|
|
|
|
|
|
|
|
inline TagType Tag::type() const
|
|
|
|
{
|
|
|
|
return TagType::Unspecified;
|
|
|
|
}
|
|
|
|
|
2021-01-30 21:53:06 +01:00
|
|
|
inline std::string_view Tag::typeName() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return "unspecified";
|
|
|
|
}
|
|
|
|
|
|
|
|
inline TagTextEncoding Tag::proposedTextEncoding() const
|
|
|
|
{
|
|
|
|
return TagTextEncoding::Latin1;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool Tag::canEncodingBeUsed(TagTextEncoding encoding) const
|
|
|
|
{
|
|
|
|
return encoding == proposedTextEncoding();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const std::string &Tag::version() const
|
|
|
|
{
|
|
|
|
return m_version;
|
|
|
|
}
|
|
|
|
|
2021-03-20 21:26:25 +01:00
|
|
|
inline std::uint64_t Tag::size() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool Tag::supportsTarget() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const TagTarget &Tag::target() const
|
|
|
|
{
|
|
|
|
return m_target;
|
|
|
|
}
|
|
|
|
|
2022-05-03 23:48:24 +02:00
|
|
|
inline TagTarget &Tag::target()
|
|
|
|
{
|
|
|
|
return m_target;
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
inline void Tag::setTarget(const TagTarget &target)
|
|
|
|
{
|
|
|
|
m_target = target;
|
|
|
|
}
|
|
|
|
|
2016-05-26 01:59:22 +02:00
|
|
|
inline TagTargetLevel Tag::targetLevel() const
|
|
|
|
{
|
|
|
|
return TagTargetLevel::Unspecified;
|
|
|
|
}
|
|
|
|
|
2021-01-30 21:53:06 +01:00
|
|
|
inline std::string_view Tag::targetLevelName() const
|
2016-05-26 01:59:22 +02:00
|
|
|
{
|
2021-01-30 21:53:06 +01:00
|
|
|
return supportsTarget() ? tagTargetLevelName(targetLevel()) : std::string_view();
|
2016-05-26 01:59:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool Tag::isTargetingLevel(TagTargetLevel tagTargetLevel) const
|
|
|
|
{
|
2019-03-13 19:06:42 +01:00
|
|
|
return !supportsTarget() || static_cast<std::uint8_t>(targetLevel()) >= static_cast<std::uint8_t>(tagTargetLevel);
|
2016-05-26 01:59:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
inline std::string Tag::targetString() const
|
|
|
|
{
|
|
|
|
return target().toString(targetLevel());
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
inline TagDataType Tag::proposedDataType(KnownField field) const
|
|
|
|
{
|
2018-03-07 01:17:50 +01:00
|
|
|
switch (field) {
|
2015-04-22 19:22:01 +02:00
|
|
|
case KnownField::Bpm:
|
|
|
|
case KnownField::Bps:
|
|
|
|
case KnownField::PartNumber:
|
|
|
|
case KnownField::TotalParts:
|
2022-06-19 17:40:01 +02:00
|
|
|
case KnownField::PlayCounter:
|
2015-04-22 19:22:01 +02:00
|
|
|
return TagDataType::Integer;
|
|
|
|
case KnownField::Cover:
|
|
|
|
return TagDataType::Picture;
|
|
|
|
case KnownField::Length:
|
|
|
|
return TagDataType::TimeSpan;
|
|
|
|
case KnownField::TrackPosition:
|
|
|
|
case KnownField::DiskPosition:
|
|
|
|
return TagDataType::PositionInSet;
|
|
|
|
case KnownField::Genre:
|
|
|
|
return TagDataType::StandardGenreIndex;
|
2022-04-05 23:30:37 +02:00
|
|
|
case KnownField::MCDI:
|
|
|
|
return TagDataType::Binary;
|
2022-06-19 14:31:12 +02:00
|
|
|
case KnownField::Rating:
|
|
|
|
// could also be a plain integer but popularity should generally be used (and can be converted
|
|
|
|
// to an integer)
|
|
|
|
return TagDataType::Popularity;
|
2019-02-13 19:06:35 +01:00
|
|
|
case KnownField::SynchronizedLyrics:
|
2022-06-19 14:31:12 +02:00
|
|
|
// not supported
|
|
|
|
return TagDataType::Undefined;
|
2015-04-22 19:22:01 +02:00
|
|
|
default:
|
|
|
|
return TagDataType::Text;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
inline bool Tag::supportsDescription(KnownField) const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
inline bool Tag::supportsMimeType(KnownField) const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-07-13 12:25:00 +02:00
|
|
|
inline bool Tag::supportsMultipleValues(KnownField) const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
} // namespace TagParser
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2018-03-06 23:09:15 +01:00
|
|
|
#endif // TAG_PARSER_TAG_H
|