mirror of
https://github.com/taglib/taglib.git
synced 2026-02-08 00:10:15 -05:00
Make tags and properties more flexible
This commit is contained in:
@ -69,6 +69,7 @@ namespace TagLib::EBML {
|
||||
inline constexpr Element::Id MkSimpleTag = 0x67C8;
|
||||
inline constexpr Element::Id MkTagName = 0x45A3;
|
||||
inline constexpr Element::Id MkTagLanguage = 0x447A;
|
||||
inline constexpr Element::Id MkTagBinary = 0x4485;
|
||||
inline constexpr Element::Id MkTagString = 0x4487;
|
||||
inline constexpr Element::Id MkTagsTagLanguage = 0x447A;
|
||||
inline constexpr Element::Id MkTagsLanguageDefault = 0x4484;
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "ebmlmktags.h"
|
||||
#include "ebmlbinaryelement.h"
|
||||
#include "ebmluintelement.h"
|
||||
#include "ebmlstringelement.h"
|
||||
#include "matroskatag.h"
|
||||
@ -79,7 +80,8 @@ Matroska::Tag *EBML::MkTags::parse()
|
||||
tagName = &(static_cast<UTF8StringElement *>(simpleTagChild)->getValue());
|
||||
else if(id == ElementIDs::MkTagString && !tagValueString)
|
||||
tagValueString = &(static_cast<UTF8StringElement *>(simpleTagChild)->getValue());
|
||||
// TODO implement binary
|
||||
else if(id == ElementIDs::MkTagBinary && !tagValueBinary)
|
||||
tagValueBinary = &(static_cast<BinaryElement *>(simpleTagChild)->getValue());
|
||||
else if(id == ElementIDs::MkTagsTagLanguage && !language)
|
||||
language = &(static_cast<Latin1StringElement *>(simpleTagChild)->getValue());
|
||||
else if(id == ElementIDs::MkTagsLanguageDefault)
|
||||
@ -96,7 +98,7 @@ Matroska::Tag *EBML::MkTags::parse()
|
||||
sTagString->setValue(*tagValueString);
|
||||
sTag = sTagString;
|
||||
}
|
||||
else if(tagValueBinary) {
|
||||
else { // tagValueBinary must be non null
|
||||
auto sTagBinary = new Matroska::SimpleTagBinary();
|
||||
sTagBinary->setTargetTypeValue(targetTypeValue);
|
||||
sTagBinary->setValue(*tagValueBinary);
|
||||
|
||||
@ -48,12 +48,15 @@ namespace TagLib {
|
||||
void removeAttachedFile(AttachedFile *file);
|
||||
void clear();
|
||||
const AttachedFileList &attachedFileList() const;
|
||||
bool render() override;
|
||||
|
||||
private:
|
||||
friend class EBML::MkAttachments;
|
||||
friend class File;
|
||||
class AttachmentsPrivate;
|
||||
|
||||
// private Element implementation
|
||||
bool render() override;
|
||||
|
||||
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
|
||||
std::unique_ptr<AttachmentsPrivate> d;
|
||||
};
|
||||
|
||||
@ -154,5 +154,6 @@ bool Matroska::CueTrack::isValid(TagLib::File &file, offset_t segmentDataOffset)
|
||||
|
||||
bool Matroska::CueTrack::adjustOffset(offset_t, offset_t)
|
||||
{
|
||||
// TODO implement
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "ebmlmksegment.h"
|
||||
#include "tlist.h"
|
||||
#include "tdebug.h"
|
||||
#include "tagutils.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@ -57,10 +58,10 @@ public:
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Matroska::File::isSupported(IOStream *)
|
||||
bool Matroska::File::isSupported(IOStream *stream)
|
||||
{
|
||||
// TODO implement
|
||||
return false;
|
||||
const ByteVector id = Utils::readHeader(stream, 4, false);
|
||||
return id.startsWith("\x1A\x45\xDF\xA3");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -46,6 +46,5 @@ namespace TagLib::Matroska {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "matroskasimpletag.h"
|
||||
#include "ebmlmasterelement.h"
|
||||
#include "ebmlstringelement.h"
|
||||
#include "ebmlbinaryelement.h"
|
||||
#include "ebmlmktags.h"
|
||||
#include "ebmluintelement.h"
|
||||
#include "ebmlutils.h"
|
||||
@ -33,16 +34,62 @@
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace TagLib::Matroska::Utils {
|
||||
std::pair<String, SimpleTag::TargetTypeValue> translateKey(const String &key);
|
||||
String translateTag(const String &name, SimpleTag::TargetTypeValue targetTypeValue);
|
||||
}
|
||||
|
||||
class Matroska::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate() = default;
|
||||
~TagPrivate() = default;
|
||||
|
||||
bool setTag(const String &key, const String &value);
|
||||
const String *getTag(const String &key) const;
|
||||
|
||||
template <typename T>
|
||||
int removeSimpleTags(T &&p)
|
||||
{
|
||||
auto &list = tags;
|
||||
int numRemoved = 0;
|
||||
for(auto it = list.begin(); it != list.end();) {
|
||||
it = std::find_if(it, list.end(), std::forward<T>(p));
|
||||
if(it != list.end()) {
|
||||
delete *it;
|
||||
*it = nullptr;
|
||||
it = list.erase(it);
|
||||
numRemoved++;
|
||||
}
|
||||
}
|
||||
return numRemoved;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SimpleTagsList findSimpleTags(T &&p)
|
||||
{
|
||||
auto &list = tags;
|
||||
for(auto it = list.begin(); it != list.end();) {
|
||||
it = std::find_if(it, list.end(), std::forward<T>(p));
|
||||
if(it != list.end()) {
|
||||
list.append(*it);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const SimpleTag *findSimpleTag(T &&p) const
|
||||
{
|
||||
auto &list = tags;
|
||||
auto it = std::find_if(list.begin(), list.end(), std::forward<T>(p));
|
||||
return it != list.end() ? *it : nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SimpleTag *findSimpleTag(T &&p)
|
||||
{
|
||||
return const_cast<SimpleTag *>(
|
||||
const_cast<const TagPrivate *>(this)->findSimpleTag(std::forward<T>(p))
|
||||
);
|
||||
}
|
||||
|
||||
List<SimpleTag *> tags;
|
||||
ByteVector data;
|
||||
};
|
||||
@ -79,84 +126,74 @@ const Matroska::SimpleTagsList &Matroska::Tag::simpleTagsList() const
|
||||
return d->tags;
|
||||
}
|
||||
|
||||
Matroska::SimpleTagsList &Matroska::Tag::simpleTagsListPrivate()
|
||||
{
|
||||
return d->tags;
|
||||
}
|
||||
|
||||
const Matroska::SimpleTagsList &Matroska::Tag::simpleTagsListPrivate() const
|
||||
{
|
||||
return d->tags;
|
||||
}
|
||||
|
||||
void Matroska::Tag::setTitle(const String &s)
|
||||
{
|
||||
setTag("TITLE", s);
|
||||
d->setTag("TITLE", s);
|
||||
}
|
||||
|
||||
void Matroska::Tag::setArtist(const String &s)
|
||||
{
|
||||
setTag("ARTIST", s);
|
||||
d->setTag("ARTIST", s);
|
||||
}
|
||||
|
||||
void Matroska::Tag::setAlbum(const String &s)
|
||||
{
|
||||
setTag("ALBUM", s);
|
||||
d->setTag("ALBUM", s);
|
||||
}
|
||||
|
||||
void Matroska::Tag::setComment(const String &s)
|
||||
{
|
||||
setTag("COMMENT", s);
|
||||
d->setTag("COMMENT", s);
|
||||
}
|
||||
|
||||
void Matroska::Tag::setGenre(const String &s)
|
||||
{
|
||||
setTag("GENRE", s);
|
||||
d->setTag("GENRE", s);
|
||||
}
|
||||
|
||||
void Matroska::Tag::setYear(unsigned int i)
|
||||
{
|
||||
setTag("DATE", String::number(i));
|
||||
d->setTag("DATE", String::number(i));
|
||||
}
|
||||
|
||||
void Matroska::Tag::setTrack(unsigned int i)
|
||||
{
|
||||
setTag("TRACKNUMBER", String::number(i));
|
||||
d->setTag("TRACKNUMBER", String::number(i));
|
||||
}
|
||||
|
||||
String Matroska::Tag::title() const
|
||||
{
|
||||
const auto value = getTag("TITLE");
|
||||
const auto value = d->getTag("TITLE");
|
||||
return value ? *value : String();
|
||||
}
|
||||
|
||||
String Matroska::Tag::artist() const
|
||||
{
|
||||
const auto value = getTag("ARTIST");
|
||||
const auto value = d->getTag("ARTIST");
|
||||
return value ? *value : String();
|
||||
}
|
||||
|
||||
String Matroska::Tag::album() const
|
||||
{
|
||||
const auto value = getTag("ALBUM");
|
||||
const auto value = d->getTag("ALBUM");
|
||||
return value ? *value : String();
|
||||
}
|
||||
|
||||
String Matroska::Tag::comment() const
|
||||
{
|
||||
const auto value = getTag("COMMENT");
|
||||
const auto value = d->getTag("COMMENT");
|
||||
return value ? *value : String();
|
||||
}
|
||||
|
||||
String Matroska::Tag::genre() const
|
||||
{
|
||||
const auto value = getTag("GENRE");
|
||||
const auto value = d->getTag("GENRE");
|
||||
return value ? *value : String();
|
||||
}
|
||||
|
||||
unsigned int Matroska::Tag::year() const
|
||||
{
|
||||
auto value = getTag("DATE");
|
||||
auto value = d->getTag("DATE");
|
||||
if(!value)
|
||||
return 0;
|
||||
auto list = value->split("-");
|
||||
@ -165,7 +202,7 @@ unsigned int Matroska::Tag::year() const
|
||||
|
||||
unsigned int Matroska::Tag::track() const
|
||||
{
|
||||
auto value = getTag("TRACKNUMBER");
|
||||
auto value = d->getTag("TRACKNUMBER");
|
||||
if(!value)
|
||||
return 0;
|
||||
auto list = value->split("-");
|
||||
@ -230,8 +267,10 @@ bool Matroska::Tag::render()
|
||||
tagValue->setValue(tStr->value());
|
||||
t->appendElement(tagValue);
|
||||
}
|
||||
else if((tBin = dynamic_cast<Matroska::SimpleTagBinary *>(simpleTag))) {
|
||||
// Todo
|
||||
else if((tBin = dynamic_cast<SimpleTagBinary *>(simpleTag))) {
|
||||
auto tagValue = new EBML::BinaryElement(EBML::ElementIDs::MkTagBinary);
|
||||
tagValue->setValue(tBin->value());
|
||||
t->appendElement(tagValue);
|
||||
}
|
||||
|
||||
// Language
|
||||
@ -264,42 +303,72 @@ bool Matroska::Tag::render()
|
||||
namespace
|
||||
{
|
||||
// PropertyMap key, Tag name, Target type value
|
||||
// If the key is the same as the name and the target type value is Track,
|
||||
// no translation is needed because this is the default mapping.
|
||||
// Therefore, keys like TITLE, ARTIST, GENRE, COMMENT, etc. are omitted.
|
||||
// For offical tags, see https://www.matroska.org/technical/tagging.html
|
||||
constexpr std::array simpleTagsTranslation {
|
||||
std::tuple("TITLE", "TITLE", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("ALBUM", "TITLE", Matroska::SimpleTag::TargetTypeValue::Album),
|
||||
std::tuple("ARTIST", "ARTIST", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("ALBUMARTIST", "ARTIST", Matroska::SimpleTag::TargetTypeValue::Album),
|
||||
std::tuple("SUBTITLE", "SUBTITLE", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("TRACKNUMBER", "PART_NUMBER", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("TRACKTOTAL", "TOTAL_PARTS", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("DISCNUMBER", "PART_NUMBER", Matroska::SimpleTag::TargetTypeValue::Part),
|
||||
std::tuple("DISCTOTAL", "TOTAL_PARTS", Matroska::SimpleTag::TargetTypeValue::Part),
|
||||
std::tuple("DATE", "DATE_RELEASED", Matroska::SimpleTag::TargetTypeValue::Album),
|
||||
// Todo - original date
|
||||
std::tuple("GENRE", "GENRE", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("COMMENT", "COMMENT", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("TITLESORT", "TITLESORT", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("ALBUMSORT", "TITLESORT", Matroska::SimpleTag::TargetTypeValue::Album),
|
||||
std::tuple("ARTISTSORT", "ARTISTSORT", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("ARTISTSORT", "ARTISTSORT", Matroska::SimpleTag::TargetTypeValue::Album),
|
||||
std::tuple("COMPOSERSORT", "COMPOSERSORT", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("COMPOSER", "COMPOSER", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("LYRICIST", "LYRICIST", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("CONDUCTOR", "CONDUCTOR", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("REMIXER", "REMIXER", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("BPM", "BPM", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("COPYRIGHT", "COPYRIGHT", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("ALBUMARTISTSORT", "ARTISTSORT", Matroska::SimpleTag::TargetTypeValue::Album),
|
||||
std::tuple("ENCODEDBY", "ENCODED_BY", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("MOOD", "MOOD", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("MEDIA", "ORIGINAL_MEDIA_TYPE", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("LABEL", "LABEL_CODE", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("CATALOGNUMBER", "CATALOG_NUMBER", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("BARCODE", "BARCODE", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
// Todo MusicBrainz tags
|
||||
std::tuple("DJMIXER", "MIXED_BY", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("REMIXER", "REMIXED_BY", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("INITIALKEY", "INITIAL_KEY", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("RELEASEDATE", "DATE_RELEASED", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("ENCODINGTIME", "DATE_ENCODED", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("TAGGINGDATE", "DATE_TAGGED", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("ENCODEDBY", "ENCODER", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("ENCODING", "ENCODER_SETTINGS", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("OWNER", "PURCHASE_OWNER", Matroska::SimpleTag::TargetTypeValue::Track),
|
||||
std::tuple("MUSICBRAINZ_ALBUMARTISTID", "MUSICBRAINZ_ALBUMARTISTID", Matroska::SimpleTag::TargetTypeValue::Album),
|
||||
std::tuple("MUSICBRAINZ_ALBUMID", "MUSICBRAINZ_ALBUMID", Matroska::SimpleTag::TargetTypeValue::Album),
|
||||
std::tuple("MUSICBRAINZ_RELEASEGROUPID", "MUSICBRAINZ_RELEASEGROUPID", Matroska::SimpleTag::TargetTypeValue::Album),
|
||||
};
|
||||
|
||||
std::pair<String, Matroska::SimpleTag::TargetTypeValue> translateKey(const String &key)
|
||||
{
|
||||
auto it = std::find_if(simpleTagsTranslation.cbegin(),
|
||||
simpleTagsTranslation.cend(),
|
||||
[&key](const auto &t) { return key == std::get<0>(t); }
|
||||
);
|
||||
if(it != simpleTagsTranslation.end())
|
||||
return { std::get<1>(*it), std::get<2>(*it) };
|
||||
if (!key.isEmpty() && !key.startsWith("_"))
|
||||
return { key, Matroska::SimpleTag::TargetTypeValue::Track };
|
||||
return { String(), Matroska::SimpleTag::TargetTypeValue::None };
|
||||
}
|
||||
|
||||
String translateTag(const String &name, Matroska::SimpleTag::TargetTypeValue targetTypeValue)
|
||||
{
|
||||
auto it = std::find_if(simpleTagsTranslation.cbegin(),
|
||||
simpleTagsTranslation.cend(),
|
||||
[&name, targetTypeValue](const auto &t) {
|
||||
return name == std::get<1>(t)
|
||||
&& targetTypeValue == std::get<2>(t);
|
||||
}
|
||||
);
|
||||
return it != simpleTagsTranslation.end()
|
||||
? String(std::get<0>(*it), String::UTF8)
|
||||
: targetTypeValue == Matroska::SimpleTag::TargetTypeValue::Track && !name.startsWith("_")
|
||||
? name
|
||||
: String();
|
||||
}
|
||||
}
|
||||
|
||||
bool Matroska::Tag::setTag(const String &key, const String &value)
|
||||
bool Matroska::Tag::TagPrivate::setTag(const String &key, const String &value)
|
||||
{
|
||||
const auto pair = Utils::translateKey(key);
|
||||
const auto pair = translateKey(key);
|
||||
// Workaround Clang issue - no lambda capture of structured bindings
|
||||
const String &name = pair.first;
|
||||
auto targetTypeValue = pair.second;
|
||||
@ -316,14 +385,14 @@ bool Matroska::Tag::setTag(const String &key, const String &value)
|
||||
t->setTargetTypeValue(targetTypeValue);
|
||||
t->setName(name);
|
||||
t->setValue(value);
|
||||
addSimpleTag(t);
|
||||
tags.append(t);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const String *Matroska::Tag::getTag(const String &key) const
|
||||
const String *Matroska::Tag::TagPrivate::getTag(const String &key) const
|
||||
{
|
||||
const auto pair = Utils::translateKey(key);
|
||||
const auto pair = translateKey(key);
|
||||
// Workaround Clang issue - no lambda capture of structured bindings
|
||||
const String &name = pair.first;
|
||||
auto targetTypeValue = pair.second;
|
||||
@ -340,36 +409,23 @@ const String *Matroska::Tag::getTag(const String &key) const
|
||||
return tag ? &tag->value() : nullptr;
|
||||
}
|
||||
|
||||
std::pair<String, Matroska::SimpleTag::TargetTypeValue> Matroska::Utils::translateKey(const String &key)
|
||||
{
|
||||
auto it = std::find_if(simpleTagsTranslation.cbegin(),
|
||||
simpleTagsTranslation.cend(),
|
||||
[&key](const auto &t) { return key == std::get<0>(t); }
|
||||
);
|
||||
if(it != simpleTagsTranslation.end())
|
||||
return { std::get<1>(*it), std::get<2>(*it) };
|
||||
else
|
||||
return { String(), SimpleTag::TargetTypeValue::None };
|
||||
}
|
||||
|
||||
String Matroska::Utils::translateTag(const String &name, SimpleTag::TargetTypeValue targetTypeValue)
|
||||
{
|
||||
auto it = std::find_if(simpleTagsTranslation.cbegin(),
|
||||
simpleTagsTranslation.cend(),
|
||||
[&name, targetTypeValue](const auto &t) {
|
||||
return name == std::get<1>(t)
|
||||
&& targetTypeValue == std::get<2>(t);
|
||||
}
|
||||
);
|
||||
return it != simpleTagsTranslation.end() ? std::get<0>(*it) : String();
|
||||
}
|
||||
|
||||
PropertyMap Matroska::Tag::setProperties(const PropertyMap &propertyMap)
|
||||
{
|
||||
PropertyMap unsupportedProperties;
|
||||
for(const auto &[key, value] : propertyMap) {
|
||||
if(!setTag(key, value.toString()))
|
||||
unsupportedProperties[key] = value;
|
||||
for(const auto &[key, values] : propertyMap) {
|
||||
for(const auto &value : values) {
|
||||
if(auto [name, targetTypeValue] = translateKey(key);
|
||||
!name.isEmpty()) {
|
||||
auto t = new SimpleTagString();
|
||||
t->setTargetTypeValue(targetTypeValue);
|
||||
t->setName(name);
|
||||
t->setValue(value);
|
||||
d->tags.append(t);
|
||||
}
|
||||
else {
|
||||
unsupportedProperties[key] = values;
|
||||
}
|
||||
}
|
||||
}
|
||||
return unsupportedProperties;
|
||||
}
|
||||
@ -378,11 +434,11 @@ PropertyMap Matroska::Tag::properties() const
|
||||
{
|
||||
PropertyMap properties;
|
||||
SimpleTagString *tStr = nullptr;
|
||||
for(auto simpleTag : d->tags) {
|
||||
for(auto simpleTag : std::as_const(d->tags)) {
|
||||
if((tStr = dynamic_cast<SimpleTagString *>(simpleTag))) {
|
||||
String key = Utils::translateTag(tStr->name(), tStr->targetTypeValue());
|
||||
if(!key.isEmpty() && !properties.contains(key))
|
||||
properties[key] = tStr->value();
|
||||
String key = translateTag(tStr->name(), tStr->targetTypeValue());
|
||||
if(!key.isEmpty())
|
||||
properties[key].append(tStr->value());
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
|
||||
@ -18,12 +18,10 @@
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef HAS_MATROSKATAG_H
|
||||
#define HAS_MATROSKATAG_H
|
||||
#ifndef TAGLIB_MATROSKATAG_H
|
||||
#define TAGLIB_MATROSKATAG_H
|
||||
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "tag.h"
|
||||
#include "tstring.h"
|
||||
@ -48,10 +46,6 @@ namespace TagLib {
|
||||
public:
|
||||
Tag();
|
||||
~Tag() override;
|
||||
void addSimpleTag(SimpleTag *tag);
|
||||
void removeSimpleTag(SimpleTag *tag);
|
||||
void clearSimpleTags();
|
||||
const SimpleTagsList &simpleTagsList() const;
|
||||
String title() const override;
|
||||
String artist() const override;
|
||||
String album() const override;
|
||||
@ -67,64 +61,22 @@ namespace TagLib {
|
||||
void setYear(unsigned int i) override;
|
||||
void setTrack(unsigned int i) override;
|
||||
bool isEmpty() const override;
|
||||
bool render() override;
|
||||
PropertyMap properties() const override;
|
||||
PropertyMap setProperties(const PropertyMap &propertyMap) override;
|
||||
template <typename T>
|
||||
int removeSimpleTags(T &&p)
|
||||
{
|
||||
auto &list = simpleTagsListPrivate();
|
||||
int numRemoved = 0;
|
||||
for(auto it = list.begin(); it != list.end();) {
|
||||
it = std::find_if(it, list.end(), std::forward<T>(p));
|
||||
if(it != list.end()) {
|
||||
delete *it;
|
||||
*it = nullptr;
|
||||
it = list.erase(it);
|
||||
numRemoved++;
|
||||
}
|
||||
}
|
||||
return numRemoved;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SimpleTagsList findSimpleTags(T &&p)
|
||||
{
|
||||
auto &list = simpleTagsListPrivate();
|
||||
for(auto it = list.begin(); it != list.end();) {
|
||||
it = std::find_if(it, list.end(), std::forward<T>(p));
|
||||
if(it != list.end()) {
|
||||
list.append(*it);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const SimpleTag *findSimpleTag(T &&p) const
|
||||
{
|
||||
auto &list = simpleTagsListPrivate();
|
||||
auto it = std::find_if(list.begin(), list.end(), std::forward<T>(p));
|
||||
return it != list.end() ? *it : nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SimpleTag *findSimpleTag(T &&p)
|
||||
{
|
||||
return const_cast<SimpleTag *>(
|
||||
const_cast<const Tag *>(this)->findSimpleTag(std::forward<T>(p))
|
||||
);
|
||||
}
|
||||
void addSimpleTag(SimpleTag *tag);
|
||||
void removeSimpleTag(SimpleTag *tag);
|
||||
void clearSimpleTags();
|
||||
const SimpleTagsList &simpleTagsList() const;
|
||||
|
||||
private:
|
||||
friend class File;
|
||||
friend class EBML::MkTags;
|
||||
SimpleTagsList &simpleTagsListPrivate();
|
||||
const SimpleTagsList &simpleTagsListPrivate() const;
|
||||
bool setTag(const String &key, const String &value);
|
||||
const String *getTag(const String &key) const;
|
||||
class TagPrivate;
|
||||
|
||||
// private Element implementation
|
||||
bool render() override;
|
||||
|
||||
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
|
||||
std::unique_ptr<TagPrivate> d;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user