diff --git a/id3/id3v2frame.cpp b/id3/id3v2frame.cpp index d9ad01d..614ebaa 100644 --- a/id3/id3v2frame.cpp +++ b/id3/id3v2frame.cpp @@ -380,6 +380,10 @@ void Id3v2Frame::parse(BinaryReader &reader, std::uint32_t version, std::uint32_ // parse comment frame or unsynchronized lyrics frame (these two frame types have the same structure) parseComment(buffer.get(), m_dataSize, value(), diag); + } else if (((version >= 3 && id() == Id3v2FrameIds::lPlayCounter) || (version < 3 && id() == Id3v2FrameIds::sPlayCounter))) { + // parse play counter frame + value().assignUnsignedInteger(readPlayCounter(buffer.get(), buffer.get() + m_dataSize, context, diag)); + } else if (((version >= 3 && id() == Id3v2FrameIds::lRating) || (version < 3 && id() == Id3v2FrameIds::sRating))) { // parse popularimeter frame auto popularity = Popularity(); @@ -697,6 +701,19 @@ Id3v2FrameMaker::Id3v2FrameMaker(Id3v2Frame &frame, std::uint8_t version, Diagno // make comment frame or the unsynchronized lyrics frame m_frame.makeComment(m_data, m_decompressedSize, *values.front(), version, diag); + } else if (((version >= 3 && m_frameId == Id3v2FrameIds::lPlayCounter) || (version < 3 && m_frameId == Id3v2FrameIds::sPlayCounter))) { + // make play counter frame + auto playCounter = std::uint64_t(); + try { + playCounter = values.front()->toUnsignedInteger(); + } catch (const ConversionException &) { + diag.emplace_back(DiagLevel::Warning, + argsToString("The play counter \"", values.front()->toDisplayString(), "\" is not an unsigned integer."), context); + } + m_decompressedSize = computePlayCounterSize(playCounter); + m_data = make_unique(m_decompressedSize); + writePlayCounter(m_data.get() + m_decompressedSize - 1, m_decompressedSize, playCounter); + } else if (((version >= 3 && m_frameId == Id3v2FrameIds::lRating) || (version < 3 && m_frameId == Id3v2FrameIds::sRating))) { // make popularimeter frame auto popularity = Popularity(); diff --git a/id3/id3v2frameids.cpp b/id3/id3v2frameids.cpp index 463b9bd..13ade9a 100644 --- a/id3/id3v2frameids.cpp +++ b/id3/id3v2frameids.cpp @@ -79,6 +79,8 @@ std::uint32_t convertToShortId(std::uint32_t id) return sRemixedBy; case lCopyright: return sCopyright; + case lPlayCounter: + return sPlayCounter; case lRating: return sRating; case lISRC: @@ -147,6 +149,8 @@ std::uint32_t convertToLongId(std::uint32_t id) return lRemixedBy; case sCopyright: return lCopyright; + case sPlayCounter: + return lPlayCounter; case sRating: return lRating; case sISRC: diff --git a/id3/id3v2frameids.h b/id3/id3v2frameids.h index f3fc723..979f38d 100644 --- a/id3/id3v2frameids.h +++ b/id3/id3v2frameids.h @@ -41,6 +41,7 @@ enum KnownValue : std::uint32_t { lRecordLabel = 0x54505542, /**< TPUB \todo rename to lPublisher in v12 */ lUniqueFileId = 0x55464944, /**< UFID */ lComposer = 0x54434f4d, /**< TCOM */ + lPlayCounter = 0x50434E54, /**< PCNT */ lRating = 0x504f504d, /**< POPM */ lRemixedBy = 0x54504534, /**< TPE4 */ lCopyright = 0x54434F50, /**< TCOP */ @@ -75,6 +76,7 @@ enum KnownValue : std::uint32_t { sRecordLabel = 0x545042, /**< ?TPB \todo rename to sPublisher in v12 */ sUniqueFileId = 0x554649, /**< ?UFI */ sComposer = 0x54434d, /**< ?TCM */ + sPlayCounter = 0x434E54, /**< CNT */ sRating = 0x504f50, /**< ?POP */ sRemixedBy = 0x545034, /**< TP4 */ sCopyright = 0x544352, /**< TCR */ diff --git a/id3/id3v2tag.cpp b/id3/id3v2tag.cpp index b47ed06..243d110 100644 --- a/id3/id3v2tag.cpp +++ b/id3/id3v2tag.cpp @@ -176,6 +176,8 @@ Id3v2Tag::IdentifierType Id3v2Tag::internallyGetFieldId(KnownField field) const return lRecordLabel; case KnownField::Composer: return lComposer; + case KnownField::PlayCounter: + return lPlayCounter; case KnownField::Rating: return lRating; case KnownField::AlbumArtist: @@ -236,6 +238,8 @@ Id3v2Tag::IdentifierType Id3v2Tag::internallyGetFieldId(KnownField field) const return sRecordLabel; case KnownField::Composer: return sComposer; + case KnownField::PlayCounter: + return sPlayCounter; case KnownField::Rating: return sRating; case KnownField::AlbumArtist: @@ -307,6 +311,8 @@ KnownField Id3v2Tag::internallyGetKnownField(const IdentifierType &id) const return KnownField::OriginalReleaseDate; case lMood: return KnownField::Mood; + case lPlayCounter: + return KnownField::PlayCounter; case lRating: return KnownField::Rating; case lISRC: @@ -351,6 +357,8 @@ KnownField Id3v2Tag::internallyGetKnownField(const IdentifierType &id) const return KnownField::RemixedBy; case sCopyright: return KnownField::Copyright; + case sPlayCounter: + return KnownField::PlayCounter; case sRating: return KnownField::Rating; case sISRC: @@ -371,6 +379,8 @@ TagDataType Id3v2Tag::internallyGetProposedDataType(const std::uint32_t &id) con case sBpm: case lYear: case sYear: + case lPlayCounter: + case sPlayCounter: return TagDataType::Integer; case lTrackPosition: case sTrackPosition: diff --git a/tag.h b/tag.h index fb9d0eb..a9c4e6a 100644 --- a/tag.h +++ b/tag.h @@ -293,6 +293,7 @@ inline TagDataType Tag::proposedDataType(KnownField field) const case KnownField::Bps: case KnownField::PartNumber: case KnownField::TotalParts: + case KnownField::PlayCounter: return TagDataType::Integer; case KnownField::Cover: return TagDataType::Picture;