diff --git a/matroska/matroskatag.cpp b/matroska/matroskatag.cpp index 2910d8f..9dc284a 100644 --- a/matroska/matroskatag.cpp +++ b/matroska/matroskatag.cpp @@ -217,14 +217,17 @@ MatroskaTagMaker::MatroskaTagMaker(MatroskaTag &tag) : // calculate size of "Targets" element m_targetsSize = 0; // NOT including ID and size if(m_tag.target().level() != 50) { - m_targetsSize += 2 + 1 + EbmlElement::calculateUIntegerLength(m_tag.target().level()); // size of "TargetTypeValue" + // size of "TargetTypeValue" + m_targetsSize += 2 + 1 + EbmlElement::calculateUIntegerLength(m_tag.target().level()); } if(!m_tag.target().levelName().empty()) { - m_targetsSize += 2 + EbmlElement::calculateSizeDenotationLength(m_tag.target().levelName().size()) + m_tag.target().levelName().size(); // size of "TargetType" + // size of "TargetType" + m_targetsSize += 2 + EbmlElement::calculateSizeDenotationLength(m_tag.target().levelName().size()) + m_tag.target().levelName().size(); } for(const auto &v : initializer_list >{m_tag.target().tracks(), m_tag.target().editions(), m_tag.target().chapters(), m_tag.target().attachments()}) { for(auto uid : v) { - m_targetsSize += 2 + 1 + EbmlElement::calculateUIntegerLength(uid); // size of UID denotation + // size of UID denotation + m_targetsSize += 2 + 1 + EbmlElement::calculateUIntegerLength(uid); } } m_tagSize = 2 + EbmlElement::calculateSizeDenotationLength(m_targetsSize) + m_targetsSize; diff --git a/mediafileinfo.cpp b/mediafileinfo.cpp index f2ea9a2..66753ff 100644 --- a/mediafileinfo.cpp +++ b/mediafileinfo.cpp @@ -439,6 +439,7 @@ void MediaFileInfo::parseEverything() * \param mergeMultipleSuccessiveId3v2Tags Specifies whether multiple successive ID3v2 tags should be merged (see mergeId3v2Tags()). * \param keepExistingId3v2version Specifies whether the version of existing ID3v2 tags should be updated. * \param id3v2version Specifies the IDv2 version to be used. Valid values are 2, 3 and 4. + * \param requiredTargets Specifies the required targets. Targets are ignored if not supported by the container. * \return Returns an indication whether appropriate tags could be created for the file. * \remarks * - The ID3 related arguments are only practiced when the file format is MP3 or when the file format @@ -452,12 +453,38 @@ void MediaFileInfo::parseEverything() * - Some tag information might be discarded. For example when an ID3v2 tag needs to be removed (\a id3v2usage is set to TagUsage::Never) * and an ID3v1 tag will be created instead not all fields can be transfered. */ -bool MediaFileInfo::createAppropriateTags(bool treatUnknownFilesAsMp3Files, TagUsage id3v1usage, TagUsage id3v2usage, bool mergeMultipleSuccessiveId3v2Tags, bool keepExistingId3v2version, uint32 id3v2version) +bool MediaFileInfo::createAppropriateTags(bool treatUnknownFilesAsMp3Files, TagUsage id3v1usage, TagUsage id3v2usage, bool mergeMultipleSuccessiveId3v2Tags, bool keepExistingId3v2version, uint32 id3v2version, const std::vector &requiredTargets) { // check if tags need to be created/adjusted/removed - if(m_container) { // container object takes care of tag management - m_container->createTag(); - } else { // no container object present; creation of ID3 tag is possible + bool targetsRequired = !requiredTargets.empty() && (requiredTargets.size() != 1 && requiredTargets.front().isEmpty()); + bool targetsSupported = false; + if(m_container) { + // container object takes care of tag management + if(targetsRequired) { + // check whether container supports targets + if(m_container->tagCount()) { + // all tags in the container should support targets if the first one supports targets + targetsSupported = m_container->tag(0)->supportsTarget(); + } else { + // try to create a new tag and check whether targets are supported + auto *tag = m_container->createTag(); + if(tag) { + if((targetsSupported = tag->supportsTarget())) { + tag->setTarget(requiredTargets.front()); + } + } + } + if(targetsSupported) { + for(const auto &target : requiredTargets) { + m_container->createTag(target); + } + } + } else { + // no targets are required -> just ensure that at least one tag is present + m_container->createTag(); + } + } else { + // no container object present; creation of ID3 tag is possible if(!hasAnyTag() && !treatUnknownFilesAsMp3Files) { switch(containerFormat()) { case ContainerFormat::MpegAudioFrames: @@ -494,18 +521,21 @@ bool MediaFileInfo::createAppropriateTags(bool treatUnknownFilesAsMp3Files, TagU if(id3v2usage == TagUsage::Never) { if(hasId3v1Tag()) { // transfer tags to ID3v1 tag before removing - for(const unique_ptr &tag : id3v2Tags()) { + for(const auto &tag : id3v2Tags()) { id3v1Tag()->insertValues(*tag, false); } } removeAllId3v2Tags(); } else if(!keepExistingId3v2version) { // set version of ID3v2 tag according user preferences - for(const unique_ptr &tag : id3v2Tags()) { + for(const auto &tag : id3v2Tags()) { tag->setVersion(id3v2version, 0); } } } + if(targetsRequired && !targetsSupported) { + addNotification(NotificationType::Warning, "The container/tags do not support targets. The specified targets are ignored.", "creating tags"); + } return true; } diff --git a/mediafileinfo.h b/mediafileinfo.h index 3ca3afa..3d87cb8 100644 --- a/mediafileinfo.h +++ b/mediafileinfo.h @@ -115,7 +115,7 @@ public: // methods to create/remove tags bool createAppropriateTags(bool treatUnknownFilesAsMp3Files = false, TagUsage id3v1usage = TagUsage::KeepExisting, TagUsage id3v2usage = TagUsage::Always, bool mergeMultipleSucessiveId3v2Tags = true, - bool keepExistingId3v2version = true, uint32 id3v2version = 3); + bool keepExistingId3v2version = true, uint32 id3v2version = 3, const std::vector &requiredTargets = std::vector()); bool removeId3v1Tag(); Id3v1Tag *createId3v1Tag(); bool removeId3v2Tag(Id3v2Tag *tag); diff --git a/tagtarget.h b/tagtarget.h index 9b223e5..b6b0e59 100644 --- a/tagtarget.h +++ b/tagtarget.h @@ -63,7 +63,7 @@ inline TagTarget::TagTarget(uint64 level, IdContainerType tracks, IdContainerTyp */ inline uint64 TagTarget::level() const { - return m_level; + return m_level ? m_level : 50; } /*! @@ -185,8 +185,8 @@ inline void TagTarget::clear() */ inline bool TagTarget::operator ==(const TagTarget &other) const { - return m_level == other.m_level - && m_levelName == other.m_levelName + return level() == other.level() + //&& m_levelName == other.m_levelName // consider targets with the same level number but different level names equal? && m_tracks == other.m_tracks && m_chapters == other.m_chapters && m_editions == other.m_editions