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