1 /* MP4Frame.h */
2 
3 /* Copyright (C) 2011-2020 Michael Lugmair (Lucio Carreras)
4  *
5  * This file is part of sayonara player
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11 
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16 
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #ifndef SAYONARA_ABSTRACT_MP4_FRAME_H
22 #define SAYONARA_ABSTRACT_MP4_FRAME_H
23 
24 #include "Utils/Tagging/AbstractFrame.h"
25 #include "Utils/Algorithm.h"
26 
27 #include <QString>
28 
29 #include <taglib/tag.h>
30 #include <taglib/tstringlist.h>
31 #include <taglib/mp4tag.h>
32 #include <taglib/tpropertymap.h>
33 
34 #include <algorithm>
35 #include <optional>
36 
37 namespace MP4
38 {
39 	template<typename Model_t>
40 	class MP4Frame :
41 		protected Tagging::AbstractFrame<TagLib::MP4::Tag>
42 	{
43 		protected:
findKey(const TagLib::MP4::ItemMap & itemMap)44 			TagLib::MP4::ItemMap::ConstIterator findKey(const TagLib::MP4::ItemMap& itemMap) const
45 			{
46 				return std::find_if(itemMap.begin(), itemMap.end(), [&](const auto& itemList) {
47 					const auto convertedString = Tagging::convertString(itemList.first);
48 					return (convertedString.compare(key(), Qt::CaseInsensitive) == 0);
49 				});
50 			}
51 
eraseAllFromTag(TagLib::MP4::Tag * tag,const QString & key)52 			void eraseAllFromTag(TagLib::MP4::Tag* tag, const QString& key)
53 			{
54 				const auto taglibKey = Tagging::convertString(key);
55 				while(tag->contains(taglibKey))
56 				{
57 					tag->removeItem(taglibKey);
58 				}
59 			}
60 
61 			virtual std::optional<Model_t> mapItemToData(const TagLib::MP4::Item& item) const = 0;
62 			virtual std::optional<TagLib::MP4::Item> mapDataToItem(const Model_t& model) = 0;
63 
64 		public:
MP4Frame(TagLib::MP4::Tag * tag,const QString & identifier)65 			MP4Frame(TagLib::MP4::Tag* tag, const QString& identifier) :
66 				Tagging::AbstractFrame<TagLib::MP4::Tag>(tag, identifier) {}
67 
68 			virtual ~MP4Frame() = default;
69 
read(Model_t & data)70 			bool read(Model_t& data) const
71 			{
72 				if(!tag())
73 				{
74 					return false;
75 				}
76 
77 				const auto& itemMap = tag()->itemMap();
78 				const auto it = findKey(itemMap);
79 				if(it != itemMap.end() && it->second.isValid())
80 				{
81 					const auto optionalData = mapItemToData(it->second);
82 					if(optionalData.has_value())
83 					{
84 						data = optionalData.value();
85 						return true;
86 					}
87 				}
88 
89 				return false;
90 			}
91 
write(const Model_t & data)92 			bool write(const Model_t& data)
93 			{
94 				if(!tag())
95 				{
96 					return false;
97 				}
98 
99 				eraseAllFromTag(tag(), key());
100 
101 				const auto item = mapDataToItem(data);
102 				if(item.has_value() && item.value().isValid())
103 				{
104 					tag()->setItem(tagKey(), *item);
105 				}
106 
107 				return item.has_value();
108 			}
109 
isFrameAvailable()110 			bool isFrameAvailable() const
111 			{
112 				if(!tag())
113 				{
114 					return false;
115 				}
116 
117 				const auto& itemMap = tag()->itemMap();
118 				return (findKey(itemMap) != itemMap.end());
119 			}
120 	};
121 }
122 
123 #endif // SAYONARA_ABSTRACT_MP4_FRAME_H
124