1 /* Cover.cpp */
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 #include "Cover.h"
22 
23 #include "Utils/Logger/Logger.h"
24 
25 #include <taglib/flacpicture.h>
26 #include <taglib/flacfile.h>
27 #include <taglib/oggfile.h>
28 #include <taglib/tmap.h>
29 
30 namespace TL = TagLib;
31 
32 namespace
33 {
getBestFittingPicture(const TL::List<TL::FLAC::Picture * > & pictures)34 	TL::FLAC::Picture* getBestFittingPicture(const TL::List<TL::FLAC::Picture*>& pictures)
35 	{
36 		if(pictures.isEmpty())
37 		{
38 			return nullptr;
39 		}
40 
41 		TL::FLAC::Picture* candidate = nullptr;
42 		for(auto* picture : pictures)
43 		{
44 			if(picture->type() == TL::FLAC::Picture::FrontCover)
45 			{
46 				if(picture->data().size() < 100)
47 				{
48 					continue;
49 				}
50 
51 				candidate = picture;
52 			}
53 
54 			else if((picture->type() == TL::FLAC::Picture::Other) && !candidate)
55 			{
56 				if(picture->data().size() < 100)
57 				{
58 					continue;
59 				}
60 
61 				candidate = picture;
62 			}
63 		}
64 
65 		return (!candidate)
66 		       ? pictures[0]
67 		       : candidate;
68 	}
69 }
70 
CoverFrame(TagLib::Ogg::XiphComment * tag)71 Xiph::CoverFrame::CoverFrame(TagLib::Ogg::XiphComment* tag) :
72 	Xiph::XiphFrame<Models::Cover>(tag, "") {}
73 
74 Xiph::CoverFrame::~CoverFrame() = default;
75 
mapTagToData() const76 std::optional<Models::Cover> Xiph::CoverFrame::mapTagToData() const
77 {
78 	const auto pictures = tag()->pictureList();
79 	if(pictures.isEmpty())
80 	{
81 		const auto cover = Models::Cover(QString(), QByteArray());
82 		return std::optional(cover);
83 	}
84 
85 	auto* picture = getBestFittingPicture(pictures);
86 	if(picture)
87 	{
88 		const auto data = picture->data();
89 		const auto cover = Models::Cover(
90 			Tagging::convertString(picture->mimeType()),
91 			QByteArray(data.data(), static_cast<int>(data.size()))
92 		);
93 
94 		return std::optional(cover);
95 	}
96 
97 	return std::optional<Models::Cover>();
98 }
99 
mapDataToTag(const Models::Cover & cover)100 void Xiph::CoverFrame::mapDataToTag(const Models::Cover& cover)
101 {
102 	this->tag()->removeAllPictures();
103 
104 	const auto dataSize = static_cast<unsigned int>(cover.imageData.size());
105 	const auto imageData = TL::ByteVector(cover.imageData.data(), dataSize);
106 
107 	auto* picture = new TL::FLAC::Picture();
108 
109 	picture->setType(TL::FLAC::Picture::FrontCover);
110 	picture->setMimeType(Tagging::convertString(cover.mimeType));
111 	picture->setDescription(TL::String("Front Cover By Sayonara"));
112 	picture->setData(TL::ByteVector(cover.imageData.data(), dataSize));
113 
114 	tag()->addPicture(picture); // do not delete the picture, because tag will take ownership
115 }
116 
isFrameAvailable() const117 bool Xiph::CoverFrame::isFrameAvailable() const
118 {
119 	const auto hasEntries = (this->tag()->pictureList().isEmpty() == false);
120 	spLog(Log::Develop, this) << "Picture list has " << this->tag()->pictureList().size() << " entries";
121 
122 	return hasEntries;
123 }
124