1 #include "stdafx.h"
2 #include "TagLibHelper.h"
3 #include "taglib/mp4file.h"
4 #include "taglib/mp4coverart.h"
5 #include "taglib/flacfile.h"
6 #include "taglib/flacpicture.h"
7 #include "taglib/mpegfile.h"
8 #include "Common.h"
9 #include "FilePathHelper.h"
10 #include "taglib/attachedpictureframe.h"
11 #include "taglib/id3v2tag.h"
12 #include "taglib/id3v1tag.h"
13 #include "taglib/apefile.h"
14 #include "taglib/wavfile.h"
15 #include "taglib/mpcfile.h"
16 #include "taglib/opusfile.h"
17 #include "taglib/wavpackfile.h"
18 #include "taglib/vorbisfile.h"
19 #include "taglib/trueaudiofile.h"
20 #include "taglib/aifffile.h"
21 #include "taglib/asffile.h"
22 #include "taglib/tpropertymap.h"
23 #include "AudioCommon.h"
24 #include "taglib/apetag.h"
25 #include "taglib/fileref.h"
26 #include "taglib/speexfile.h"
27 #include "taglib/unsynchronizedlyricsframe.h"
28 #include "taglib/id3v2frame.h"
29 #include "taglib/popularimeterframe.h"
30
31
32 using namespace TagLib;
33
34 #define STR_MP4_COVER_TAG "covr"
35 #define STR_ASF_COVER_TAG "WM/Picture"
36 #define STR_APE_COVER_TAG "COVER ART (FRONT)"
37
38 #define STR_MP4_LYRICS_TAG "----:com.apple.iTunes:Lyrics"
39 #define STR_ID3V2_LYRIC_TAG "USLT"
40 #define STR_FLAC_LYRIC_TAG "LYRICS"
41 #define STR_ASF_LYRIC_TAG "LYRICS"
42
43 #define STR_APE_CUE_TAG "CUESHEET"
44
45 #define STR_ID3V2_RATEING_TAG "POPM"
46 #define STR_FLAC_RATING_TAG "RATING"
47 //#define STR_WMA_RATING_TAG "RATING WMP"
48
49 //将taglib中的字符串转换成std::wstring类型。
50 //由于taglib将所有非unicode编码全部作为Latin编码处理,因此无法正确处理本地代码页
51 //这里将Latin编码的字符串按本地代码页处理
TagStringToWstring(const String & str,bool to_local)52 static std::wstring TagStringToWstring(const String& str, bool to_local)
53 {
54 std::wstring result;
55 if (to_local && str.isLatin1())
56 result = CCommon::StrToUnicode(str.to8Bit(), CodeType::ANSI);
57 else
58 result = str.toWString();
59 return result;
60 }
61
SongInfoToTag(const SongInfo & song_info,Tag * tag)62 static void SongInfoToTag(const SongInfo& song_info, Tag* tag)
63 {
64 if (tag != nullptr)
65 {
66 tag->setTitle(song_info.title);
67 tag->setArtist(song_info.artist);
68 tag->setAlbum(song_info.album);
69 tag->setGenre(song_info.genre);
70 tag->setTrack(song_info.track);
71 tag->setComment(song_info.comment);
72 tag->setYear(song_info.year);
73 }
74 }
75
IsStringNumber(std::wstring str,int num)76 static bool IsStringNumber(std::wstring str, int num)
77 {
78 if (!str.empty() && str.front() == L'(')
79 str = str.substr(1);
80 if (!str.empty() && str.back() == L')')
81 str.pop_back();
82 if (CCommon::StrIsNumber(str))
83 {
84 num = _wtoi(str.c_str());
85 return true;
86 }
87 return false;
88 }
89
TagToSongInfo(SongInfo & song_info,Tag * tag,bool to_local)90 static void TagToSongInfo(SongInfo& song_info, Tag* tag, bool to_local)
91 {
92 if (tag != nullptr)
93 {
94 song_info.title = TagStringToWstring(tag->title(), to_local);
95 song_info.artist = TagStringToWstring(tag->artist(), to_local);
96 song_info.album = TagStringToWstring(tag->album(), to_local);
97 song_info.genre = TagStringToWstring(tag->genre(), to_local);
98 int genre_num{};
99 if (IsStringNumber(song_info.genre, genre_num))
100 {
101 song_info.genre = CAudioCommon::GetGenre(static_cast<BYTE>(genre_num));
102 }
103
104 song_info.year = tag->year();
105 song_info.track = tag->track();
106 song_info.comment = TagStringToWstring(tag->comment(), to_local);
107 }
108 }
109
110 //将文件内容读取到ByteVector
FileToByteVector(ByteVector & data,const std::wstring & file_path)111 static void FileToByteVector(ByteVector& data, const std::wstring& file_path)
112 {
113 std::ifstream file{ file_path, std::ios::binary | std::ios::in };
114 if (file.fail())
115 return;
116
117 //获取文件长度
118 file.seekg(0, file.end);
119 unsigned int length = static_cast<unsigned int>(file.tellg());
120 file.seekg(0, file.beg);
121
122 data.clear();
123 data.resize(length);
124
125 file.read(data.data(), length);
126
127 file.close();
128 }
129
GetPicType(const std::wstring & mimeType)130 int GetPicType(const std::wstring& mimeType)
131 {
132 int type{ -1 };
133 if (mimeType == L"image/jpeg" || mimeType == L"image/jpg")
134 type = 0;
135 else if (mimeType == L"image/png")
136 type = 1;
137 else if (mimeType == L"image/gif")
138 type = 2;
139 else if (mimeType == L"image/bmp")
140 type = 3;
141 else
142 type = -1;
143 return type;
144 }
145
GetId3v2AlbumCover(ID3v2::Tag * id3v2,string & cover_contents,int & type)146 static void GetId3v2AlbumCover(ID3v2::Tag* id3v2, string& cover_contents, int& type)
147 {
148 if (id3v2 != nullptr)
149 {
150 auto pic_frame_list = id3v2->frameListMap()["APIC"];
151 if (!pic_frame_list.isEmpty())
152 {
153 ID3v2::AttachedPictureFrame* frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(pic_frame_list.front());
154 if (frame != nullptr)
155 {
156 auto pic_data = frame->picture();
157 //获取专辑封面
158 cover_contents.assign(pic_data.data(), pic_data.size());
159 std::wstring img_type = frame->mimeType().toCWString();
160 type = GetPicType(img_type);
161 }
162 }
163 }
164 }
165
DeleteId3v2AlbumCover(ID3v2::Tag * id3v2tag)166 static void DeleteId3v2AlbumCover(ID3v2::Tag* id3v2tag)
167 {
168 if (id3v2tag != nullptr)
169 {
170 auto pic_frame_list = id3v2tag->frameListMap()["APIC"];
171 if (!pic_frame_list.isEmpty())
172 {
173 for (auto frame : pic_frame_list)
174 id3v2tag->removeFrame(frame);
175 }
176 }
177 }
178
WriteId3v2AlbumCover(ID3v2::Tag * id3v2tag,const std::wstring & album_cover_path)179 static void WriteId3v2AlbumCover(ID3v2::Tag* id3v2tag, const std::wstring& album_cover_path)
180 {
181 if (id3v2tag != nullptr)
182 {
183 //读取图片文件
184 ByteVector pic_data;
185 FileToByteVector(pic_data, album_cover_path);
186 //向音频文件写入图片文件
187 ID3v2::AttachedPictureFrame* pic_frame = new ID3v2::AttachedPictureFrame();
188 pic_frame->setPicture(pic_data);
189 pic_frame->setType(ID3v2::AttachedPictureFrame::FrontCover);
190 std::wstring ext = CFilePathHelper(album_cover_path).GetFileExtension();
191 pic_frame->setMimeType(L"image/" + ext);
192 id3v2tag->addFrame(pic_frame);
193 }
194 }
195
196
GetApeTagAlbumCover(APE::Tag * tag,string & cover_contents,int & type)197 static void GetApeTagAlbumCover(APE::Tag* tag, string& cover_contents, int& type)
198 {
199 if (tag != nullptr)
200 {
201 auto item_list_map = tag->itemListMap();
202 auto pic_item = item_list_map[STR_APE_COVER_TAG];
203 auto pic_data = pic_item.binaryData();
204 if (!pic_data.isEmpty())
205 {
206 cover_contents.assign(pic_data.data(), pic_data.size());
207
208 size_t index{};
209 index = cover_contents.find('\0');
210 std::string pic_desc;
211 if (index != std::string::npos)
212 {
213 pic_desc = cover_contents.substr(0, index);
214 cover_contents = cover_contents.substr(index + 1);
215 }
216
217 if (!pic_desc.empty())
218 {
219 std::string img_type;
220 index = pic_desc.rfind('.');
221 if (index != std::string::npos && index < pic_desc.size() - 1)
222 {
223 img_type = pic_desc.substr(index + 1);
224 img_type = "image/" + img_type;
225 type = GetPicType(CCommon::ASCIIToUnicode(img_type));
226 }
227 }
228 }
229 }
230 }
231
WriteApeTagAlbumCover(APE::Tag * tag,const std::wstring & album_cover_path,bool remove_exist)232 static void WriteApeTagAlbumCover(APE::Tag* tag, const std::wstring& album_cover_path, bool remove_exist)
233 {
234 if (remove_exist)
235 {
236 tag->removeItem(STR_APE_COVER_TAG);
237 }
238
239 if (!album_cover_path.empty())
240 {
241 ByteVector pic_data;
242 FileToByteVector(pic_data, album_cover_path);
243
244 ByteVector pic_item_data;
245 pic_item_data = "Cover Art (Front).";
246 std::wstring file_type = CFilePathHelper(album_cover_path).GetFileExtension();
247 for (wchar_t ch : file_type)
248 pic_item_data.append(static_cast<char>(ch));
249 pic_item_data.append('\0');
250 pic_item_data.append(pic_data);
251
252 APE::Item pic_item(STR_APE_COVER_TAG, pic_item_data, true);
253 tag->setItem(STR_APE_COVER_TAG, pic_item);
254 }
255 }
256
WriteXiphCommentAlbumCover(Ogg::XiphComment * tag,const std::wstring & album_cover_path,bool remove_exist)257 static void WriteXiphCommentAlbumCover(Ogg::XiphComment* tag, const std::wstring& album_cover_path, bool remove_exist)
258 {
259 //先删除专辑封面
260 if (remove_exist)
261 {
262 tag->removeAllPictures();
263 }
264
265 if (!album_cover_path.empty())
266 {
267 ByteVector pic_data;
268 FileToByteVector(pic_data, album_cover_path);
269 FLAC::Picture* newpic = new FLAC::Picture();
270 newpic->setType(FLAC::Picture::FrontCover);
271 newpic->setData(pic_data);
272 std::wstring ext = CFilePathHelper(album_cover_path).GetFileExtension();
273 newpic->setMimeType(L"image/" + ext);
274 tag->addPicture(newpic);
275 }
276 }
277
278
GetXiphCommentAlbumCover(Ogg::XiphComment * tag,string & cover_contents,int & type)279 static void GetXiphCommentAlbumCover(Ogg::XiphComment* tag, string& cover_contents, int& type)
280 {
281 const auto& cover_list = tag->pictureList();
282 if (!cover_list.isEmpty())
283 {
284 auto pic = cover_list.front();
285 if (pic != nullptr)
286 {
287 const auto& pic_data = pic->data();
288 //获取专辑封面
289 cover_contents.assign(pic_data.data(), pic_data.size());
290
291 std::wstring img_type = pic->mimeType().toCWString();
292 type = GetPicType(img_type);
293 }
294 }
295 }
296
GetId3v2Lyric(ID3v2::Tag * id3v2)297 static std::wstring GetId3v2Lyric(ID3v2::Tag* id3v2)
298 {
299 std::wstring lyrics;
300 if (id3v2 != nullptr)
301 {
302 auto frame_list_map = id3v2->frameListMap();
303 auto lyric_frame = frame_list_map[STR_ID3V2_LYRIC_TAG];
304 if (!lyric_frame.isEmpty())
305 lyrics = lyric_frame.front()->toString().toWString();
306 }
307 return lyrics;
308 }
309
310
WriteId3v2Lyric(ID3v2::Tag * id3v2,const std::wstring & lyric_contents)311 static void WriteId3v2Lyric(ID3v2::Tag* id3v2, const std::wstring& lyric_contents)
312 {
313 if (id3v2 != nullptr)
314 {
315 //先删除歌词帧
316 auto lyric_frame_list = id3v2->frameListMap()[STR_ID3V2_LYRIC_TAG];
317 if (!lyric_frame_list.isEmpty())
318 {
319 for (auto frame : lyric_frame_list)
320 id3v2->removeFrame(frame);
321 }
322
323 if (!lyric_contents.empty())
324 {
325 //写入歌词帧
326 ID3v2::UnsynchronizedLyricsFrame* lyric_frame = new ID3v2::UnsynchronizedLyricsFrame();
327 lyric_frame->setText(lyric_contents.c_str());
328 id3v2->addFrame(lyric_frame);
329 }
330 }
331 }
332
333
334 template<class T>
GetTagPropertyMap(T * tag,std::map<std::wstring,std::wstring> & property_map)335 void GetTagPropertyMap(T* tag, std::map<std::wstring, std::wstring>& property_map)
336 {
337 if (tag != nullptr)
338 {
339 auto properties = tag->properties();
340 for (const auto& prop : properties)
341 {
342 std::wstring key = prop.first.toWString();
343 std::wstring value = TagStringToWstring(prop.second.toString(L";"), true);
344 auto iter = property_map.find(key);
345 if (iter == property_map.end())
346 property_map[key] = value;
347 else if (iter->second.empty())
348 iter->second = value;
349 }
350 }
351 }
352
GetMapValue(const std::wstring & key,const std::map<std::wstring,std::wstring> & property_map)353 static std::wstring GetMapValue(const std::wstring& key, const std::map<std::wstring, std::wstring>& property_map)
354 {
355 auto iter = property_map.find(key);
356 if (iter != property_map.end())
357 return iter->second;
358 return std::wstring();
359 }
360
361 //将标签属性中额外的信息保存到SongInfo中
OtherPropertyToSongInfo(SongInfo & song_info,const std::map<std::wstring,std::wstring> & property_map)362 static void OtherPropertyToSongInfo(SongInfo& song_info, const std::map<std::wstring, std::wstring>& property_map)
363 {
364 //获取唱片集艺术家
365 song_info.album_artist = GetMapValue(L"ALBUMARTIST", property_map);
366
367 //获取音轨总数
368 std::wstring track_number = GetMapValue(L"TRACKNUMBER", property_map);
369 size_t index = track_number.find(L'/');
370 if (index != std::wstring::npos)
371 {
372 song_info.total_tracks = static_cast<BYTE>(_wtoi(track_number.substr(index + 1).c_str()));
373 }
374
375 //获取CD序号和CD总数
376 std::wstring disc_number = GetMapValue(L"DISCNUMBER", property_map);
377 index = disc_number.find(L'/');
378 if (index != std::wstring::npos)
379 {
380 song_info.total_discs = static_cast<BYTE>(CCommon::StringToInt(disc_number.substr(index + 1)));
381 }
382 song_info.disc_num = static_cast<BYTE>(CCommon::StringToInt(disc_number));
383 }
384
385 template<class T>
WriteOtherProperties(const SongInfo & song_info,T & file)386 static void WriteOtherProperties(const SongInfo& song_info, T& file)
387 {
388 TagLib::PropertyMap properties = file.properties();
389 properties["ALBUMARTIST"].clear();
390 properties["DISCNUMBER"].clear();
391 if (!song_info.album_artist.empty())
392 properties["ALBUMARTIST"].append(song_info.album_artist);
393 if (song_info.disc_num != 0)
394 properties["DISCNUMBER"].append(std::to_wstring(static_cast<int>(song_info.disc_num)));
395 file.setProperties(properties);
396 }
397
398 //解析Windows资源管理器设置的分级信息
ParseAudioRating(int rate_raw)399 static int ParseAudioRating(int rate_raw)
400 {
401 //使用Windows资源管理器设置了分级后,POPM字段的内容为以下格式:
402 //Windows Media Player 9 Series rating=196 counter=0
403 //其中rating后面的数字为分级,rating与分级的对应关系如下所示
404 /*
405 rating | 分级
406 ---------|------------
407 255 | 5
408 196 | 4
409 128 | 3
410 64 | 2
411 1 | 1
412 */
413
414 //根据分级转换成1~5星
415 if (rate_raw == 1)
416 return 1;
417 else if (rate_raw <= 64)
418 return 2;
419 else if (rate_raw <= 128)
420 return 3;
421 else if (rate_raw <= 196)
422 return 4;
423 else if (rate_raw <= 255)
424 return 5;
425 return 0;
426 }
427
GenerateAudioRating(int rate)428 static int GenerateAudioRating(int rate)
429 {
430 switch (rate)
431 {
432 case 1:
433 return 1;
434 case 2:
435 return 64;
436 case 3:
437 return 128;
438 case 4:
439 return 196;
440 case 5:
441 return 255;
442 default:
443 return 0;
444 }
445 }
446
GetId3v2Rating(ID3v2::Tag * id3v2)447 static int GetId3v2Rating(ID3v2::Tag* id3v2)
448 {
449 if (id3v2 != nullptr)
450 {
451 auto frame_list_map = id3v2->frameListMap();
452 auto rate_frame = frame_list_map[STR_ID3V2_RATEING_TAG];
453 if (!rate_frame.isEmpty())
454 {
455 ID3v2::PopularimeterFrame* pFrame = dynamic_cast<ID3v2::PopularimeterFrame*>(rate_frame.front());
456 if (pFrame != nullptr)
457 {
458 int rate_raw = pFrame->rating();
459 return ParseAudioRating(rate_raw);
460 }
461 }
462 }
463 return 0;
464 }
465
WriteId3v2Rating(ID3v2::Tag * id3v2,int rate)466 static void WriteId3v2Rating(ID3v2::Tag* id3v2, int rate)
467 {
468 if (id3v2 != nullptr)
469 {
470 auto frameListMap = id3v2->frameListMap();
471
472 //先删除POPM帧
473 auto rate_frame_list = id3v2->frameListMap()[STR_ID3V2_RATEING_TAG];
474 if (!rate_frame_list.isEmpty())
475 {
476 for (auto frame : rate_frame_list)
477 id3v2->removeFrame(frame);
478 }
479
480 if (rate >= 1 && rate <= 5)
481 {
482 ID3v2::PopularimeterFrame* rate_frame = new ID3v2::PopularimeterFrame();
483 int rate_raw = GenerateAudioRating(rate);
484 rate_frame->setRating(rate_raw);
485 id3v2->addFrame(rate_frame);
486 }
487 }
488 }
489
getFlacPropertyMap(FLAC::File & file,std::map<std::wstring,std::wstring> & property_map)490 static void getFlacPropertyMap(FLAC::File& file, std::map<std::wstring, std::wstring>& property_map)
491 {
492 if (file.hasXiphComment())
493 GetTagPropertyMap(file.xiphComment(), property_map);
494 if (file.hasID3v2Tag())
495 GetTagPropertyMap(file.ID3v2Tag(), property_map);
496 if (file.hasID3v1Tag())
497 GetTagPropertyMap(file.ID3v1Tag(), property_map);
498 }
499
getM4aPropertyMap(MP4::File & file,std::map<std::wstring,std::wstring> & property_map)500 static void getM4aPropertyMap(MP4::File& file, std::map<std::wstring, std::wstring>& property_map)
501 {
502 auto tag = file.tag();
503 GetTagPropertyMap(tag, property_map);
504 }
505
getMpegPropertyMap(MPEG::File & file,std::map<std::wstring,std::wstring> & property_map)506 static void getMpegPropertyMap(MPEG::File& file, std::map<std::wstring, std::wstring>& property_map)
507 {
508 if (file.hasID3v2Tag())
509 GetTagPropertyMap(file.ID3v2Tag(), property_map);
510 if (file.hasAPETag())
511 GetTagPropertyMap(file.APETag(), property_map);
512 if (file.hasID3v1Tag())
513 GetTagPropertyMap(file.ID3v1Tag(), property_map);
514 }
515
getAsfPropertyMap(ASF::File & file,std::map<std::wstring,std::wstring> & property_map)516 static void getAsfPropertyMap(ASF::File& file, std::map<std::wstring, std::wstring>& property_map)
517 {
518 auto tag = file.tag();
519 GetTagPropertyMap(tag, property_map);
520 }
521
getApePropertyMap(APE::File & file,std::map<std::wstring,std::wstring> & property_map)522 static void getApePropertyMap(APE::File& file, std::map<std::wstring, std::wstring>& property_map)
523 {
524 if (file.hasAPETag())
525 GetTagPropertyMap(file.APETag(), property_map);
526 if (file.hasID3v1Tag())
527 GetTagPropertyMap(file.ID3v1Tag(), property_map);
528 }
529
getWavPropertyMap(RIFF::WAV::File & file,std::map<std::wstring,std::wstring> & property_map)530 static void getWavPropertyMap(RIFF::WAV::File& file, std::map<std::wstring, std::wstring>& property_map)
531 {
532 if (file.hasID3v2Tag())
533 GetTagPropertyMap(file.ID3v2Tag(), property_map);
534 if (file.hasInfoTag())
535 GetTagPropertyMap(file.InfoTag(), property_map);
536 }
537
getOggPropertyMap(Vorbis::File & file,std::map<std::wstring,std::wstring> & property_map)538 static void getOggPropertyMap(Vorbis::File& file, std::map<std::wstring, std::wstring>& property_map)
539 {
540 auto tag = file.tag();
541 GetTagPropertyMap(tag, property_map);
542 }
543
getMpcPropertyMap(MPC::File & file,std::map<std::wstring,std::wstring> & property_map)544 static void getMpcPropertyMap(MPC::File& file, std::map<std::wstring, std::wstring>& property_map)
545 {
546 if (file.hasAPETag())
547 GetTagPropertyMap(file.APETag(), property_map);
548 if (file.hasID3v1Tag())
549 GetTagPropertyMap(file.ID3v1Tag(), property_map);
550 }
551
getOpusPropertyMap(Ogg::Opus::File & file,std::map<std::wstring,std::wstring> & property_map)552 static void getOpusPropertyMap(Ogg::Opus::File& file, std::map<std::wstring, std::wstring>& property_map)
553 {
554 auto tag = file.tag();
555 GetTagPropertyMap(tag, property_map);
556 }
557
getWavPackPropertyMap(WavPack::File & file,std::map<std::wstring,std::wstring> & property_map)558 static void getWavPackPropertyMap(WavPack::File& file, std::map<std::wstring, std::wstring>& property_map)
559 {
560 if (file.hasAPETag())
561 GetTagPropertyMap(file.APETag(), property_map);
562 if (file.hasID3v1Tag())
563 GetTagPropertyMap(file.ID3v1Tag(), property_map);
564 }
565
getTtaPropertyMap(TrueAudio::File & file,std::map<std::wstring,std::wstring> & property_map)566 static void getTtaPropertyMap(TrueAudio::File& file, std::map<std::wstring, std::wstring>& property_map)
567 {
568 if (file.hasID3v2Tag())
569 GetTagPropertyMap(file.ID3v2Tag(), property_map);
570 if (file.hasID3v1Tag())
571 GetTagPropertyMap(file.ID3v1Tag(), property_map);
572 }
573
getAiffPropertyMap(RIFF::AIFF::File & file,std::map<std::wstring,std::wstring> & property_map)574 static void getAiffPropertyMap(RIFF::AIFF::File& file, std::map<std::wstring, std::wstring>& property_map)
575 {
576 auto tag = file.tag();
577 GetTagPropertyMap(tag, property_map);
578 }
579
getSpxPropertyMap(Ogg::Speex::File & file,std::map<std::wstring,std::wstring> & property_map)580 static void getSpxPropertyMap(Ogg::Speex::File& file, std::map<std::wstring, std::wstring>& property_map)
581 {
582 auto tag = file.tag();
583 GetTagPropertyMap(tag, property_map);
584 }
585
getAnyFilePropertyMap(FileRef & file,std::map<std::wstring,std::wstring> & property_map)586 static void getAnyFilePropertyMap(FileRef& file, std::map<std::wstring, std::wstring>& property_map)
587 {
588 auto tag = file.tag();
589 GetTagPropertyMap(tag, property_map);
590 }
591
592
593 ///////////////////////////////////////////////////////////////////////////////////
594 ///////////////////////////////////////////////////////////////////////////////////
595 ///////////////////////////////////////////////////////////////////////////////////
596
597 bool CTagLibHelper::m_write_id3v2_3{ false };
598
CTagLibHelper()599 CTagLibHelper::CTagLibHelper()
600 {
601 }
602
~CTagLibHelper()603 CTagLibHelper::~CTagLibHelper()
604 {
605 }
606
SetWriteId3V2_3(bool write_id3v2_3)607 void CTagLibHelper::SetWriteId3V2_3(bool write_id3v2_3)
608 {
609 m_write_id3v2_3 = write_id3v2_3;
610 }
611
GetM4aAlbumCover(const std::wstring & file_path,int & type)612 string CTagLibHelper::GetM4aAlbumCover(const std::wstring& file_path, int& type)
613 {
614 string cover_contents;
615 MP4::File file(file_path.c_str());
616 auto tag = file.tag();
617 if (tag != nullptr)
618 {
619 auto cover_item = tag->item(STR_MP4_COVER_TAG).toCoverArtList();
620 if (!cover_item.isEmpty())
621 {
622 const auto& pic_data = cover_item.front().data();
623 //获取专辑封面
624 cover_contents.assign(pic_data.data(), pic_data.size());
625
626 //获取封面格式
627 switch (cover_item.front().format())
628 {
629 case MP4::CoverArt::JPEG:
630 type = 0;
631 break;
632 case MP4::CoverArt::PNG:
633 type = 1;
634 break;
635 case MP4::CoverArt::BMP:
636 type = 3;
637 break;
638 case MP4::CoverArt::GIF:
639 type = 2;
640 break;
641 default:
642 type = -1;
643 break;
644 }
645 }
646 }
647 return cover_contents;
648 }
649
GetFlacAlbumCover(const std::wstring & file_path,int & type)650 string CTagLibHelper::GetFlacAlbumCover(const std::wstring& file_path, int& type)
651 {
652 string cover_contents;
653 FLAC::File file(file_path.c_str());
654 const auto& cover_list = file.pictureList();
655 if (!cover_list.isEmpty())
656 {
657 auto pic = cover_list.front();
658 if (pic != nullptr)
659 {
660 const auto& pic_data = pic->data();
661 //获取专辑封面
662 cover_contents.assign(pic_data.data(), pic_data.size());
663
664 std::wstring img_type = pic->mimeType().toCWString();
665 type = GetPicType(img_type);
666 }
667 }
668 return cover_contents;
669 }
670
GetMp3AlbumCover(const std::wstring & file_path,int & type)671 string CTagLibHelper::GetMp3AlbumCover(const std::wstring& file_path, int& type)
672 {
673 string cover_contents;
674 MPEG::File file(file_path.c_str());
675 auto id3v2 = file.ID3v2Tag();
676 GetId3v2AlbumCover(id3v2, cover_contents, type);
677 return cover_contents;
678 }
679
GetAsfAlbumCover(const std::wstring & file_path,int & type)680 string CTagLibHelper::GetAsfAlbumCover(const std::wstring& file_path, int& type)
681 {
682 string cover_contents;
683 ASF::File file(file_path.c_str());
684 auto tag = file.tag();
685 if (tag != nullptr)
686 {
687 ASF::AttributeList attr = tag->attribute("WM/Picture");
688 if (!attr.isEmpty())
689 {
690 ASF::Picture picture = attr.front().toPicture();
691 auto pic_data = picture.picture();
692 cover_contents.assign(pic_data.data(), pic_data.size());
693 std::wstring img_type = picture.mimeType().toCWString();
694 type = GetPicType(img_type);
695 }
696 }
697 return cover_contents;
698 }
699
GetWavAlbumCover(const std::wstring & file_path,int & type)700 string CTagLibHelper::GetWavAlbumCover(const std::wstring& file_path, int& type)
701 {
702 string cover_contents;
703 RIFF::WAV::File file(file_path.c_str());
704 auto id3v2 = file.ID3v2Tag();
705 GetId3v2AlbumCover(id3v2, cover_contents, type);
706 return cover_contents;
707 }
708
GetTtaAlbumCover(const std::wstring & file_path,int & type)709 string CTagLibHelper::GetTtaAlbumCover(const std::wstring& file_path, int& type)
710 {
711 string cover_contents;
712 TrueAudio::File file(file_path.c_str());
713 auto id3v2 = file.ID3v2Tag();
714 GetId3v2AlbumCover(id3v2, cover_contents, type);
715 return cover_contents;
716 }
717
GetApeAlbumCover(const std::wstring & file_path,int & type)718 string CTagLibHelper::GetApeAlbumCover(const std::wstring& file_path, int& type)
719 {
720 string cover_contents;
721 APE::File file(file_path.c_str());
722 auto tag = file.APETag();
723 GetApeTagAlbumCover(tag, cover_contents, type);
724 return cover_contents;
725 }
726
727
GetOggAlbumCover(const std::wstring & file_path,int & type)728 string CTagLibHelper::GetOggAlbumCover(const std::wstring& file_path, int& type)
729 {
730 string cover_contents;
731 Ogg::Vorbis::File file(file_path.c_str());
732 auto tag = file.tag();
733 if (tag != nullptr)
734 {
735 GetXiphCommentAlbumCover(tag, cover_contents, type);
736 }
737 return cover_contents;
738 }
739
GetOpusAlbumCover(const std::wstring & file_path,int & type)740 string CTagLibHelper::GetOpusAlbumCover(const std::wstring& file_path, int& type)
741 {
742 string cover_contents;
743 Ogg::Opus::File file(file_path.c_str());
744 auto tag = file.tag();
745 if (tag != nullptr)
746 {
747 GetXiphCommentAlbumCover(tag, cover_contents, type);
748 }
749 return cover_contents;
750 }
751
GetSpxAlbumCover(const std::wstring & file_path,int & type)752 string CTagLibHelper::GetSpxAlbumCover(const std::wstring& file_path, int& type)
753 {
754 string cover_contents;
755 Ogg::Speex::File file(file_path.c_str());
756 auto tag = file.tag();
757 if (tag != nullptr)
758 {
759 GetXiphCommentAlbumCover(tag, cover_contents, type);
760 }
761 return cover_contents;
762 }
763
GetAiffAlbumCover(const std::wstring & file_path,int & type)764 string CTagLibHelper::GetAiffAlbumCover(const std::wstring& file_path, int& type)
765 {
766 string cover_contents;
767 RIFF::AIFF::File file(file_path.c_str());
768 auto id3v2 = file.tag();
769 GetId3v2AlbumCover(id3v2, cover_contents, type);
770 return cover_contents;
771
772 }
773
GetMpcAlbumCover(const std::wstring & file_path,int & type)774 string CTagLibHelper::GetMpcAlbumCover(const std::wstring& file_path, int& type)
775 {
776 string cover_contents;
777 MPC::File file(file_path.c_str());
778 auto ape_tag = file.APETag();
779 GetApeTagAlbumCover(ape_tag, cover_contents, type);
780 return cover_contents;
781 }
782
GetWavePackAlbumCover(const std::wstring & file_path,int & type)783 string CTagLibHelper::GetWavePackAlbumCover(const std::wstring& file_path, int& type)
784 {
785 string cover_contents;
786 WavPack::File file(file_path.c_str());
787 auto ape_tag = file.APETag();
788 GetApeTagAlbumCover(ape_tag, cover_contents, type);
789 return cover_contents;
790 }
791
GetFlacTagInfo(SongInfo & song_info)792 void CTagLibHelper::GetFlacTagInfo(SongInfo& song_info)
793 {
794 FLAC::File file(song_info.file_path.c_str());
795 if (file.hasID3v1Tag())
796 song_info.tag_type |= T_ID3V1;
797 if (file.hasID3v2Tag())
798 song_info.tag_type |= T_ID3V2;
799 auto tag = file.tag();
800 if (tag != nullptr)
801 {
802 TagToSongInfo(song_info, tag, true);
803 }
804 std::map<std::wstring, std::wstring> property_map;
805 getFlacPropertyMap(file, property_map);
806 OtherPropertyToSongInfo(song_info, property_map);
807 }
808
GetM4aTagInfo(SongInfo & song_info)809 void CTagLibHelper::GetM4aTagInfo(SongInfo& song_info)
810 {
811 MP4::File file(song_info.file_path.c_str());
812 if (file.hasMP4Tag())
813 song_info.tag_type |= T_MP4;
814 auto tag = file.tag();
815 if (tag != nullptr)
816 {
817 TagToSongInfo(song_info, tag, false);
818 }
819 std::map<std::wstring, std::wstring> property_map;
820 getM4aPropertyMap(file, property_map);
821 OtherPropertyToSongInfo(song_info, property_map);
822 }
823
GetMpegTagInfo(SongInfo & song_info)824 void CTagLibHelper::GetMpegTagInfo(SongInfo& song_info)
825 {
826 MPEG::File file(song_info.file_path.c_str());
827 if (file.hasID3v1Tag())
828 song_info.tag_type |= T_ID3V1;
829 if (file.hasID3v2Tag())
830 song_info.tag_type |= T_ID3V2;
831 if (file.hasAPETag())
832 song_info.tag_type |= T_APE;
833
834 auto tag = file.tag();
835 if (tag != nullptr)
836 {
837 TagToSongInfo(song_info, tag, true);
838 }
839 std::map<std::wstring, std::wstring> property_map;
840 getMpegPropertyMap(file, property_map);
841 OtherPropertyToSongInfo(song_info, property_map);
842 }
843
GetAsfTagInfo(SongInfo & song_info)844 void CTagLibHelper::GetAsfTagInfo(SongInfo& song_info)
845 {
846 ASF::File file(song_info.file_path.c_str());
847 auto tag = file.tag();
848 if (tag != nullptr)
849 {
850 TagToSongInfo(song_info, tag, false);
851 }
852 std::map<std::wstring, std::wstring> property_map;
853 getAsfPropertyMap(file, property_map);
854 OtherPropertyToSongInfo(song_info, property_map);
855 }
856
GetApeTagInfo(SongInfo & song_info)857 void CTagLibHelper::GetApeTagInfo(SongInfo& song_info)
858 {
859 APE::File file(song_info.file_path.c_str());
860 if (file.hasID3v1Tag())
861 song_info.tag_type |= T_ID3V1;
862 if (file.hasAPETag())
863 song_info.tag_type |= T_APE;
864
865 auto tag = file.tag();
866 if (tag != nullptr)
867 {
868 TagToSongInfo(song_info, tag, true);
869 }
870 std::map<std::wstring, std::wstring> property_map;
871 getApePropertyMap(file, property_map);
872 OtherPropertyToSongInfo(song_info, property_map);
873 }
874
GetWavTagInfo(SongInfo & song_info)875 void CTagLibHelper::GetWavTagInfo(SongInfo& song_info)
876 {
877 RIFF::WAV::File file(song_info.file_path.c_str());
878 if (file.hasID3v2Tag())
879 song_info.tag_type |= T_ID3V2;
880 if (file.hasInfoTag())
881 song_info.tag_type |= T_RIFF;
882 auto tag = file.tag();
883 if (tag != nullptr)
884 {
885 TagToSongInfo(song_info, tag, false);
886 }
887 std::map<std::wstring, std::wstring> property_map;
888 getWavPropertyMap(file, property_map);
889 OtherPropertyToSongInfo(song_info, property_map);
890 }
891
GetOggTagInfo(SongInfo & song_info)892 void CTagLibHelper::GetOggTagInfo(SongInfo& song_info)
893 {
894 Vorbis::File file(song_info.file_path.c_str());
895 auto tag = file.tag();
896 if (tag != nullptr)
897 {
898 TagToSongInfo(song_info, tag, false);
899 }
900 std::map<std::wstring, std::wstring> property_map;
901 getOggPropertyMap(file, property_map);
902 OtherPropertyToSongInfo(song_info, property_map);
903 }
904
GetMpcTagInfo(SongInfo & song_info)905 void CTagLibHelper::GetMpcTagInfo(SongInfo& song_info)
906 {
907 MPC::File file(song_info.file_path.c_str());
908 if (file.hasAPETag())
909 song_info.tag_type |= T_APE;
910 if (file.hasID3v1Tag())
911 song_info.tag_type |= T_ID3V1;
912 auto tag = file.tag();
913 if (tag != nullptr)
914 {
915 TagToSongInfo(song_info, tag, true);
916 }
917 std::map<std::wstring, std::wstring> property_map;
918 getMpcPropertyMap(file, property_map);
919 OtherPropertyToSongInfo(song_info, property_map);
920 }
921
GetOpusTagInfo(SongInfo & song_info)922 void CTagLibHelper::GetOpusTagInfo(SongInfo& song_info)
923 {
924 Ogg::Opus::File file(song_info.file_path.c_str());
925 auto tag = file.tag();
926 if (tag != nullptr)
927 {
928 TagToSongInfo(song_info, tag, false);
929 }
930 std::map<std::wstring, std::wstring> property_map;
931 getOpusPropertyMap(file, property_map);
932 OtherPropertyToSongInfo(song_info, property_map);
933 }
934
GetWavPackTagInfo(SongInfo & song_info)935 void CTagLibHelper::GetWavPackTagInfo(SongInfo& song_info)
936 {
937 WavPack::File file(song_info.file_path.c_str());
938 if (file.hasAPETag())
939 song_info.tag_type |= T_APE;
940 if (file.hasID3v1Tag())
941 song_info.tag_type |= T_ID3V1;
942 auto tag = file.tag();
943 if (tag != nullptr)
944 {
945 TagToSongInfo(song_info, tag, true);
946 }
947 std::map<std::wstring, std::wstring> property_map;
948 getWavPackPropertyMap(file, property_map);
949 OtherPropertyToSongInfo(song_info, property_map);
950 }
951
GetTtaTagInfo(SongInfo & song_info)952 void CTagLibHelper::GetTtaTagInfo(SongInfo& song_info)
953 {
954 TrueAudio::File file(song_info.file_path.c_str());
955 if (file.hasID3v1Tag())
956 song_info.tag_type |= T_ID3V1;
957 if (file.hasID3v2Tag())
958 song_info.tag_type |= T_ID3V2;
959 auto tag = file.tag();
960 if (tag != nullptr)
961 {
962 TagToSongInfo(song_info, tag, true);
963 }
964 std::map<std::wstring, std::wstring> property_map;
965 getTtaPropertyMap(file, property_map);
966 OtherPropertyToSongInfo(song_info, property_map);
967 }
968
GetAiffTagInfo(SongInfo & song_info)969 void CTagLibHelper::GetAiffTagInfo(SongInfo& song_info)
970 {
971 RIFF::AIFF::File file(song_info.file_path.c_str());
972 if (file.hasID3v2Tag())
973 song_info.tag_type |= T_ID3V2;
974 auto tag = file.tag();
975 if (tag != nullptr)
976 {
977 TagToSongInfo(song_info, tag, false);
978 }
979 std::map<std::wstring, std::wstring> property_map;
980 getAiffPropertyMap(file, property_map);
981 OtherPropertyToSongInfo(song_info, property_map);
982 }
983
GetSpxTagInfo(SongInfo & song_info)984 void CTagLibHelper::GetSpxTagInfo(SongInfo& song_info)
985 {
986 Ogg::Speex::File file(song_info.file_path.c_str());
987 auto tag = file.tag();
988 if (tag != nullptr)
989 {
990 TagToSongInfo(song_info, tag, false);
991 }
992 std::map<std::wstring, std::wstring> property_map;
993 getSpxPropertyMap(file, property_map);
994 OtherPropertyToSongInfo(song_info, property_map);
995 }
996
GetAnyFileTagInfo(SongInfo & song_info)997 void CTagLibHelper::GetAnyFileTagInfo(SongInfo& song_info)
998 {
999 FileRef file(song_info.file_path.c_str());
1000 auto tag = file.tag();
1001 if (tag != nullptr)
1002 {
1003 TagToSongInfo(song_info, tag, false);
1004 }
1005 std::map<std::wstring, std::wstring> property_map;
1006 getAnyFilePropertyMap(file, property_map);
1007 OtherPropertyToSongInfo(song_info, property_map);
1008 }
1009
GetFlacPropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1010 void CTagLibHelper::GetFlacPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1011 {
1012 FLAC::File file(file_path.c_str());
1013 getFlacPropertyMap(file, property_map);
1014 }
1015
GetM4aPropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1016 void CTagLibHelper::GetM4aPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1017 {
1018 MP4::File file(file_path.c_str());
1019 getM4aPropertyMap(file, property_map);
1020 }
1021
GetMpegPropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1022 void CTagLibHelper::GetMpegPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1023 {
1024 MPEG::File file(file_path.c_str());
1025 getMpegPropertyMap(file, property_map);
1026 }
1027
GetAsfPropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1028 void CTagLibHelper::GetAsfPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1029 {
1030 ASF::File file(file_path.c_str());
1031 getAsfPropertyMap(file, property_map);
1032 }
1033
GetApePropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1034 void CTagLibHelper::GetApePropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1035 {
1036 APE::File file(file_path.c_str());
1037 getApePropertyMap(file, property_map);
1038 }
1039
GetWavPropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1040 void CTagLibHelper::GetWavPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1041 {
1042 RIFF::WAV::File file(file_path.c_str());
1043 getWavPropertyMap(file, property_map);
1044 }
1045
GetOggPropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1046 void CTagLibHelper::GetOggPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1047 {
1048 Vorbis::File file(file_path.c_str());
1049 getOggPropertyMap(file, property_map);
1050 }
1051
GetMpcPropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1052 void CTagLibHelper::GetMpcPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1053 {
1054 MPC::File file(file_path.c_str());
1055 getMpcPropertyMap(file, property_map);
1056 }
1057
GetOpusPropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1058 void CTagLibHelper::GetOpusPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1059 {
1060 Ogg::Opus::File file(file_path.c_str());
1061 getOpusPropertyMap(file, property_map);
1062 }
1063
GetWavPackPropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1064 void CTagLibHelper::GetWavPackPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1065 {
1066 WavPack::File file(file_path.c_str());
1067 getWavPackPropertyMap(file, property_map);
1068 }
1069
GetTtaPropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1070 void CTagLibHelper::GetTtaPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1071 {
1072 TrueAudio::File file(file_path.c_str());
1073 getTtaPropertyMap(file, property_map);
1074 }
1075
GetAiffPropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1076 void CTagLibHelper::GetAiffPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1077 {
1078 RIFF::AIFF::File file(file_path.c_str());
1079 getAiffPropertyMap(file, property_map);
1080 }
1081
GetSpxPropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1082 void CTagLibHelper::GetSpxPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1083 {
1084 Ogg::Speex::File file(file_path.c_str());
1085 getSpxPropertyMap(file, property_map);
1086 }
1087
GetAnyFilePropertyMap(const std::wstring & file_path,std::map<std::wstring,std::wstring> & property_map)1088 void CTagLibHelper::GetAnyFilePropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1089 {
1090 FileRef file(file_path.c_str());
1091 getAnyFilePropertyMap(file, property_map);
1092 }
1093
GetMpegLyric(const std::wstring & file_path)1094 std::wstring CTagLibHelper::GetMpegLyric(const std::wstring& file_path)
1095 {
1096 MPEG::File file(file_path.c_str());
1097 auto id3v2 = file.ID3v2Tag();
1098 return GetId3v2Lyric(id3v2);
1099 }
1100
GetM4aLyric(const std::wstring & file_path)1101 std::wstring CTagLibHelper::GetM4aLyric(const std::wstring& file_path)
1102 {
1103 std::wstring lyrics;
1104 MP4::File file(file_path.c_str());
1105 auto tag = file.tag();
1106 if (tag != nullptr)
1107 {
1108 auto item_map = file.tag()->itemMap();
1109 auto lyric_item = item_map[STR_MP4_LYRICS_TAG].toStringList();;
1110 if (!lyric_item.isEmpty())
1111 lyrics = lyric_item.front().toWString();
1112 }
1113 return lyrics;
1114 }
1115
GetFlacLyric(const std::wstring & file_path)1116 std::wstring CTagLibHelper::GetFlacLyric(const std::wstring& file_path)
1117 {
1118 std::wstring lyrics;
1119 FLAC::File file(file_path.c_str());
1120 auto properties = file.properties();
1121 if (file.isValid())
1122 {
1123 auto lyric_item = properties[STR_FLAC_LYRIC_TAG];
1124 if (!lyric_item.isEmpty())
1125 {
1126 lyrics = lyric_item.front().toWString();
1127 }
1128 }
1129 return lyrics;
1130 }
1131
GetAsfLyric(const std::wstring & file_path)1132 std::wstring CTagLibHelper::GetAsfLyric(const std::wstring& file_path)
1133 {
1134 std::wstring lyrics;
1135 ASF::File file(file_path.c_str());
1136 if (file.isValid())
1137 {
1138 auto properties = file.properties();
1139 auto lyric_item = properties[STR_ASF_LYRIC_TAG];
1140 if (!lyric_item.isEmpty())
1141 {
1142 lyrics = lyric_item.front().toWString();
1143 }
1144 }
1145 return lyrics;
1146 }
1147
1148
GetWavLyric(const std::wstring & file_path)1149 std::wstring CTagLibHelper::GetWavLyric(const std::wstring& file_path)
1150 {
1151 RIFF::WAV::File file(file_path.c_str());
1152 auto id3v2 = file.ID3v2Tag();
1153 return GetId3v2Lyric(id3v2);
1154
1155 }
1156
WriteMpegLyric(const std::wstring & file_path,const std::wstring & lyric_contents)1157 bool CTagLibHelper::WriteMpegLyric(const std::wstring& file_path, const std::wstring& lyric_contents)
1158 {
1159 std::wstring lyrics;
1160 MPEG::File file(file_path.c_str());
1161 auto id3v2 = file.ID3v2Tag();
1162 WriteId3v2Lyric(id3v2, lyric_contents);
1163 int tags = MPEG::File::ID3v2;
1164 if (file.hasAPETag())
1165 tags |= MPEG::File::APE;
1166 bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version());
1167 return saved;
1168 }
1169
WriteFlacLyric(const std::wstring & file_path,const std::wstring & lyric_contents)1170 bool CTagLibHelper::WriteFlacLyric(const std::wstring& file_path, const std::wstring& lyric_contents)
1171 {
1172 FLAC::File file(file_path.c_str());
1173 if (file.isValid())
1174 {
1175 auto properties = file.properties();
1176 if (lyric_contents.empty())
1177 {
1178 properties.erase(STR_FLAC_LYRIC_TAG);
1179 }
1180 else
1181 {
1182 StringList lyric_item;
1183 lyric_item.append(lyric_contents);
1184 properties[STR_FLAC_LYRIC_TAG] = lyric_item;
1185 }
1186 file.setProperties(properties);
1187 bool saved = file.save();
1188 return saved;
1189 }
1190 return false;
1191 }
1192
WriteM4aLyric(const std::wstring & file_path,const std::wstring & lyric_contents)1193 bool CTagLibHelper::WriteM4aLyric(const std::wstring& file_path, const std::wstring& lyric_contents)
1194 {
1195 MP4::File file(file_path.c_str());
1196 auto tag = file.tag();
1197 if (tag != nullptr)
1198 {
1199 if (lyric_contents.empty())
1200 {
1201 tag->removeItem(STR_MP4_LYRICS_TAG);
1202 }
1203 else
1204 {
1205 StringList lyric_list;
1206 lyric_list.append(lyric_contents);
1207 MP4::Item lyrics_item(lyric_list);
1208 tag->setItem(STR_MP4_LYRICS_TAG, lyrics_item);
1209 }
1210 bool saved = file.save();
1211 return saved;
1212 }
1213 return false;
1214 }
1215
WriteAsfLyric(const std::wstring & file_path,const std::wstring & lyric_contents)1216 bool CTagLibHelper::WriteAsfLyric(const std::wstring& file_path, const std::wstring& lyric_contents)
1217 {
1218 ASF::File file(file_path.c_str());
1219 if (file.isValid())
1220 {
1221 auto properties = file.properties();
1222 if (lyric_contents.empty())
1223 {
1224 properties.erase(STR_ASF_LYRIC_TAG);
1225 }
1226 else
1227 {
1228 StringList lyric_item;
1229 lyric_item.append(lyric_contents);
1230 properties[STR_ASF_LYRIC_TAG] = lyric_item;
1231 }
1232 file.setProperties(properties);
1233 bool saved = file.save();
1234 return saved;
1235 }
1236 return false;
1237 }
1238
WriteWavLyric(const std::wstring & file_path,const std::wstring & lyric_contents)1239 bool CTagLibHelper::WriteWavLyric(const std::wstring& file_path, const std::wstring& lyric_contents)
1240 {
1241 std::wstring lyrics;
1242 RIFF::WAV::File file(file_path.c_str());
1243 auto id3v2 = file.ID3v2Tag();
1244 WriteId3v2Lyric(id3v2, lyric_contents);
1245 bool saved = file.save(RIFF::WAV::File::TagTypes::AllTags, File::StripOthers, GetWriteId3v2Version());
1246 return saved;
1247 }
1248
WriteMp3AlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1249 bool CTagLibHelper::WriteMp3AlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist)
1250 {
1251 MPEG::File file(file_path.c_str());
1252 if (!file.isValid())
1253 return false;
1254
1255 //先删除专辑封面
1256 if (remove_exist)
1257 {
1258 auto id3v2tag = file.ID3v2Tag();
1259 DeleteId3v2AlbumCover(id3v2tag);
1260 }
1261 if (!album_cover_path.empty())
1262 {
1263 auto id3v2tag = file.ID3v2Tag(true);
1264 WriteId3v2AlbumCover(id3v2tag, album_cover_path);
1265 }
1266 int tags = MPEG::File::ID3v2;
1267 if (file.hasAPETag())
1268 tags |= MPEG::File::APE;
1269 bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version());
1270 return saved;
1271 }
1272
WriteFlacAlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1273 bool CTagLibHelper::WriteFlacAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist)
1274 {
1275 FLAC::File file(file_path.c_str());
1276 if (!file.isValid())
1277 return false;
1278
1279 //先删除专辑封面
1280 if (remove_exist)
1281 {
1282 file.removePictures();
1283 }
1284
1285 if (!album_cover_path.empty())
1286 {
1287 ByteVector pic_data;
1288 FileToByteVector(pic_data, album_cover_path);
1289 FLAC::Picture* newpic = new FLAC::Picture();
1290 newpic->setType(FLAC::Picture::FrontCover);
1291 newpic->setData(pic_data);
1292 std::wstring ext = CFilePathHelper(album_cover_path).GetFileExtension();
1293 newpic->setMimeType(L"image/" + ext);
1294 file.addPicture(newpic);
1295 }
1296 bool saved = file.save();
1297 return saved;
1298 }
1299
WriteM4aAlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1300 bool CTagLibHelper::WriteM4aAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1301 {
1302 MP4::File file(file_path.c_str());
1303 if (!file.isValid())
1304 return false;
1305
1306 auto tag = file.tag();
1307 if (tag == nullptr)
1308 return false;
1309
1310 if (remove_exist)
1311 {
1312 if (tag->contains(STR_MP4_COVER_TAG))
1313 {
1314 tag->removeItem(STR_MP4_COVER_TAG);
1315 }
1316 }
1317
1318 if (!album_cover_path.empty())
1319 {
1320 ByteVector pic_data;
1321 FileToByteVector(pic_data, album_cover_path);
1322 MP4::CoverArt::Format format = MP4::CoverArt::Format::Unknown;
1323 std::wstring ext = CFilePathHelper(album_cover_path).GetFileExtension();
1324 if (ext == L"jpg" || ext == L"jpeg")
1325 format = MP4::CoverArt::Format::JPEG;
1326 else if (ext == L"png")
1327 format = MP4::CoverArt::Format::PNG;
1328 else if (ext == L"gif")
1329 format = MP4::CoverArt::Format::GIF;
1330 else if (ext == L"bmp")
1331 format = MP4::CoverArt::Format::BMP;
1332 MP4::CoverArt cover_item(format, pic_data);
1333
1334 auto cover_item_list = tag->item(STR_MP4_COVER_TAG).toCoverArtList();
1335 cover_item_list.append(cover_item);
1336 tag->setItem(STR_MP4_COVER_TAG, cover_item_list);
1337 }
1338 bool saved = file.save();
1339 return saved;
1340 }
1341
WriteAsfAlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1342 bool CTagLibHelper::WriteAsfAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1343 {
1344 ASF::File file(file_path.c_str());
1345 if (!file.isValid())
1346 return false;
1347
1348 auto tag = file.tag();
1349 if (tag == nullptr)
1350 return false;
1351
1352 if (remove_exist)
1353 {
1354 if (tag->contains(STR_ASF_COVER_TAG))
1355 {
1356 tag->removeItem(STR_ASF_COVER_TAG);
1357 }
1358 }
1359
1360 if (!album_cover_path.empty())
1361 {
1362 ByteVector pic_data;
1363 FileToByteVector(pic_data, album_cover_path);
1364
1365 ASF::Picture picture;
1366 std::wstring str_mine_type = L"image/" + CFilePathHelper(album_cover_path).GetFileExtension();
1367 picture.setMimeType(str_mine_type);
1368 picture.setType(ASF::Picture::FrontCover);
1369 picture.setPicture(pic_data);
1370 tag->setAttribute(STR_ASF_COVER_TAG, picture);
1371 }
1372 bool saved = file.save();
1373 return saved;
1374 }
1375
WriteWavAlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1376 bool CTagLibHelper::WriteWavAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1377 {
1378 RIFF::WAV::File file(file_path.c_str());
1379 if (!file.isValid())
1380 return false;
1381
1382 //先删除专辑封面
1383 auto id3v2tag = file.ID3v2Tag();
1384 if (remove_exist)
1385 {
1386 DeleteId3v2AlbumCover(id3v2tag);
1387 }
1388 if (!album_cover_path.empty())
1389 {
1390 WriteId3v2AlbumCover(id3v2tag, album_cover_path);
1391 }
1392 bool saved = file.save(RIFF::WAV::File::AllTags, File::StripOthers, GetWriteId3v2Version());
1393 return saved;
1394 }
1395
WriteTtaAlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1396 bool CTagLibHelper::WriteTtaAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1397 {
1398 TrueAudio::File file(file_path.c_str());
1399 if (!file.isValid())
1400 return false;
1401
1402 if (remove_exist)
1403 {
1404 auto id3v2tag = file.ID3v2Tag();
1405 DeleteId3v2AlbumCover(id3v2tag);
1406 }
1407 if (!album_cover_path.empty())
1408 {
1409 auto id3v2tag = file.ID3v2Tag(true);
1410 WriteId3v2AlbumCover(id3v2tag, album_cover_path);
1411 }
1412 bool saved = file.save();
1413 return saved;
1414 return false;
1415 }
1416
WriteApeAlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1417 bool CTagLibHelper::WriteApeAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1418 {
1419 APE::File file(file_path.c_str());
1420 if (!file.isValid())
1421 return false;
1422
1423 auto tag = file.APETag(true);
1424 WriteApeTagAlbumCover(tag, album_cover_path, remove_exist);
1425 bool saved = file.save();
1426 return saved;
1427 }
1428
WriteOggAlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1429 bool CTagLibHelper::WriteOggAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1430 {
1431 Ogg::Vorbis::File file(file_path.c_str());
1432 if (!file.isValid())
1433 return false;
1434
1435 auto tag = file.tag();
1436 if (tag != nullptr)
1437 {
1438 WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist);
1439 bool saved = file.save();
1440 return saved;
1441 }
1442 return false;
1443 }
1444
WriteOpusAlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1445 bool CTagLibHelper::WriteOpusAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist)
1446 {
1447 Ogg::Opus::File file(file_path.c_str());
1448 if (!file.isValid())
1449 return false;
1450
1451 auto tag = file.tag();
1452 if (tag != nullptr)
1453 {
1454 WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist);
1455 bool saved = file.save();
1456 return saved;
1457 }
1458 return false;
1459 }
1460
WriteSpxAlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1461 bool CTagLibHelper::WriteSpxAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1462 {
1463 Ogg::Speex::File file(file_path.c_str());
1464 if (!file.isValid())
1465 return false;
1466
1467 auto tag = file.tag();
1468 if (tag != nullptr)
1469 {
1470 WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist);
1471 bool saved = file.save();
1472 return saved;
1473 }
1474 return false;
1475 }
1476
WriteAiffAlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1477 bool CTagLibHelper::WriteAiffAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1478 {
1479 RIFF::AIFF::File file(file_path.c_str());
1480 if (!file.isValid())
1481 return false;
1482
1483 //先删除专辑封面
1484 auto id3v2tag = file.tag();
1485 if (remove_exist)
1486 {
1487 DeleteId3v2AlbumCover(id3v2tag);
1488 }
1489 if (!album_cover_path.empty())
1490 {
1491 WriteId3v2AlbumCover(id3v2tag, album_cover_path);
1492 }
1493 bool saved = file.save(GetWriteId3v2Version());
1494 return saved;
1495 }
1496
WriteMpcAlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1497 bool CTagLibHelper::WriteMpcAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1498 {
1499 MPC::File file(file_path.c_str());
1500 if (!file.isValid())
1501 return false;
1502
1503 auto tag = file.APETag(true);
1504 WriteApeTagAlbumCover(tag, album_cover_path, remove_exist);
1505 bool saved = file.save();
1506 return saved;
1507 }
1508
WriteWavePackAlbumCover(const std::wstring & file_path,const std::wstring & album_cover_path,bool remove_exist)1509 bool CTagLibHelper::WriteWavePackAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1510 {
1511 WavPack::File file(file_path.c_str());
1512 if (!file.isValid())
1513 return false;
1514
1515 auto tag = file.APETag(true);
1516 WriteApeTagAlbumCover(tag, album_cover_path, remove_exist);
1517 bool saved = file.save();
1518 return saved;
1519 }
1520
WriteMpegTag(const SongInfo & song_info)1521 bool CTagLibHelper::WriteMpegTag(const SongInfo& song_info)
1522 {
1523 MPEG::File file(song_info.file_path.c_str());
1524 auto tag = file.tag();
1525 SongInfoToTag(song_info, tag);
1526 int tags = MPEG::File::ID3v2;
1527 //if (file.hasID3v1Tag())
1528 // tags |= MPEG::File::ID3v1;
1529 if (file.hasAPETag())
1530 tags |= MPEG::File::APE;
1531 WriteOtherProperties(song_info, file);
1532 bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version());
1533 return saved;
1534 }
1535
WriteFlacTag(const SongInfo & song_info)1536 bool CTagLibHelper::WriteFlacTag(const SongInfo& song_info)
1537 {
1538 FLAC::File file(song_info.file_path.c_str());
1539 auto tag = file.tag();
1540 SongInfoToTag(song_info, tag);
1541 WriteOtherProperties(song_info, file);
1542 bool saved = file.save();
1543 return saved;
1544 }
1545
WriteM4aTag(const SongInfo & song_info)1546 bool CTagLibHelper::WriteM4aTag(const SongInfo& song_info)
1547 {
1548 MP4::File file(song_info.file_path.c_str());
1549 auto tag = file.tag();
1550 SongInfoToTag(song_info, tag);
1551 bool saved = file.save();
1552 return saved;
1553 }
1554
WriteWavTag(const SongInfo & song_info)1555 bool CTagLibHelper::WriteWavTag(const SongInfo& song_info)
1556 {
1557 RIFF::WAV::File file(song_info.file_path.c_str());
1558 auto tag = file.tag();
1559 SongInfoToTag(song_info, tag);
1560 WriteOtherProperties(song_info, file);
1561 bool saved = file.save(RIFF::WAV::File::AllTags, File::StripOthers, GetWriteId3v2Version());
1562 return saved;
1563 }
1564
WriteOggTag(const SongInfo & song_info)1565 bool CTagLibHelper::WriteOggTag(const SongInfo& song_info)
1566 {
1567 Vorbis::File file(song_info.file_path.c_str());
1568 auto tag = file.tag();
1569 SongInfoToTag(song_info, tag);
1570 WriteOtherProperties(song_info, file);
1571 bool saved = file.save();
1572 return saved;
1573 }
1574
WriteApeTag(const SongInfo & song_info)1575 bool CTagLibHelper::WriteApeTag(const SongInfo& song_info)
1576 {
1577 APE::File file(song_info.file_path.c_str());
1578 auto tag = file.tag();
1579 SongInfoToTag(song_info, tag);
1580 WriteOtherProperties(song_info, file);
1581 bool saved = file.save();
1582 return saved;
1583 }
1584
WriteMpcTag(const SongInfo & song_info)1585 bool CTagLibHelper::WriteMpcTag(const SongInfo& song_info)
1586 {
1587 MPC::File file(song_info.file_path.c_str());
1588 auto tag = file.tag();
1589 SongInfoToTag(song_info, tag);
1590 WriteOtherProperties(song_info, file);
1591 bool saved = file.save();
1592 return saved;
1593 }
1594
WriteOpusTag(const SongInfo & song_info)1595 bool CTagLibHelper::WriteOpusTag(const SongInfo& song_info)
1596 {
1597 Ogg::Opus::File file(song_info.file_path.c_str());
1598 auto tag = file.tag();
1599 SongInfoToTag(song_info, tag);
1600 WriteOtherProperties(song_info, file);
1601 bool saved = file.save();
1602 return saved;
1603 }
1604
WriteWavPackTag(const SongInfo & song_info)1605 bool CTagLibHelper::WriteWavPackTag(const SongInfo& song_info)
1606 {
1607 WavPack::File file(song_info.file_path.c_str());
1608 auto tag = file.tag();
1609 SongInfoToTag(song_info, tag);
1610 WriteOtherProperties(song_info, file);
1611 bool saved = file.save();
1612 return saved;
1613 }
1614
WriteTtaTag(const SongInfo & song_info)1615 bool CTagLibHelper::WriteTtaTag(const SongInfo& song_info)
1616 {
1617 TrueAudio::File file(song_info.file_path.c_str());
1618 auto tag = file.tag();
1619 SongInfoToTag(song_info, tag);
1620 WriteOtherProperties(song_info, file);
1621 bool saved = file.save();
1622 return saved;
1623 }
1624
WriteAiffTag(const SongInfo & song_info)1625 bool CTagLibHelper::WriteAiffTag(const SongInfo& song_info)
1626 {
1627 RIFF::AIFF::File file(song_info.file_path.c_str());
1628 auto tag = file.tag();
1629 SongInfoToTag(song_info, tag);
1630 WriteOtherProperties(song_info, file);
1631 bool saved = file.save(GetWriteId3v2Version());
1632 return saved;
1633 }
1634
WriteAsfTag(const SongInfo & song_info)1635 bool CTagLibHelper::WriteAsfTag(const SongInfo& song_info)
1636 {
1637 ASF::File file(song_info.file_path.c_str());
1638 auto tag = file.tag();
1639 SongInfoToTag(song_info, tag);
1640 WriteOtherProperties(song_info, file);
1641 bool saved = file.save();
1642 return saved;
1643 }
1644
WriteSpxTag(const SongInfo & song_info)1645 bool CTagLibHelper::WriteSpxTag(const SongInfo& song_info)
1646 {
1647 Ogg::Speex::File file(song_info.file_path.c_str());
1648 auto tag = file.tag();
1649 SongInfoToTag(song_info, tag);
1650 WriteOtherProperties(song_info, file);
1651 bool saved = file.save();
1652 return saved;
1653 }
1654
GetApeCue(const std::wstring & file_path)1655 std::wstring CTagLibHelper::GetApeCue(const std::wstring& file_path)
1656 {
1657 std::wstring cue_contents;
1658 APE::File file(file_path.c_str());
1659 auto tag = file.APETag();
1660 if (tag != nullptr)
1661 {
1662 auto item_list_map = tag->itemListMap();
1663 auto cue_item = item_list_map[STR_APE_CUE_TAG];
1664 cue_contents = cue_item.toString().toWString();
1665 }
1666 return cue_contents;
1667 }
1668
GetMepgRating(const std::wstring & file_path)1669 int CTagLibHelper::GetMepgRating(const std::wstring& file_path)
1670 {
1671 MPEG::File file(file_path.c_str());
1672 auto id3v2 = file.ID3v2Tag();
1673 return GetId3v2Rating(id3v2);
1674 }
1675
GetFlacRating(const std::wstring & file_path)1676 int CTagLibHelper::GetFlacRating(const std::wstring& file_path)
1677 {
1678 FLAC::File file(file_path.c_str());
1679 auto properties = file.properties();
1680 if (file.isValid())
1681 {
1682 auto rating_item = properties[STR_FLAC_RATING_TAG];
1683 if (!rating_item.isEmpty())
1684 {
1685 int rating = _wtoi(rating_item.front().toWString().c_str());
1686 return rating;
1687 }
1688 }
1689 return 0;
1690
1691 }
1692
GetWmaRating(const std::wstring & file_path)1693 int CTagLibHelper::GetWmaRating(const std::wstring& file_path)
1694 {
1695 int rate{};
1696 ASF::File file(file_path.c_str());
1697 if (file.isValid())
1698 {
1699 ASF::Tag* tag = file.tag();
1700 auto rating_str = tag->rating();
1701 rate = _wtoi(rating_str.toWString().c_str());
1702 }
1703 return rate;
1704 }
1705
WriteMpegRating(const std::wstring & file_path,int rate)1706 bool CTagLibHelper::WriteMpegRating(const std::wstring& file_path, int rate)
1707 {
1708 MPEG::File file(file_path.c_str());
1709 auto id3v2 = file.ID3v2Tag();
1710 WriteId3v2Rating(id3v2, rate);
1711 int tags = MPEG::File::ID3v2;
1712 if (file.hasAPETag())
1713 tags |= MPEG::File::APE;
1714 bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version());
1715 return saved;
1716 }
1717
WriteFlacRating(const std::wstring & file_path,int rate)1718 bool CTagLibHelper::WriteFlacRating(const std::wstring& file_path, int rate)
1719 {
1720 FLAC::File file(file_path.c_str());
1721 if (file.isValid())
1722 {
1723 auto properties = file.properties();
1724 properties[STR_FLAC_RATING_TAG].clear();
1725 properties[STR_FLAC_RATING_TAG].append(std::to_wstring(rate).c_str());
1726 file.setProperties(properties);
1727 bool saved = file.save();
1728 return saved;
1729 }
1730 return false;
1731 }
1732
WriteWmaRating(const std::wstring & file_path,int rate)1733 bool CTagLibHelper::WriteWmaRating(const std::wstring& file_path, int rate)
1734 {
1735 ASF::File file(file_path.c_str());
1736 if (file.isValid())
1737 {
1738 auto tag = file.tag();
1739 tag->setRating(std::to_wstring(rate));
1740 bool saved = file.save();
1741 return saved;
1742 }
1743 return false;
1744 }
1745
GetWriteId3v2Version()1746 TagLib::ID3v2::Version CTagLibHelper::GetWriteId3v2Version()
1747 {
1748 return (m_write_id3v2_3 ? ID3v2::Version::v3 : ID3v2::Version::v4);
1749 }
1750