xref: /MusicPlayer2/MusicPlayer2/TagLibHelper.cpp (revision 7e0593209f5419de1dfdd8496d6e41f0d9dd9b48)
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编码的字符串按本地代码页处理
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 
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 
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 
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
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     size_t length = file.tellg();
120     file.seekg(0, file.beg);
121 
122     data.clear();
123     data.resize(static_cast<unsigned int>(length));
124 
125     file.read(data.data(), length);
126 
127     file.close();
128 }
129 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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>
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 
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中
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>(_wtoi(disc_number.substr(index + 1).c_str()));
381     }
382     song_info.disc_num = static_cast<BYTE>(_wtoi(disc_number.substr(0, index).c_str()));
383 }
384 
385 
386 //解析Windows资源管理器设置的分级信息
387 static int ParseAudioRating(int rate_raw)
388 {
389     //使用Windows资源管理器设置了分级后,POPM字段的内容为以下格式:
390     //Windows Media Player 9 Series rating=196 counter=0
391     //其中rating后面的数字为分级,rating与分级的对应关系如下所示
392     /*
393       rating   |    分级
394       ---------|------------
395         255    |     5
396         196    |     4
397         128    |     3
398         64     |     2
399         1      |     1
400     */
401 
402     //根据分级转换成1~5星
403     if (rate_raw == 1)
404         return 1;
405     else if (rate_raw <= 64)
406         return 2;
407     else if (rate_raw <= 128)
408         return 3;
409     else if (rate_raw <= 196)
410         return 4;
411     else if (rate_raw <= 255)
412         return 5;
413     return 0;
414 }
415 
416 static int GenerateAudioRating(int rate)
417 {
418     switch (rate)
419     {
420     case 1:
421         return 1;
422     case 2:
423         return 64;
424     case 3:
425         return 128;
426     case 4:
427         return 196;
428     case 5:
429         return 255;
430     default:
431         return 0;
432     }
433 }
434 
435 static int GetId3v2Rating(ID3v2::Tag* id3v2)
436 {
437     if (id3v2 != nullptr)
438     {
439         auto frame_list_map = id3v2->frameListMap();
440         auto rate_frame = frame_list_map[STR_ID3V2_RATEING_TAG];
441         if (!rate_frame.isEmpty())
442         {
443             ID3v2::PopularimeterFrame* pFrame = dynamic_cast<ID3v2::PopularimeterFrame*>(rate_frame.front());
444             if (pFrame != nullptr)
445             {
446                 int rate_raw = pFrame->rating();
447                 return ParseAudioRating(rate_raw);
448             }
449         }
450     }
451     return 0;
452 }
453 
454 static void WriteId3v2Rating(ID3v2::Tag* id3v2, int rate)
455 {
456     if (id3v2 != nullptr)
457     {
458         auto frameListMap = id3v2->frameListMap();
459 
460         //先删除POPM帧
461         auto rate_frame_list = id3v2->frameListMap()[STR_ID3V2_RATEING_TAG];
462         if (!rate_frame_list.isEmpty())
463         {
464             for (auto frame : rate_frame_list)
465                 id3v2->removeFrame(frame);
466         }
467 
468         if (rate >= 1 && rate <= 5)
469         {
470             ID3v2::PopularimeterFrame* rate_frame = new ID3v2::PopularimeterFrame();
471             int rate_raw = GenerateAudioRating(rate);
472             rate_frame->setRating(rate_raw);
473             id3v2->addFrame(rate_frame);
474         }
475     }
476 }
477 
478 static void getFlacPropertyMap(FLAC::File& file, std::map<std::wstring, std::wstring>& property_map)
479 {
480     if (file.hasXiphComment())
481         GetTagPropertyMap(file.xiphComment(), property_map);
482     if (file.hasID3v2Tag())
483         GetTagPropertyMap(file.ID3v2Tag(), property_map);
484     if (file.hasID3v1Tag())
485         GetTagPropertyMap(file.ID3v1Tag(), property_map);
486 }
487 
488 static void getM4aPropertyMap(MP4::File& file, std::map<std::wstring, std::wstring>& property_map)
489 {
490     auto tag = file.tag();
491     GetTagPropertyMap(tag, property_map);
492 }
493 
494 static void getMpegPropertyMap(MPEG::File& file, std::map<std::wstring, std::wstring>& property_map)
495 {
496     if (file.hasID3v2Tag())
497         GetTagPropertyMap(file.ID3v2Tag(), property_map);
498     if (file.hasAPETag())
499         GetTagPropertyMap(file.APETag(), property_map);
500     if (file.hasID3v1Tag())
501         GetTagPropertyMap(file.ID3v1Tag(), property_map);
502 }
503 
504 static void getAsfPropertyMap(ASF::File& file, std::map<std::wstring, std::wstring>& property_map)
505 {
506     auto tag = file.tag();
507     GetTagPropertyMap(tag, property_map);
508 }
509 
510 static void getApePropertyMap(APE::File& file, std::map<std::wstring, std::wstring>& property_map)
511 {
512     if (file.hasAPETag())
513         GetTagPropertyMap(file.APETag(), property_map);
514     if (file.hasID3v1Tag())
515         GetTagPropertyMap(file.ID3v1Tag(), property_map);
516 }
517 
518 static void getWavPropertyMap(RIFF::WAV::File& file, std::map<std::wstring, std::wstring>& property_map)
519 {
520     if (file.hasID3v2Tag())
521         GetTagPropertyMap(file.ID3v2Tag(), property_map);
522     if (file.hasInfoTag())
523         GetTagPropertyMap(file.InfoTag(), property_map);
524 }
525 
526 static void getOggPropertyMap(Vorbis::File& file, std::map<std::wstring, std::wstring>& property_map)
527 {
528     auto tag = file.tag();
529     GetTagPropertyMap(tag, property_map);
530 }
531 
532 static void getMpcPropertyMap(MPC::File& file, std::map<std::wstring, std::wstring>& property_map)
533 {
534     if (file.hasAPETag())
535         GetTagPropertyMap(file.APETag(), property_map);
536     if (file.hasID3v1Tag())
537         GetTagPropertyMap(file.ID3v1Tag(), property_map);
538 }
539 
540 static void getOpusPropertyMap(Ogg::Opus::File& file, std::map<std::wstring, std::wstring>& property_map)
541 {
542     auto tag = file.tag();
543     GetTagPropertyMap(tag, property_map);
544 }
545 
546 static void getWavPackPropertyMap(WavPack::File& file, std::map<std::wstring, std::wstring>& property_map)
547 {
548     if (file.hasAPETag())
549         GetTagPropertyMap(file.APETag(), property_map);
550     if (file.hasID3v1Tag())
551         GetTagPropertyMap(file.ID3v1Tag(), property_map);
552 }
553 
554 static void getTtaPropertyMap(TrueAudio::File& file, std::map<std::wstring, std::wstring>& property_map)
555 {
556     if (file.hasID3v2Tag())
557         GetTagPropertyMap(file.ID3v2Tag(), property_map);
558     if (file.hasID3v1Tag())
559         GetTagPropertyMap(file.ID3v1Tag(), property_map);
560 }
561 
562 static void getAiffPropertyMap(RIFF::AIFF::File& file, std::map<std::wstring, std::wstring>& property_map)
563 {
564     auto tag = file.tag();
565     GetTagPropertyMap(tag, property_map);
566 }
567 
568 static void getSpxPropertyMap(Ogg::Speex::File& file, std::map<std::wstring, std::wstring>& property_map)
569 {
570     auto tag = file.tag();
571     GetTagPropertyMap(tag, property_map);
572 }
573 
574 static void getAnyFilePropertyMap(FileRef& file, std::map<std::wstring, std::wstring>& property_map)
575 {
576     auto tag = file.tag();
577     GetTagPropertyMap(tag, property_map);
578 }
579 
580 
581 ///////////////////////////////////////////////////////////////////////////////////
582 ///////////////////////////////////////////////////////////////////////////////////
583 ///////////////////////////////////////////////////////////////////////////////////
584 
585 bool CTagLibHelper::m_write_id3v2_3{ false };
586 
587 CTagLibHelper::CTagLibHelper()
588 {
589 }
590 
591 CTagLibHelper::~CTagLibHelper()
592 {
593 }
594 
595 void CTagLibHelper::SetWriteId3V2_3(bool write_id3v2_3)
596 {
597     m_write_id3v2_3 = write_id3v2_3;
598 }
599 
600 string CTagLibHelper::GetM4aAlbumCover(const std::wstring& file_path, int& type)
601 {
602     string cover_contents;
603     MP4::File file(file_path.c_str());
604     auto tag = file.tag();
605     if (tag != nullptr)
606     {
607         auto cover_item = tag->item(STR_MP4_COVER_TAG).toCoverArtList();
608         if (!cover_item.isEmpty())
609         {
610             const auto& pic_data = cover_item.front().data();
611             //获取专辑封面
612             cover_contents.assign(pic_data.data(), pic_data.size());
613 
614             //获取封面格式
615             switch (cover_item.front().format())
616             {
617             case MP4::CoverArt::JPEG:
618                 type = 0;
619                 break;
620             case MP4::CoverArt::PNG:
621                 type = 1;
622                 break;
623             case MP4::CoverArt::BMP:
624                 type = 3;
625                 break;
626             case MP4::CoverArt::GIF:
627                 type = 2;
628                 break;
629             default:
630                 type = -1;
631                 break;
632             }
633         }
634     }
635     return cover_contents;
636 }
637 
638 string CTagLibHelper::GetFlacAlbumCover(const std::wstring& file_path, int& type)
639 {
640     string cover_contents;
641     FLAC::File file(file_path.c_str());
642     const auto& cover_list = file.pictureList();
643     if (!cover_list.isEmpty())
644     {
645         auto pic = cover_list.front();
646         if (pic != nullptr)
647         {
648             const auto& pic_data = pic->data();
649             //获取专辑封面
650             cover_contents.assign(pic_data.data(), pic_data.size());
651 
652             std::wstring img_type = pic->mimeType().toCWString();
653             type = GetPicType(img_type);
654         }
655     }
656     return cover_contents;
657 }
658 
659 string CTagLibHelper::GetMp3AlbumCover(const std::wstring& file_path, int& type)
660 {
661     string cover_contents;
662     MPEG::File file(file_path.c_str());
663     auto id3v2 = file.ID3v2Tag();
664     GetId3v2AlbumCover(id3v2, cover_contents, type);
665     return cover_contents;
666 }
667 
668 string CTagLibHelper::GetAsfAlbumCover(const std::wstring& file_path, int& type)
669 {
670     string cover_contents;
671     ASF::File file(file_path.c_str());
672     auto tag = file.tag();
673     if (tag != nullptr)
674     {
675         ASF::AttributeList attr = tag->attribute("WM/Picture");
676         if (!attr.isEmpty())
677         {
678             ASF::Picture picture = attr.front().toPicture();
679             auto pic_data = picture.picture();
680             cover_contents.assign(pic_data.data(), pic_data.size());
681             std::wstring img_type = picture.mimeType().toCWString();
682             type = GetPicType(img_type);
683         }
684     }
685     return cover_contents;
686 }
687 
688 string CTagLibHelper::GetWavAlbumCover(const std::wstring& file_path, int& type)
689 {
690     string cover_contents;
691     RIFF::WAV::File file(file_path.c_str());
692     auto id3v2 = file.ID3v2Tag();
693     GetId3v2AlbumCover(id3v2, cover_contents, type);
694     return cover_contents;
695 }
696 
697 string CTagLibHelper::GetTtaAlbumCover(const std::wstring& file_path, int& type)
698 {
699     string cover_contents;
700     TrueAudio::File file(file_path.c_str());
701     auto id3v2 = file.ID3v2Tag();
702     GetId3v2AlbumCover(id3v2, cover_contents, type);
703     return cover_contents;
704 }
705 
706 string CTagLibHelper::GetApeAlbumCover(const std::wstring& file_path, int& type)
707 {
708     string cover_contents;
709     APE::File file(file_path.c_str());
710     auto tag = file.APETag();
711     GetApeTagAlbumCover(tag, cover_contents, type);
712     return cover_contents;
713 }
714 
715 
716 string CTagLibHelper::GetOggAlbumCover(const std::wstring& file_path, int& type)
717 {
718     string cover_contents;
719     Ogg::Vorbis::File file(file_path.c_str());
720     auto tag = file.tag();
721     if (tag != nullptr)
722     {
723         GetXiphCommentAlbumCover(tag, cover_contents, type);
724     }
725     return cover_contents;
726 }
727 
728 string CTagLibHelper::GetOpusAlbumCover(const std::wstring& file_path, int& type)
729 {
730     string cover_contents;
731     Ogg::Opus::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 
740 string CTagLibHelper::GetSpxAlbumCover(const std::wstring& file_path, int& type)
741 {
742     string cover_contents;
743     Ogg::Speex::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 
752 string CTagLibHelper::GetAiffAlbumCover(const std::wstring& file_path, int& type)
753 {
754     string cover_contents;
755     RIFF::AIFF::File file(file_path.c_str());
756     auto id3v2 = file.tag();
757     GetId3v2AlbumCover(id3v2, cover_contents, type);
758     return cover_contents;
759 
760 }
761 
762 string CTagLibHelper::GetMpcAlbumCover(const std::wstring& file_path, int& type)
763 {
764     string cover_contents;
765     MPC::File file(file_path.c_str());
766     auto ape_tag = file.APETag();
767     GetApeTagAlbumCover(ape_tag, cover_contents, type);
768     return cover_contents;
769 }
770 
771 string CTagLibHelper::GetWavePackAlbumCover(const std::wstring& file_path, int& type)
772 {
773     string cover_contents;
774     WavPack::File file(file_path.c_str());
775     auto ape_tag = file.APETag();
776     GetApeTagAlbumCover(ape_tag, cover_contents, type);
777     return cover_contents;
778 }
779 
780 void CTagLibHelper::GetFlacTagInfo(SongInfo& song_info)
781 {
782     FLAC::File file(song_info.file_path.c_str());
783     if (file.hasID3v1Tag())
784         song_info.tag_type |= T_ID3V1;
785     if (file.hasID3v2Tag())
786         song_info.tag_type |= T_ID3V2;
787     auto tag = file.tag();
788     if (tag != nullptr)
789     {
790         TagToSongInfo(song_info, tag, true);
791     }
792     std::map<std::wstring, std::wstring> property_map;
793     getFlacPropertyMap(file, property_map);
794     OtherPropertyToSongInfo(song_info, property_map);
795 }
796 
797 void CTagLibHelper::GetM4aTagInfo(SongInfo& song_info)
798 {
799     MP4::File file(song_info.file_path.c_str());
800     if (file.hasMP4Tag())
801         song_info.tag_type |= T_MP4;
802     auto tag = file.tag();
803     if (tag != nullptr)
804     {
805         TagToSongInfo(song_info, tag, false);
806     }
807     std::map<std::wstring, std::wstring> property_map;
808     getM4aPropertyMap(file, property_map);
809     OtherPropertyToSongInfo(song_info, property_map);
810 }
811 
812 void CTagLibHelper::GetMpegTagInfo(SongInfo& song_info)
813 {
814     MPEG::File file(song_info.file_path.c_str());
815     if (file.hasID3v1Tag())
816         song_info.tag_type |= T_ID3V1;
817     if (file.hasID3v2Tag())
818         song_info.tag_type |= T_ID3V2;
819     if (file.hasAPETag())
820         song_info.tag_type |= T_APE;
821 
822     auto tag = file.tag();
823     if (tag != nullptr)
824     {
825         TagToSongInfo(song_info, tag, true);
826     }
827     std::map<std::wstring, std::wstring> property_map;
828     getMpegPropertyMap(file, property_map);
829     OtherPropertyToSongInfo(song_info, property_map);
830 }
831 
832 void CTagLibHelper::GetAsfTagInfo(SongInfo& song_info)
833 {
834     ASF::File file(song_info.file_path.c_str());
835     auto tag = file.tag();
836     if (tag != nullptr)
837     {
838         TagToSongInfo(song_info, tag, false);
839     }
840     std::map<std::wstring, std::wstring> property_map;
841     getAsfPropertyMap(file, property_map);
842     OtherPropertyToSongInfo(song_info, property_map);
843 }
844 
845 void CTagLibHelper::GetApeTagInfo(SongInfo& song_info)
846 {
847     APE::File file(song_info.file_path.c_str());
848     if (file.hasID3v1Tag())
849         song_info.tag_type |= T_ID3V1;
850     if (file.hasAPETag())
851         song_info.tag_type |= T_APE;
852 
853     auto tag = file.tag();
854     if (tag != nullptr)
855     {
856         TagToSongInfo(song_info, tag, true);
857     }
858     std::map<std::wstring, std::wstring> property_map;
859     getApePropertyMap(file, property_map);
860     OtherPropertyToSongInfo(song_info, property_map);
861 }
862 
863 void CTagLibHelper::GetWavTagInfo(SongInfo& song_info)
864 {
865     RIFF::WAV::File file(song_info.file_path.c_str());
866     if (file.hasID3v2Tag())
867         song_info.tag_type |= T_ID3V2;
868     if (file.hasInfoTag())
869         song_info.tag_type |= T_RIFF;
870     auto tag = file.tag();
871     if (tag != nullptr)
872     {
873         TagToSongInfo(song_info, tag, false);
874     }
875     std::map<std::wstring, std::wstring> property_map;
876     getWavPropertyMap(file, property_map);
877     OtherPropertyToSongInfo(song_info, property_map);
878 }
879 
880 void CTagLibHelper::GetOggTagInfo(SongInfo& song_info)
881 {
882     Vorbis::File file(song_info.file_path.c_str());
883     auto tag = file.tag();
884     if (tag != nullptr)
885     {
886         TagToSongInfo(song_info, tag, false);
887     }
888     std::map<std::wstring, std::wstring> property_map;
889     getOggPropertyMap(file, property_map);
890     OtherPropertyToSongInfo(song_info, property_map);
891 }
892 
893 void CTagLibHelper::GetMpcTagInfo(SongInfo& song_info)
894 {
895     MPC::File file(song_info.file_path.c_str());
896     if (file.hasAPETag())
897         song_info.tag_type |= T_APE;
898     if (file.hasID3v1Tag())
899         song_info.tag_type |= T_ID3V1;
900     auto tag = file.tag();
901     if (tag != nullptr)
902     {
903         TagToSongInfo(song_info, tag, true);
904     }
905     std::map<std::wstring, std::wstring> property_map;
906     getMpcPropertyMap(file, property_map);
907     OtherPropertyToSongInfo(song_info, property_map);
908 }
909 
910 void CTagLibHelper::GetOpusTagInfo(SongInfo& song_info)
911 {
912     Ogg::Opus::File file(song_info.file_path.c_str());
913     auto tag = file.tag();
914     if (tag != nullptr)
915     {
916         TagToSongInfo(song_info, tag, false);
917     }
918     std::map<std::wstring, std::wstring> property_map;
919     getOpusPropertyMap(file, property_map);
920     OtherPropertyToSongInfo(song_info, property_map);
921 }
922 
923 void CTagLibHelper::GetWavPackTagInfo(SongInfo& song_info)
924 {
925     WavPack::File file(song_info.file_path.c_str());
926     if (file.hasAPETag())
927         song_info.tag_type |= T_APE;
928     if (file.hasID3v1Tag())
929         song_info.tag_type |= T_ID3V1;
930     auto tag = file.tag();
931     if (tag != nullptr)
932     {
933         TagToSongInfo(song_info, tag, true);
934     }
935     std::map<std::wstring, std::wstring> property_map;
936     getWavPackPropertyMap(file, property_map);
937     OtherPropertyToSongInfo(song_info, property_map);
938 }
939 
940 void CTagLibHelper::GetTtaTagInfo(SongInfo& song_info)
941 {
942     TrueAudio::File file(song_info.file_path.c_str());
943     if (file.hasID3v1Tag())
944         song_info.tag_type |= T_ID3V1;
945     if (file.hasID3v2Tag())
946         song_info.tag_type |= T_ID3V2;
947     auto tag = file.tag();
948     if (tag != nullptr)
949     {
950         TagToSongInfo(song_info, tag, true);
951     }
952     std::map<std::wstring, std::wstring> property_map;
953     getTtaPropertyMap(file, property_map);
954     OtherPropertyToSongInfo(song_info, property_map);
955 }
956 
957 void CTagLibHelper::GetAiffTagInfo(SongInfo& song_info)
958 {
959     RIFF::AIFF::File file(song_info.file_path.c_str());
960     if (file.hasID3v2Tag())
961         song_info.tag_type |= T_ID3V2;
962     auto tag = file.tag();
963     if (tag != nullptr)
964     {
965         TagToSongInfo(song_info, tag, false);
966     }
967     std::map<std::wstring, std::wstring> property_map;
968     getAiffPropertyMap(file, property_map);
969     OtherPropertyToSongInfo(song_info, property_map);
970 }
971 
972 void CTagLibHelper::GetSpxTagInfo(SongInfo& song_info)
973 {
974     Ogg::Speex::File file(song_info.file_path.c_str());
975     auto tag = file.tag();
976     if (tag != nullptr)
977     {
978         TagToSongInfo(song_info, tag, false);
979     }
980     std::map<std::wstring, std::wstring> property_map;
981     getSpxPropertyMap(file, property_map);
982     OtherPropertyToSongInfo(song_info, property_map);
983 }
984 
985 void CTagLibHelper::GetAnyFileTagInfo(SongInfo& song_info)
986 {
987     FileRef file(song_info.file_path.c_str());
988     auto tag = file.tag();
989     if (tag != nullptr)
990     {
991         TagToSongInfo(song_info, tag, false);
992     }
993     std::map<std::wstring, std::wstring> property_map;
994     getAnyFilePropertyMap(file, property_map);
995     OtherPropertyToSongInfo(song_info, property_map);
996 }
997 
998 void CTagLibHelper::GetFlacPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
999 {
1000     FLAC::File file(file_path.c_str());
1001     getFlacPropertyMap(file, property_map);
1002 }
1003 
1004 void CTagLibHelper::GetM4aPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1005 {
1006     MP4::File file(file_path.c_str());
1007     getM4aPropertyMap(file, property_map);
1008 }
1009 
1010 void CTagLibHelper::GetMpegPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1011 {
1012     MPEG::File file(file_path.c_str());
1013     getMpegPropertyMap(file, property_map);
1014 }
1015 
1016 void CTagLibHelper::GetAsfPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1017 {
1018     ASF::File file(file_path.c_str());
1019     getAsfPropertyMap(file, property_map);
1020 }
1021 
1022 void CTagLibHelper::GetApePropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1023 {
1024     APE::File file(file_path.c_str());
1025     getApePropertyMap(file, property_map);
1026 }
1027 
1028 void CTagLibHelper::GetWavPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1029 {
1030     RIFF::WAV::File file(file_path.c_str());
1031     getWavPropertyMap(file, property_map);
1032 }
1033 
1034 void CTagLibHelper::GetOggPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1035 {
1036     Vorbis::File file(file_path.c_str());
1037     getOggPropertyMap(file, property_map);
1038 }
1039 
1040 void CTagLibHelper::GetMpcPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1041 {
1042     MPC::File file(file_path.c_str());
1043     getMpcPropertyMap(file, property_map);
1044 }
1045 
1046 void CTagLibHelper::GetOpusPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1047 {
1048     Ogg::Opus::File file(file_path.c_str());
1049     getOpusPropertyMap(file, property_map);
1050 }
1051 
1052 void CTagLibHelper::GetWavPackPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1053 {
1054     WavPack::File file(file_path.c_str());
1055     getWavPackPropertyMap(file, property_map);
1056 }
1057 
1058 void CTagLibHelper::GetTtaPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1059 {
1060     TrueAudio::File file(file_path.c_str());
1061     getTtaPropertyMap(file, property_map);
1062 }
1063 
1064 void CTagLibHelper::GetAiffPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1065 {
1066     RIFF::AIFF::File file(file_path.c_str());
1067     getAiffPropertyMap(file, property_map);
1068 }
1069 
1070 void CTagLibHelper::GetSpxPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1071 {
1072     Ogg::Speex::File file(file_path.c_str());
1073     getSpxPropertyMap(file, property_map);
1074 }
1075 
1076 void CTagLibHelper::GetAnyFilePropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map)
1077 {
1078     FileRef file(file_path.c_str());
1079     getAnyFilePropertyMap(file, property_map);
1080 }
1081 
1082 std::wstring CTagLibHelper::GetMpegLyric(const std::wstring& file_path)
1083 {
1084     MPEG::File file(file_path.c_str());
1085     auto id3v2 = file.ID3v2Tag();
1086     return GetId3v2Lyric(id3v2);
1087 }
1088 
1089 std::wstring CTagLibHelper::GetM4aLyric(const std::wstring& file_path)
1090 {
1091     std::wstring lyrics;
1092     MP4::File file(file_path.c_str());
1093     auto tag = file.tag();
1094     if (tag != nullptr)
1095     {
1096         auto item_map = file.tag()->itemMap();
1097         auto lyric_item = item_map[STR_MP4_LYRICS_TAG].toStringList();;
1098         if (!lyric_item.isEmpty())
1099             lyrics = lyric_item.front().toWString();
1100     }
1101     return lyrics;
1102 }
1103 
1104 std::wstring CTagLibHelper::GetFlacLyric(const std::wstring& file_path)
1105 {
1106     std::wstring lyrics;
1107     FLAC::File file(file_path.c_str());
1108     auto properties = file.properties();
1109     if (file.isValid())
1110     {
1111         auto lyric_item = properties[STR_FLAC_LYRIC_TAG];
1112         if (!lyric_item.isEmpty())
1113         {
1114             lyrics = lyric_item.front().toWString();
1115         }
1116     }
1117     return lyrics;
1118 }
1119 
1120 std::wstring CTagLibHelper::GetAsfLyric(const std::wstring& file_path)
1121 {
1122     std::wstring lyrics;
1123     ASF::File file(file_path.c_str());
1124     if (file.isValid())
1125     {
1126         auto properties = file.properties();
1127         auto lyric_item = properties[STR_ASF_LYRIC_TAG];
1128         if (!lyric_item.isEmpty())
1129         {
1130             lyrics = lyric_item.front().toWString();
1131         }
1132     }
1133     return lyrics;
1134 }
1135 
1136 
1137 std::wstring CTagLibHelper::GetWavLyric(const std::wstring& file_path)
1138 {
1139     RIFF::WAV::File file(file_path.c_str());
1140     auto id3v2 = file.ID3v2Tag();
1141     return GetId3v2Lyric(id3v2);
1142 
1143 }
1144 
1145 bool CTagLibHelper::WriteMpegLyric(const std::wstring& file_path, const std::wstring& lyric_contents)
1146 {
1147     std::wstring lyrics;
1148     MPEG::File file(file_path.c_str());
1149     auto id3v2 = file.ID3v2Tag();
1150     WriteId3v2Lyric(id3v2, lyric_contents);
1151     int tags = MPEG::File::ID3v2;
1152     if (file.hasAPETag())
1153         tags |= MPEG::File::APE;
1154     bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version());
1155     return saved;
1156 }
1157 
1158 bool CTagLibHelper::WriteFlacLyric(const std::wstring& file_path, const std::wstring& lyric_contents)
1159 {
1160     FLAC::File file(file_path.c_str());
1161     if (file.isValid())
1162     {
1163         auto properties = file.properties();
1164         if (lyric_contents.empty())
1165         {
1166             properties.erase(STR_FLAC_LYRIC_TAG);
1167         }
1168         else
1169         {
1170             StringList lyric_item;
1171             lyric_item.append(lyric_contents);
1172             properties[STR_FLAC_LYRIC_TAG] = lyric_item;
1173         }
1174         file.setProperties(properties);
1175         bool saved = file.save();
1176         return saved;
1177     }
1178     return false;
1179 }
1180 
1181 bool CTagLibHelper::WriteM4aLyric(const std::wstring& file_path, const std::wstring& lyric_contents)
1182 {
1183     MP4::File file(file_path.c_str());
1184     auto tag = file.tag();
1185     if (tag != nullptr)
1186     {
1187         if (lyric_contents.empty())
1188         {
1189             tag->removeItem(STR_MP4_LYRICS_TAG);
1190         }
1191         else
1192         {
1193             StringList lyric_list;
1194             lyric_list.append(lyric_contents);
1195             MP4::Item lyrics_item(lyric_list);
1196             tag->setItem(STR_MP4_LYRICS_TAG, lyrics_item);
1197         }
1198         bool saved = file.save();
1199         return saved;
1200     }
1201     return false;
1202 }
1203 
1204 bool CTagLibHelper::WriteAsfLyric(const std::wstring& file_path, const std::wstring& lyric_contents)
1205 {
1206     ASF::File file(file_path.c_str());
1207     if (file.isValid())
1208     {
1209         auto properties = file.properties();
1210         if (lyric_contents.empty())
1211         {
1212             properties.erase(STR_ASF_LYRIC_TAG);
1213         }
1214         else
1215         {
1216             StringList lyric_item;
1217             lyric_item.append(lyric_contents);
1218             properties[STR_ASF_LYRIC_TAG] = lyric_item;
1219         }
1220         file.setProperties(properties);
1221         bool saved = file.save();
1222         return saved;
1223     }
1224     return false;
1225 }
1226 
1227 bool CTagLibHelper::WriteWavLyric(const std::wstring& file_path, const std::wstring& lyric_contents)
1228 {
1229     std::wstring lyrics;
1230     RIFF::WAV::File file(file_path.c_str());
1231     auto id3v2 = file.ID3v2Tag();
1232     WriteId3v2Lyric(id3v2, lyric_contents);
1233     bool saved = file.save(RIFF::WAV::File::TagTypes::AllTags, File::StripOthers, GetWriteId3v2Version());
1234     return saved;
1235 }
1236 
1237 bool CTagLibHelper::WriteMp3AlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist)
1238 {
1239     MPEG::File file(file_path.c_str());
1240     if (!file.isValid())
1241         return false;
1242 
1243     //先删除专辑封面
1244     if (remove_exist)
1245     {
1246         auto id3v2tag = file.ID3v2Tag();
1247         DeleteId3v2AlbumCover(id3v2tag);
1248     }
1249     if (!album_cover_path.empty())
1250     {
1251         auto id3v2tag = file.ID3v2Tag(true);
1252         WriteId3v2AlbumCover(id3v2tag, album_cover_path);
1253     }
1254     int tags = MPEG::File::ID3v2;
1255     if (file.hasAPETag())
1256         tags |= MPEG::File::APE;
1257     bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version());
1258     return saved;
1259 }
1260 
1261 bool CTagLibHelper::WriteFlacAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist)
1262 {
1263     FLAC::File file(file_path.c_str());
1264     if (!file.isValid())
1265         return false;
1266 
1267     //先删除专辑封面
1268     if (remove_exist)
1269     {
1270         file.removePictures();
1271     }
1272 
1273     if (!album_cover_path.empty())
1274     {
1275         ByteVector pic_data;
1276         FileToByteVector(pic_data, album_cover_path);
1277         FLAC::Picture* newpic = new FLAC::Picture();
1278         newpic->setType(FLAC::Picture::FrontCover);
1279         newpic->setData(pic_data);
1280         std::wstring ext = CFilePathHelper(album_cover_path).GetFileExtension();
1281         newpic->setMimeType(L"image/" + ext);
1282         file.addPicture(newpic);
1283     }
1284     bool saved = file.save();
1285     return saved;
1286 }
1287 
1288 bool CTagLibHelper::WriteM4aAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1289 {
1290     MP4::File file(file_path.c_str());
1291     if (!file.isValid())
1292         return false;
1293 
1294     auto tag = file.tag();
1295     if (tag == nullptr)
1296         return false;
1297 
1298     if (remove_exist)
1299     {
1300         if (tag->contains(STR_MP4_COVER_TAG))
1301         {
1302             tag->removeItem(STR_MP4_COVER_TAG);
1303         }
1304     }
1305 
1306     if (!album_cover_path.empty())
1307     {
1308         ByteVector pic_data;
1309         FileToByteVector(pic_data, album_cover_path);
1310         MP4::CoverArt::Format format = MP4::CoverArt::Format::Unknown;
1311         std::wstring ext = CFilePathHelper(album_cover_path).GetFileExtension();
1312         if (ext == L"jpg" || ext == L"jpeg")
1313             format = MP4::CoverArt::Format::JPEG;
1314         else if (ext == L"png")
1315             format = MP4::CoverArt::Format::PNG;
1316         else if (ext == L"gif")
1317             format = MP4::CoverArt::Format::GIF;
1318         else if (ext == L"bmp")
1319             format = MP4::CoverArt::Format::BMP;
1320         MP4::CoverArt cover_item(format, pic_data);
1321 
1322         auto cover_item_list = tag->item(STR_MP4_COVER_TAG).toCoverArtList();
1323         cover_item_list.append(cover_item);
1324         tag->setItem(STR_MP4_COVER_TAG, cover_item_list);
1325     }
1326     bool saved = file.save();
1327     return saved;
1328 }
1329 
1330 bool CTagLibHelper::WriteAsfAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1331 {
1332     ASF::File file(file_path.c_str());
1333     if (!file.isValid())
1334         return false;
1335 
1336     auto tag = file.tag();
1337     if (tag == nullptr)
1338         return false;
1339 
1340     if (remove_exist)
1341     {
1342         if (tag->contains(STR_ASF_COVER_TAG))
1343         {
1344             tag->removeItem(STR_ASF_COVER_TAG);
1345         }
1346     }
1347 
1348     if (!album_cover_path.empty())
1349     {
1350         ByteVector pic_data;
1351         FileToByteVector(pic_data, album_cover_path);
1352 
1353         ASF::Picture picture;
1354         std::wstring str_mine_type = L"image/" + CFilePathHelper(album_cover_path).GetFileExtension();
1355         picture.setMimeType(str_mine_type);
1356         picture.setType(ASF::Picture::FrontCover);
1357         picture.setPicture(pic_data);
1358         tag->setAttribute(STR_ASF_COVER_TAG, picture);
1359     }
1360     bool saved = file.save();
1361     return saved;
1362 }
1363 
1364 bool CTagLibHelper::WriteWavAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1365 {
1366     RIFF::WAV::File file(file_path.c_str());
1367     if (!file.isValid())
1368         return false;
1369 
1370     //先删除专辑封面
1371     auto id3v2tag = file.ID3v2Tag();
1372     if (remove_exist)
1373     {
1374         DeleteId3v2AlbumCover(id3v2tag);
1375     }
1376     if (!album_cover_path.empty())
1377     {
1378         WriteId3v2AlbumCover(id3v2tag, album_cover_path);
1379     }
1380     bool saved = file.save(RIFF::WAV::File::AllTags, File::StripOthers, GetWriteId3v2Version());
1381     return saved;
1382 }
1383 
1384 bool CTagLibHelper::WriteTtaAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1385 {
1386     TrueAudio::File file(file_path.c_str());
1387     if (!file.isValid())
1388         return false;
1389 
1390     if (remove_exist)
1391     {
1392         auto id3v2tag = file.ID3v2Tag();
1393         DeleteId3v2AlbumCover(id3v2tag);
1394     }
1395     if (!album_cover_path.empty())
1396     {
1397         auto id3v2tag = file.ID3v2Tag(true);
1398         WriteId3v2AlbumCover(id3v2tag, album_cover_path);
1399     }
1400     bool saved = file.save();
1401     return saved;
1402     return false;
1403 }
1404 
1405 bool CTagLibHelper::WriteApeAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1406 {
1407     APE::File file(file_path.c_str());
1408     if (!file.isValid())
1409         return false;
1410 
1411     auto tag = file.APETag(true);
1412     WriteApeTagAlbumCover(tag, album_cover_path, remove_exist);
1413     bool saved = file.save();
1414     return saved;
1415 }
1416 
1417 bool CTagLibHelper::WriteOggAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1418 {
1419     Ogg::Vorbis::File file(file_path.c_str());
1420     if (!file.isValid())
1421         return false;
1422 
1423     auto tag = file.tag();
1424     if (tag != nullptr)
1425     {
1426         WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist);
1427         bool saved = file.save();
1428         return saved;
1429     }
1430     return false;
1431 }
1432 
1433 bool CTagLibHelper::WriteOpusAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist)
1434 {
1435     Ogg::Opus::File file(file_path.c_str());
1436     if (!file.isValid())
1437         return false;
1438 
1439     auto tag = file.tag();
1440     if (tag != nullptr)
1441     {
1442         WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist);
1443         bool saved = file.save();
1444         return saved;
1445     }
1446     return false;
1447 }
1448 
1449 bool CTagLibHelper::WriteSpxAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1450 {
1451     Ogg::Speex::File file(file_path.c_str());
1452     if (!file.isValid())
1453         return false;
1454 
1455     auto tag = file.tag();
1456     if (tag != nullptr)
1457     {
1458         WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist);
1459         bool saved = file.save();
1460         return saved;
1461     }
1462     return false;
1463 }
1464 
1465 bool CTagLibHelper::WriteAiffAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1466 {
1467     RIFF::AIFF::File file(file_path.c_str());
1468     if (!file.isValid())
1469         return false;
1470 
1471     //先删除专辑封面
1472     auto id3v2tag = file.tag();
1473     if (remove_exist)
1474     {
1475         DeleteId3v2AlbumCover(id3v2tag);
1476     }
1477     if (!album_cover_path.empty())
1478     {
1479         WriteId3v2AlbumCover(id3v2tag, album_cover_path);
1480     }
1481     bool saved = file.save(GetWriteId3v2Version());
1482     return saved;
1483 }
1484 
1485 bool CTagLibHelper::WriteMpcAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1486 {
1487     MPC::File file(file_path.c_str());
1488     if (!file.isValid())
1489         return false;
1490 
1491     auto tag = file.APETag(true);
1492     WriteApeTagAlbumCover(tag, album_cover_path, remove_exist);
1493     bool saved = file.save();
1494     return saved;
1495 }
1496 
1497 bool CTagLibHelper::WriteWavePackAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/)
1498 {
1499     WavPack::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 
1509 bool CTagLibHelper::WriteMpegTag(const SongInfo& song_info)
1510 {
1511     MPEG::File file(song_info.file_path.c_str());
1512     auto tag = file.tag();
1513     SongInfoToTag(song_info, tag);
1514     int tags = MPEG::File::ID3v2;
1515     //if (file.hasID3v1Tag())
1516     //    tags |= MPEG::File::ID3v1;
1517     if (file.hasAPETag())
1518         tags |= MPEG::File::APE;
1519     bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version());
1520     return saved;
1521 }
1522 
1523 bool CTagLibHelper::WriteFlacTag(const SongInfo& song_info)
1524 {
1525     FLAC::File file(song_info.file_path.c_str());
1526     auto tag = file.tag();
1527     SongInfoToTag(song_info, tag);
1528     bool saved = file.save();
1529     return saved;
1530 }
1531 
1532 bool CTagLibHelper::WriteM4aTag(const SongInfo& song_info)
1533 {
1534     MP4::File file(song_info.file_path.c_str());
1535     auto tag = file.tag();
1536     SongInfoToTag(song_info, tag);
1537     bool saved = file.save();
1538     return saved;
1539 }
1540 
1541 bool CTagLibHelper::WriteWavTag(const SongInfo& song_info)
1542 {
1543     RIFF::WAV::File file(song_info.file_path.c_str());
1544     auto tag = file.tag();
1545     SongInfoToTag(song_info, tag);
1546     bool saved = file.save(RIFF::WAV::File::AllTags, File::StripOthers, GetWriteId3v2Version());
1547     return saved;
1548 }
1549 
1550 bool CTagLibHelper::WriteOggTag(const SongInfo& song_info)
1551 {
1552     Vorbis::File file(song_info.file_path.c_str());
1553     auto tag = file.tag();
1554     SongInfoToTag(song_info, tag);
1555     bool saved = file.save();
1556     return saved;
1557 }
1558 
1559 bool CTagLibHelper::WriteApeTag(const SongInfo& song_info)
1560 {
1561     APE::File file(song_info.file_path.c_str());
1562     auto tag = file.tag();
1563     SongInfoToTag(song_info, tag);
1564     bool saved = file.save();
1565     return saved;
1566 }
1567 
1568 bool CTagLibHelper::WriteMpcTag(const SongInfo& song_info)
1569 {
1570     MPC::File file(song_info.file_path.c_str());
1571     auto tag = file.tag();
1572     SongInfoToTag(song_info, tag);
1573     bool saved = file.save();
1574     return saved;
1575 }
1576 
1577 bool CTagLibHelper::WriteOpusTag(const SongInfo& song_info)
1578 {
1579     Ogg::Opus::File file(song_info.file_path.c_str());
1580     auto tag = file.tag();
1581     SongInfoToTag(song_info, tag);
1582     bool saved = file.save();
1583     return saved;
1584 }
1585 
1586 bool CTagLibHelper::WriteWavPackTag(const SongInfo& song_info)
1587 {
1588     WavPack::File file(song_info.file_path.c_str());
1589     auto tag = file.tag();
1590     SongInfoToTag(song_info, tag);
1591     bool saved = file.save();
1592     return saved;
1593 }
1594 
1595 bool CTagLibHelper::WriteTtaTag(const SongInfo& song_info)
1596 {
1597     TrueAudio::File file(song_info.file_path.c_str());
1598     auto tag = file.tag();
1599     SongInfoToTag(song_info, tag);
1600     bool saved = file.save();
1601     return saved;
1602 }
1603 
1604 bool CTagLibHelper::WriteAiffTag(const SongInfo& song_info)
1605 {
1606     RIFF::AIFF::File file(song_info.file_path.c_str());
1607     auto tag = file.tag();
1608     SongInfoToTag(song_info, tag);
1609     bool saved = file.save(GetWriteId3v2Version());
1610     return saved;
1611 }
1612 
1613 bool CTagLibHelper::WriteAsfTag(const SongInfo& song_info)
1614 {
1615     ASF::File file(song_info.file_path.c_str());
1616     auto tag = file.tag();
1617     SongInfoToTag(song_info, tag);
1618     bool saved = file.save();
1619     return saved;
1620 }
1621 
1622 bool CTagLibHelper::WriteSpxTag(const SongInfo& song_info)
1623 {
1624     Ogg::Speex::File file(song_info.file_path.c_str());
1625     auto tag = file.tag();
1626     SongInfoToTag(song_info, tag);
1627     bool saved = file.save();
1628     return saved;
1629 }
1630 
1631 std::wstring CTagLibHelper::GetApeCue(const std::wstring& file_path)
1632 {
1633     std::wstring cue_contents;
1634     APE::File file(file_path.c_str());
1635     auto tag = file.APETag();
1636     if (tag != nullptr)
1637     {
1638         auto item_list_map = tag->itemListMap();
1639         auto cue_item = item_list_map[STR_APE_CUE_TAG];
1640         cue_contents = cue_item.toString().toWString();
1641     }
1642     return cue_contents;
1643 }
1644 
1645 int CTagLibHelper::GetMepgRating(const std::wstring& file_path)
1646 {
1647     MPEG::File file(file_path.c_str());
1648     auto id3v2 = file.ID3v2Tag();
1649     return GetId3v2Rating(id3v2);
1650 }
1651 
1652 int CTagLibHelper::GetFlacRating(const std::wstring& file_path)
1653 {
1654     FLAC::File file(file_path.c_str());
1655     auto properties = file.properties();
1656     if (file.isValid())
1657     {
1658         auto rating_item = properties[STR_FLAC_RATING_TAG];
1659         if (!rating_item.isEmpty())
1660         {
1661             int rating = _wtoi(rating_item.front().toWString().c_str());
1662             return rating;
1663         }
1664     }
1665     return 0;
1666 
1667 }
1668 
1669 int CTagLibHelper::GetWmaRating(const std::wstring& file_path)
1670 {
1671     int rate{};
1672     ASF::File file(file_path.c_str());
1673     if (file.isValid())
1674     {
1675         ASF::Tag* tag = file.tag();
1676         auto rating_str = tag->rating();
1677         rate = _wtoi(rating_str.toWString().c_str());
1678     }
1679     return rate;
1680 }
1681 
1682 bool CTagLibHelper::WriteMpegRating(const std::wstring& file_path, int rate)
1683 {
1684     MPEG::File file(file_path.c_str());
1685     auto id3v2 = file.ID3v2Tag();
1686     WriteId3v2Rating(id3v2, rate);
1687     int tags = MPEG::File::ID3v2;
1688     if (file.hasAPETag())
1689         tags |= MPEG::File::APE;
1690     bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version());
1691     return saved;
1692 }
1693 
1694 bool CTagLibHelper::WriteFlacRating(const std::wstring& file_path, int rate)
1695 {
1696     FLAC::File file(file_path.c_str());
1697     if (file.isValid())
1698     {
1699         auto properties = file.properties();
1700         properties[STR_FLAC_RATING_TAG].clear();
1701         properties[STR_FLAC_RATING_TAG].append(std::to_wstring(rate).c_str());
1702         file.setProperties(properties);
1703         bool saved = file.save();
1704         return saved;
1705     }
1706     return false;
1707 }
1708 
1709 bool CTagLibHelper::WriteWmaRating(const std::wstring& file_path, int rate)
1710 {
1711     ASF::File file(file_path.c_str());
1712     if (file.isValid())
1713     {
1714         auto tag = file.tag();
1715         tag->setRating(std::to_wstring(rate));
1716         bool saved = file.save();
1717         return saved;
1718     }
1719     return false;
1720 }
1721 
1722 TagLib::ID3v2::Version CTagLibHelper::GetWriteId3v2Version()
1723 {
1724     return (m_write_id3v2_3 ? ID3v2::Version::v3 : ID3v2::Version::v4);
1725 }
1726