xref: /MusicPlayer2/MusicPlayer2/TagLibHelper.cpp (revision ea6fbf769fc4b78abeb767f3b2780951bc6463e0)
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/apefile.h"
13 #include "taglib/wavfile.h"
14 #include "taglib/mpcfile.h"
15 #include "taglib/opusfile.h"
16 #include "taglib/wavpackfile.h"
17 #include "taglib/vorbisfile.h"
18 #include "taglib/trueaudiofile.h"
19 #include "taglib/aifffile.h"
20 #include "taglib/asffile.h"
21 #include "taglib/tpropertymap.h"
22 #include "AudioCommon.h"
23 #include "taglib/apetag.h"
24 #include "taglib/fileref.h"
25 #include "taglib/speexfile.h"
26 
27 
28 using namespace TagLib;
29 
30 #define STR_MP4_COVER_TAG "covr"
31 #define STR_MP4_LYRICS_TAG "----:com.apple.iTunes:Lyrics"
32 #define STR_ASF_COVER_TAG "WM/Picture"
33 #define STR_APE_COVER_TAG "COVER ART (FRONT)"
34 
35 //��taglib�е��ַ���ת����wstring���͡�
36 //����taglib�����з�unicode����ȫ����ΪLatin���봦������޷���ȷ�����ش���ҳ
37 //���ォLatin������ַ��������ش���ҳ����
38 static wstring TagStringToWstring(const String& str, bool to_local)
39 {
40     wstring result;
41     if (to_local && str.isLatin1())
42         result = CCommon::StrToUnicode(str.to8Bit(), CodeType::ANSI);
43     else
44         result = str.toWString();
45     return result;
46 }
47 
48 static void SongInfoToTag(const SongInfo& song_info, Tag* tag)
49 {
50     if (tag != nullptr)
51     {
52         tag->setTitle(song_info.title);
53         tag->setArtist(song_info.artist);
54         tag->setAlbum(song_info.album);
55         tag->setGenre(song_info.genre);
56         tag->setTrack(song_info.track);
57         tag->setComment(song_info.comment);
58         tag->setYear(_wtoi(song_info.year.c_str()));
59     }
60 }
61 
62 static bool IsStringNumber(wstring str, int num)
63 {
64     if (!str.empty() && str.front() == L'(')
65         str = str.substr(1);
66     if (!str.empty() && str.back() == L')')
67         str.pop_back();
68     if (CCommon::StrIsNumber(str))
69     {
70         num = _wtoi(str.c_str());
71         return true;
72     }
73     return false;
74 }
75 
76 static void TagToSongInfo(SongInfo& song_info, Tag* tag, bool to_local)
77 {
78     if (tag != nullptr)
79     {
80         song_info.title = TagStringToWstring(tag->title(), to_local);
81         song_info.artist = TagStringToWstring(tag->artist(), to_local);
82         song_info.album = TagStringToWstring(tag->album(), to_local);
83         song_info.genre = TagStringToWstring(tag->genre(), to_local);
84         int genre_num{};
85         if (IsStringNumber(song_info.genre, genre_num))
86         {
87             song_info.genre = CAudioCommon::GetGenre(static_cast<BYTE>(genre_num));
88         }
89 
90         unsigned int year = tag->year();
91         song_info.year = (year == 0 ? L"" : std::to_wstring(year));
92         song_info.track = tag->track();
93         song_info.comment = TagStringToWstring(tag->comment(), to_local);
94     }
95 }
96 
97 //���ļ����ݶ�ȡ��ByteVector
98 static void FileToByteVector(ByteVector& data, const std::wstring& file_path)
99 {
100     std::ifstream file{ file_path, std::ios::binary | std::ios::in };
101     if (file.fail())
102         return;
103 
104     //��ȡ�ļ�����
105     file.seekg(0, file.end);
106     size_t length = file.tellg();
107     file.seekg(0, file.beg);
108 
109     data.clear();
110     data.resize(static_cast<unsigned int>(length));
111 
112     file.read(data.data(), length);
113 
114     file.close();
115 }
116 
117 int GetPicType(const wstring& mimeType)
118 {
119     int type{ -1 };
120     if (mimeType == L"image/jpeg" || mimeType == L"image/jpg")
121         type = 0;
122     else if (mimeType == L"image/png")
123         type = 1;
124     else if (mimeType == L"image/gif")
125         type = 2;
126     else if (mimeType == L"image/bmp")
127         type = 3;
128     else
129         type = -1;
130     return type;
131 }
132 
133 static void GetId3v2AlbumCover(ID3v2::Tag* id3v2, string& cover_contents, int& type)
134 {
135     if (id3v2 != nullptr)
136     {
137         auto pic_frame_list = id3v2->frameListMap()["APIC"];
138         if (!pic_frame_list.isEmpty())
139         {
140             ID3v2::AttachedPictureFrame *frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(pic_frame_list.front());
141             if (frame != nullptr)
142             {
143                 auto pic_data = frame->picture();
144                 //��ȡר������
145                 cover_contents.assign(pic_data.data(), pic_data.size());
146                 wstring img_type = frame->mimeType().toCWString();
147                 type = GetPicType(img_type);
148             }
149         }
150     }
151 }
152 
153 static void DeleteId3v2AlbumCover(ID3v2::Tag* id3v2tag)
154 {
155     if (id3v2tag != nullptr)
156     {
157         auto pic_frame_list = id3v2tag->frameListMap()["APIC"];
158         if (!pic_frame_list.isEmpty())
159         {
160             for (auto frame : pic_frame_list)
161                 id3v2tag->removeFrame(frame);
162         }
163     }
164 }
165 
166 static void WriteId3v2AlbumCover(ID3v2::Tag* id3v2tag, const wstring& album_cover_path)
167 {
168     if (id3v2tag != nullptr)
169     {
170         //��ȡͼƬ�ļ�
171         ByteVector pic_data;
172         FileToByteVector(pic_data, album_cover_path);
173         //����Ƶ�ļ�д��ͼƬ�ļ�
174         ID3v2::AttachedPictureFrame* pic_frame = new ID3v2::AttachedPictureFrame();
175         pic_frame->setPicture(pic_data);
176         pic_frame->setType(ID3v2::AttachedPictureFrame::FrontCover);
177         wstring ext = CFilePathHelper(album_cover_path).GetFileExtension();
178         pic_frame->setMimeType(L"image/" + ext);
179         id3v2tag->addFrame(pic_frame);
180     }
181 }
182 
183 
184 static void GetApeTagAlbumCover(APE::Tag* tag, string& cover_contents, int& type)
185 {
186     if (tag != nullptr)
187     {
188         auto item_list_map = tag->itemListMap();
189         auto pic_item = item_list_map[STR_APE_COVER_TAG];
190         auto pic_data = pic_item.binaryData();
191         if (!pic_data.isEmpty())
192         {
193             cover_contents.assign(pic_data.data(), pic_data.size());
194 
195             size_t index{};
196             index = cover_contents.find('\0');
197             std::string pic_desc;
198             if (index != std::string::npos)
199             {
200                 pic_desc = cover_contents.substr(0, index);
201                 cover_contents = cover_contents.substr(index + 1);
202             }
203 
204             if (!pic_desc.empty())
205             {
206                 std::string img_type;
207                 index = pic_desc.rfind('.');
208                 if (index != std::string::npos && index < pic_desc.size() - 1)
209                 {
210                     img_type = pic_desc.substr(index + 1);
211                     img_type = "image/" + img_type;
212                     type = GetPicType(CCommon::ASCIIToUnicode(img_type));
213                 }
214             }
215         }
216     }
217 }
218 
219 static void WriteApeTagAlbumCover(APE::Tag* tag, const wstring &album_cover_path, bool remove_exist)
220 {
221     if (remove_exist)
222     {
223         tag->removeItem(STR_APE_COVER_TAG);
224     }
225 
226     if (!album_cover_path.empty())
227     {
228         ByteVector pic_data;
229         FileToByteVector(pic_data, album_cover_path);
230 
231         ByteVector pic_item_data;
232         pic_item_data = "Cover Art (Front).";
233         wstring file_type = CFilePathHelper(album_cover_path).GetFileExtension();
234         for (wchar_t ch : file_type)
235             pic_item_data.append(static_cast<char>(ch));
236         pic_item_data.append('\0');
237         pic_item_data.append(pic_data);
238 
239         APE::Item pic_item(STR_APE_COVER_TAG, pic_item_data, true);
240         tag->setItem(STR_APE_COVER_TAG, pic_item);
241     }
242 }
243 
244 static void WriteXiphCommentAlbumCover(Ogg::XiphComment * tag, const wstring &album_cover_path, bool remove_exist)
245 {
246     //��ɾ��ר������
247     if (remove_exist)
248     {
249         tag->removeAllPictures();
250     }
251 
252     if (!album_cover_path.empty())
253     {
254         ByteVector pic_data;
255         FileToByteVector(pic_data, album_cover_path);
256         FLAC::Picture *newpic = new FLAC::Picture();
257         newpic->setType(FLAC::Picture::FrontCover);
258         newpic->setData(pic_data);
259         wstring ext = CFilePathHelper(album_cover_path).GetFileExtension();
260         newpic->setMimeType(L"image/" + ext);
261         tag->addPicture(newpic);
262     }
263 }
264 
265 
266 void GetXiphCommentAlbumCover(Ogg::XiphComment * tag, string &cover_contents, int& type)
267 {
268     const auto& cover_list = tag->pictureList();
269     if (!cover_list.isEmpty())
270     {
271         auto pic = cover_list.front();
272         if (pic != nullptr)
273         {
274             const auto& pic_data = pic->data();
275             //��ȡר������
276             cover_contents.assign(pic_data.data(), pic_data.size());
277 
278             wstring img_type = pic->mimeType().toCWString();
279             type = GetPicType(img_type);
280         }
281     }
282 }
283 
284 
285 ///////////////////////////////////////////////////////////////////////////////////
286 ///////////////////////////////////////////////////////////////////////////////////
287 
288 CTagLibHelper::CTagLibHelper()
289 {
290 }
291 
292 CTagLibHelper::~CTagLibHelper()
293 {
294 }
295 
296 string CTagLibHelper::GetM4aAlbumCover(const wstring& file_path, int& type)
297 {
298     string cover_contents;
299     MP4::File file(file_path.c_str());
300     auto tag = file.tag();
301     if(tag != nullptr)
302     {
303         auto cover_item = tag->item(STR_MP4_COVER_TAG).toCoverArtList();
304         if (!cover_item.isEmpty())
305         {
306             const auto& pic_data = cover_item.front().data();
307             //��ȡר������
308             cover_contents.assign(pic_data.data(), pic_data.size());
309 
310             //��ȡ�����ʽ
311             switch (cover_item.front().format())
312             {
313             case MP4::CoverArt::JPEG:
314                 type = 0;
315                 break;
316             case MP4::CoverArt::PNG:
317                 type = 1;
318                 break;
319             case MP4::CoverArt::BMP:
320                 type = 3;
321                 break;
322             case MP4::CoverArt::GIF:
323                 type = 2;
324                 break;
325             default:
326                 type = -1;
327                 break;
328             }
329         }
330     }
331     return cover_contents;
332 }
333 
334 string CTagLibHelper::GetFlacAlbumCover(const wstring& file_path, int& type)
335 {
336     string cover_contents;
337     FLAC::File file(file_path.c_str());
338     const auto& cover_list = file.pictureList();
339     if (!cover_list.isEmpty())
340     {
341         auto pic = cover_list.front();
342         if (pic != nullptr)
343         {
344             const auto& pic_data = pic->data();
345             //��ȡר������
346             cover_contents.assign(pic_data.data(), pic_data.size());
347 
348             wstring img_type = pic->mimeType().toCWString();
349             type = GetPicType(img_type);
350         }
351     }
352     return cover_contents;
353 }
354 
355 string CTagLibHelper::GetMp3AlbumCover(const wstring & file_path, int & type)
356 {
357     string cover_contents;
358     MPEG::File file(file_path.c_str());
359     auto id3v2 = file.ID3v2Tag();
360     GetId3v2AlbumCover(id3v2, cover_contents, type);
361     return cover_contents;
362 }
363 
364 string CTagLibHelper::GetAsfAlbumCover(const wstring& file_path, int& type)
365 {
366     string cover_contents;
367     ASF::File file(file_path.c_str());
368     auto tag = file.tag();
369     if (tag != nullptr)
370     {
371         ASF::AttributeList attr = tag->attribute("WM/Picture");
372         if (!attr.isEmpty())
373         {
374             ASF::Picture picture = attr.front().toPicture();
375             auto pic_data = picture.picture();
376             cover_contents.assign(pic_data.data(), pic_data.size());
377             wstring img_type = picture.mimeType().toCWString();
378             type = GetPicType(img_type);
379         }
380     }
381     return cover_contents;
382 }
383 
384 string CTagLibHelper::GetWavAlbumCover(const wstring& file_path, int& type)
385 {
386     string cover_contents;
387     RIFF::WAV::File file(file_path.c_str());
388     auto id3v2 = file.ID3v2Tag();
389     GetId3v2AlbumCover(id3v2, cover_contents, type);
390     return cover_contents;
391 }
392 
393 string CTagLibHelper::GetTtaAlbumCover(const wstring& file_path, int& type)
394 {
395     string cover_contents;
396     TrueAudio::File file(file_path.c_str());
397     auto id3v2 = file.ID3v2Tag();
398     GetId3v2AlbumCover(id3v2, cover_contents, type);
399     return cover_contents;
400 }
401 
402 string CTagLibHelper::GetApeAlbumCover(const wstring& file_path, int& type)
403 {
404     string cover_contents;
405     APE::File file(file_path.c_str());
406     auto tag = file.APETag();
407     GetApeTagAlbumCover(tag, cover_contents, type);
408     return cover_contents;
409 }
410 
411 
412 string CTagLibHelper::GetOggAlbumCover(const wstring& file_path, int& type)
413 {
414     string cover_contents;
415     Ogg::Vorbis::File file(file_path.c_str());
416     auto tag = file.tag();
417     if (tag != nullptr)
418     {
419         GetXiphCommentAlbumCover(tag, cover_contents, type);
420     }
421     return cover_contents;
422 }
423 
424 string CTagLibHelper::GetOpusAlbumCover(const wstring & file_path, int & type)
425 {
426     string cover_contents;
427     Ogg::Opus::File file(file_path.c_str());
428     auto tag = file.tag();
429     if (tag != nullptr)
430     {
431         GetXiphCommentAlbumCover(tag, cover_contents, type);
432     }
433     return cover_contents;
434 }
435 
436 string CTagLibHelper::GetSpxAlbumCover(const wstring& file_path, int& type)
437 {
438     string cover_contents;
439     Ogg::Speex::File file(file_path.c_str());
440     auto tag = file.tag();
441     if (tag != nullptr)
442     {
443         GetXiphCommentAlbumCover(tag, cover_contents, type);
444     }
445     return cover_contents;
446 }
447 
448 string CTagLibHelper::GetAiffAlbumCover(const wstring& file_path, int& type)
449 {
450     string cover_contents;
451     RIFF::AIFF::File file(file_path.c_str());
452     auto id3v2 = file.tag();
453     GetId3v2AlbumCover(id3v2, cover_contents, type);
454     return cover_contents;
455 
456 }
457 
458 string CTagLibHelper::GetMpcAlbumCover(const wstring& file_path, int& type)
459 {
460     string cover_contents;
461     MPC::File file(file_path.c_str());
462     auto ape_tag = file.APETag();
463     GetApeTagAlbumCover(ape_tag, cover_contents, type);
464     return cover_contents;
465 }
466 
467 string CTagLibHelper::GetWavePackAlbumCover(const wstring& file_path, int& type)
468 {
469     string cover_contents;
470     WavPack::File file(file_path.c_str());
471     auto ape_tag = file.APETag();
472     GetApeTagAlbumCover(ape_tag, cover_contents, type);
473     return cover_contents;
474 }
475 
476 void CTagLibHelper::GetFlacTagInfo(SongInfo& song_info)
477 {
478     FLAC::File file(song_info.file_path.c_str());
479     if (file.hasID3v1Tag())
480         song_info.tag_type |= T_ID3V1;
481     if (file.hasID3v2Tag())
482         song_info.tag_type |= T_ID3V2;
483     auto tag = file.tag();
484     if (tag != nullptr)
485     {
486         TagToSongInfo(song_info, tag, file.hasID3v1Tag());
487     }
488 }
489 
490 void CTagLibHelper::GetM4aTagInfo(SongInfo& song_info)
491 {
492     MP4::File file(song_info.file_path.c_str());
493     if (file.hasMP4Tag())
494         song_info.tag_type |= T_MP4;
495     auto tag = file.tag();
496     if (tag != nullptr)
497     {
498         TagToSongInfo(song_info, tag, false);
499     }
500 }
501 
502 void CTagLibHelper::GetMpegTagInfo(SongInfo& song_info)
503 {
504     MPEG::File file(song_info.file_path.c_str());
505     if (file.hasID3v1Tag())
506         song_info.tag_type |= T_ID3V1;
507     if (file.hasID3v2Tag())
508         song_info.tag_type |= T_ID3V2;
509     if (file.hasAPETag())
510         song_info.tag_type |= T_APE;
511 
512     auto tag = file.tag();
513     if (tag != nullptr)
514     {
515         TagToSongInfo(song_info, tag, file.hasID3v1Tag());
516     }
517 }
518 
519 void CTagLibHelper::GetAsfTagInfo(SongInfo& song_info)
520 {
521     ASF::File file(song_info.file_path.c_str());
522     auto tag = file.tag();
523     if (tag != nullptr)
524     {
525         TagToSongInfo(song_info, tag, false);
526     }
527 }
528 
529 void CTagLibHelper::GetApeTagInfo(SongInfo& song_info)
530 {
531     APE::File file(song_info.file_path.c_str());
532     if (file.hasID3v1Tag())
533         song_info.tag_type |= T_ID3V1;
534     if (file.hasAPETag())
535         song_info.tag_type |= T_APE;
536 
537     auto tag = file.tag();
538     if (tag != nullptr)
539     {
540         TagToSongInfo(song_info, tag, file.hasID3v1Tag());
541     }
542 }
543 
544 void CTagLibHelper::GetWavTagInfo(SongInfo& song_info)
545 {
546     RIFF::WAV::File file(song_info.file_path.c_str());
547     if (file.hasID3v2Tag())
548         song_info.tag_type |= T_ID3V2;
549     if (file.hasInfoTag())
550         song_info.tag_type |= T_RIFF;
551     auto tag = file.tag();
552     if (tag != nullptr)
553     {
554         TagToSongInfo(song_info, tag, false);
555     }
556 }
557 
558 void CTagLibHelper::GetOggTagInfo(SongInfo& song_info)
559 {
560     Vorbis::File file(song_info.file_path.c_str());
561     auto tag = file.tag();
562     if (tag != nullptr)
563     {
564         TagToSongInfo(song_info, tag, false);
565     }
566 }
567 
568 void CTagLibHelper::GetMpcTagInfo(SongInfo& song_info)
569 {
570     MPC::File file(song_info.file_path.c_str());
571     if (file.hasAPETag())
572         song_info.tag_type |= T_APE;
573     if (file.hasID3v1Tag())
574         song_info.tag_type |= T_ID3V1;
575     auto tag = file.tag();
576     if (tag != nullptr)
577     {
578         TagToSongInfo(song_info, tag, file.hasID3v1Tag());
579     }
580 }
581 
582 void CTagLibHelper::GetOpusTagInfo(SongInfo& song_info)
583 {
584     Ogg::Opus::File file(song_info.file_path.c_str());
585     auto tag = file.tag();
586     if (tag != nullptr)
587     {
588         TagToSongInfo(song_info, tag, false);
589     }
590 }
591 
592 void CTagLibHelper::GetWavPackTagInfo(SongInfo& song_info)
593 {
594     WavPack::File file(song_info.file_path.c_str());
595     if (file.hasAPETag())
596         song_info.tag_type |= T_APE;
597     if (file.hasID3v1Tag())
598         song_info.tag_type |= T_ID3V1;
599     auto tag = file.tag();
600     if (tag != nullptr)
601     {
602         TagToSongInfo(song_info, tag, file.hasID3v1Tag());
603     }
604 }
605 
606 void CTagLibHelper::GetTtaTagInfo(SongInfo& song_info)
607 {
608     TrueAudio::File file(song_info.file_path.c_str());
609     if (file.hasID3v1Tag())
610         song_info.tag_type |= T_ID3V1;
611     if (file.hasID3v2Tag())
612         song_info.tag_type |= T_ID3V2;
613     auto tag = file.tag();
614     if (tag != nullptr)
615     {
616         TagToSongInfo(song_info, tag, file.hasID3v1Tag());
617     }
618 }
619 
620 void CTagLibHelper::GetAiffTagInfo(SongInfo& song_info)
621 {
622     RIFF::AIFF::File file(song_info.file_path.c_str());
623     if (file.hasID3v2Tag())
624         song_info.tag_type |= T_ID3V2;
625     auto tag = file.tag();
626     if (tag != nullptr)
627     {
628         TagToSongInfo(song_info, tag, false);
629     }
630 }
631 
632 void CTagLibHelper::GetSpxTagInfo(SongInfo& song_info)
633 {
634     Ogg::Speex::File file(song_info.file_path.c_str());
635     auto tag = file.tag();
636     if (tag != nullptr)
637     {
638         TagToSongInfo(song_info, tag, false);
639     }
640 }
641 
642 void CTagLibHelper::GetAnyFileTagInfo(SongInfo & song_info)
643 {
644     FileRef file(song_info.file_path.c_str());
645     auto tag = file.tag();
646     if (tag != nullptr)
647     {
648         TagToSongInfo(song_info, tag, false);
649     }
650 }
651 
652 wstring CTagLibHelper::GetMpegLyric(const wstring& file_path)
653 {
654     wstring lyrics;
655     MPEG::File file(file_path.c_str());
656     auto id3v2 = file.ID3v2Tag();
657     if (id3v2 != nullptr)
658     {
659         auto frame_list_map = id3v2->frameListMap();
660         auto lyric_frame = frame_list_map["USLT"];
661         if (!lyric_frame.isEmpty())
662             lyrics = lyric_frame.front()->toString().toWString();
663     }
664     return lyrics;
665 }
666 
667 wstring CTagLibHelper::GetM4aLyric(const wstring& file_path)
668 {
669     wstring lyrics;
670     MP4::File file(file_path.c_str());
671     auto tag = file.tag();
672     if (tag != nullptr)
673     {
674         auto item_map = file.tag()->itemMap();
675         auto lyric_item = item_map[STR_MP4_LYRICS_TAG].toStringList();;
676         if (!lyric_item.isEmpty())
677             lyrics = lyric_item.front().toWString();
678     }
679     return lyrics;
680 }
681 
682 wstring CTagLibHelper::GetFlacLyric(const wstring& file_path)
683 {
684     wstring lyrics;
685     FLAC::File file(file_path.c_str());
686     auto properties = file.properties();
687     auto lyric_item = properties["LYRICS"];
688     if (!lyric_item.isEmpty())
689     {
690         lyrics = lyric_item.front().toWString();
691     }
692     return lyrics;
693 }
694 
695 wstring CTagLibHelper::GetAsfLyric(const wstring& file_path)
696 {
697     wstring lyrics;
698     ASF::File file(file_path.c_str());
699     auto properties = file.properties();
700     auto lyric_item = properties["LYRICS"];
701     if (!lyric_item.isEmpty())
702     {
703         lyrics = lyric_item.front().toWString();
704     }
705     return lyrics;
706 }
707 
708 
709 bool CTagLibHelper::WriteMp3AlbumCover(const wstring& file_path, const wstring& album_cover_path, bool remove_exist)
710 {
711     MPEG::File file(file_path.c_str());
712     if (!file.isValid())
713         return false;
714 
715     //��ɾ��ר������
716     if (remove_exist)
717     {
718         auto id3v2tag = file.ID3v2Tag();
719         DeleteId3v2AlbumCover(id3v2tag);
720     }
721     if (!album_cover_path.empty())
722     {
723         auto id3v2tag = file.ID3v2Tag(true);
724         WriteId3v2AlbumCover(id3v2tag, album_cover_path);
725     }
726     bool saved = file.save(MPEG::File::ID3v2);
727     return saved;
728 }
729 
730 bool CTagLibHelper::WriteFlacAlbumCover(const wstring& file_path, const wstring& album_cover_path, bool remove_exist)
731 {
732     FLAC::File file(file_path.c_str());
733     if (!file.isValid())
734         return false;
735 
736     //��ɾ��ר������
737     if (remove_exist)
738     {
739         file.removePictures();
740     }
741 
742     if (!album_cover_path.empty())
743     {
744         ByteVector pic_data;
745         FileToByteVector(pic_data, album_cover_path);
746         FLAC::Picture *newpic = new FLAC::Picture();
747         newpic->setType(FLAC::Picture::FrontCover);
748         newpic->setData(pic_data);
749         wstring ext = CFilePathHelper(album_cover_path).GetFileExtension();
750         newpic->setMimeType(L"image/" + ext);
751         file.addPicture(newpic);
752     }
753     bool saved = file.save();
754     return saved;
755 }
756 
757 bool CTagLibHelper::WriteM4aAlbumCover(const wstring& file_path, const wstring& album_cover_path, bool remove_exist /*= true*/)
758 {
759     MP4::File file(file_path.c_str());
760     if (!file.isValid())
761         return false;
762 
763     auto tag = file.tag();
764     if (tag == nullptr)
765         return false;
766 
767     if (remove_exist)
768     {
769         if (tag->contains(STR_MP4_COVER_TAG))
770         {
771             tag->removeItem(STR_MP4_COVER_TAG);
772         }
773     }
774 
775     if (!album_cover_path.empty())
776     {
777         ByteVector pic_data;
778         FileToByteVector(pic_data, album_cover_path);
779         MP4::CoverArt::Format format = MP4::CoverArt::Format::Unknown;
780         wstring ext = CFilePathHelper(album_cover_path).GetFileExtension();
781         if (ext == L"jpg" || ext == L"jpeg")
782             format = MP4::CoverArt::Format::JPEG;
783         else if (ext == L"png")
784             format = MP4::CoverArt::Format::PNG;
785         else if (ext == L"gif")
786             format = MP4::CoverArt::Format::GIF;
787         else if (ext == L"bmp")
788             format = MP4::CoverArt::Format::BMP;
789         MP4::CoverArt cover_item(format, pic_data);
790 
791         auto cover_item_list = tag->item(STR_MP4_COVER_TAG).toCoverArtList();
792         cover_item_list.append(cover_item);
793         tag->setItem(STR_MP4_COVER_TAG, cover_item_list);
794     }
795     bool saved = file.save();
796     return saved;
797 }
798 
799 bool CTagLibHelper::WriteAsfAlbumCover(const wstring& file_path, const wstring& album_cover_path, bool remove_exist /*= true*/)
800 {
801     ASF::File file(file_path.c_str());
802     if (!file.isValid())
803         return false;
804 
805     auto tag = file.tag();
806     if (tag == nullptr)
807         return false;
808 
809     if (remove_exist)
810     {
811         if (tag->contains(STR_ASF_COVER_TAG))
812         {
813             tag->removeItem(STR_ASF_COVER_TAG);
814         }
815     }
816 
817     if (!album_cover_path.empty())
818     {
819         ByteVector pic_data;
820         FileToByteVector(pic_data, album_cover_path);
821 
822         ASF::Picture picture;
823         wstring str_mine_type = L"image/" + CFilePathHelper(album_cover_path).GetFileExtension();
824         picture.setMimeType(str_mine_type);
825         picture.setType(ASF::Picture::FrontCover);
826         picture.setPicture(pic_data);
827         tag->setAttribute(STR_ASF_COVER_TAG, picture);
828     }
829     bool saved = file.save();
830     return saved;
831 }
832 
833 bool CTagLibHelper::WriteWavAlbumCover(const wstring& file_path, const wstring& album_cover_path, bool remove_exist /*= true*/)
834 {
835     RIFF::WAV::File file(file_path.c_str());
836     if (!file.isValid())
837         return false;
838 
839     //��ɾ��ר������
840     auto id3v2tag = file.ID3v2Tag();
841     if (remove_exist)
842     {
843         DeleteId3v2AlbumCover(id3v2tag);
844     }
845     if (!album_cover_path.empty())
846     {
847         WriteId3v2AlbumCover(id3v2tag, album_cover_path);
848     }
849     bool saved = file.save();
850     return saved;
851 }
852 
853 bool CTagLibHelper::WriteTtaAlbumCover(const wstring& file_path, const wstring& album_cover_path, bool remove_exist /*= true*/)
854 {
855     TrueAudio::File file(file_path.c_str());
856     if (!file.isValid())
857         return false;
858 
859     if (remove_exist)
860     {
861         auto id3v2tag = file.ID3v2Tag();
862         DeleteId3v2AlbumCover(id3v2tag);
863     }
864     if (!album_cover_path.empty())
865     {
866         auto id3v2tag = file.ID3v2Tag(true);
867         WriteId3v2AlbumCover(id3v2tag, album_cover_path);
868     }
869     bool saved = file.save();
870     return saved;
871     return false;
872 }
873 
874 bool CTagLibHelper::WriteApeAlbumCover(const wstring& file_path, const wstring& album_cover_path, bool remove_exist /*= true*/)
875 {
876     APE::File file(file_path.c_str());
877     if (!file.isValid())
878         return false;
879 
880     auto tag = file.APETag(true);
881     WriteApeTagAlbumCover(tag, album_cover_path, remove_exist);
882     bool saved = file.save();
883     return saved;
884 }
885 
886 bool CTagLibHelper::WriteOggAlbumCover(const wstring& file_path, const wstring& album_cover_path, bool remove_exist /*= true*/)
887 {
888     Ogg::Vorbis::File file(file_path.c_str());
889     if (!file.isValid())
890         return false;
891 
892     auto tag = file.tag();
893     if (tag != nullptr)
894     {
895         WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist);
896         bool saved = file.save();
897         return saved;
898     }
899     return false;
900 }
901 
902 bool CTagLibHelper::WriteOpusAlbumCover(const wstring & file_path, const wstring & album_cover_path, bool remove_exist)
903 {
904     Ogg::Opus::File file(file_path.c_str());
905     if (!file.isValid())
906         return false;
907 
908     auto tag = file.tag();
909     if (tag != nullptr)
910     {
911         WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist);
912         bool saved = file.save();
913         return saved;
914     }
915     return false;
916 }
917 
918 bool CTagLibHelper::WriteSpxAlbumCover(const wstring& file_path, const wstring& album_cover_path, bool remove_exist /*= true*/)
919 {
920     Ogg::Speex::File file(file_path.c_str());
921     if (!file.isValid())
922         return false;
923 
924     auto tag = file.tag();
925     if (tag != nullptr)
926     {
927         WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist);
928         bool saved = file.save();
929         return saved;
930     }
931     return false;
932 }
933 
934 bool CTagLibHelper::WriteAiffAlbumCover(const wstring& file_path, const wstring& album_cover_path, bool remove_exist /*= true*/)
935 {
936     RIFF::AIFF::File file(file_path.c_str());
937     if (!file.isValid())
938         return false;
939 
940     //��ɾ��ר������
941     auto id3v2tag = file.tag();
942     if (remove_exist)
943     {
944         DeleteId3v2AlbumCover(id3v2tag);
945     }
946     if (!album_cover_path.empty())
947     {
948         WriteId3v2AlbumCover(id3v2tag, album_cover_path);
949     }
950     bool saved = file.save();
951     return saved;
952 }
953 
954 bool CTagLibHelper::WriteMpcAlbumCover(const wstring& file_path, const wstring& album_cover_path, bool remove_exist /*= true*/)
955 {
956     MPC::File file(file_path.c_str());
957     if (!file.isValid())
958         return false;
959 
960     auto tag = file.APETag(true);
961     WriteApeTagAlbumCover(tag, album_cover_path, remove_exist);
962     bool saved = file.save();
963     return saved;
964 }
965 
966 bool CTagLibHelper::WriteWavePackAlbumCover(const wstring& file_path, const wstring& album_cover_path, bool remove_exist /*= true*/)
967 {
968     WavPack::File file(file_path.c_str());
969     if (!file.isValid())
970         return false;
971 
972     auto tag = file.APETag(true);
973     WriteApeTagAlbumCover(tag, album_cover_path, remove_exist);
974     bool saved = file.save();
975     return saved;
976 }
977 
978 bool CTagLibHelper::WriteMpegTag(SongInfo & song_info)
979 {
980     MPEG::File file(song_info.file_path.c_str());
981     auto tag = file.tag();
982     SongInfoToTag(song_info, tag);
983     int tags = MPEG::File::ID3v2;
984     //if (file.hasID3v1Tag())
985     //    tags |= MPEG::File::ID3v1;
986     if (file.hasAPETag())
987         tags |= MPEG::File::APE;
988     bool saved = file.save(tags);
989     return saved;
990 }
991 
992 bool CTagLibHelper::WriteFlacTag(SongInfo& song_info)
993 {
994     FLAC::File file(song_info.file_path.c_str());
995     auto tag = file.tag();
996     SongInfoToTag(song_info, tag);
997     bool saved = file.save();
998     return saved;
999 }
1000 
1001 bool CTagLibHelper::WriteM4aTag(SongInfo & song_info)
1002 {
1003     MP4::File file(song_info.file_path.c_str());
1004     auto tag = file.tag();
1005     SongInfoToTag(song_info, tag);
1006     bool saved = file.save();
1007     return saved;
1008 }
1009 
1010 bool CTagLibHelper::WriteWavTag(SongInfo & song_info)
1011 {
1012     RIFF::WAV::File file(song_info.file_path.c_str());
1013     auto tag = file.tag();
1014     SongInfoToTag(song_info, tag);
1015     bool saved = file.save();
1016     return saved;
1017 }
1018 
1019 bool CTagLibHelper::WriteOggTag(SongInfo & song_info)
1020 {
1021     Vorbis::File file(song_info.file_path.c_str());
1022     auto tag = file.tag();
1023     SongInfoToTag(song_info, tag);
1024     bool saved = file.save();
1025     return saved;
1026 }
1027 
1028 bool CTagLibHelper::WriteApeTag(SongInfo& song_info)
1029 {
1030     APE::File file(song_info.file_path.c_str());
1031     auto tag = file.tag();
1032     SongInfoToTag(song_info, tag);
1033     bool saved = file.save();
1034     return saved;
1035 }
1036 
1037 bool CTagLibHelper::WriteMpcTag(SongInfo& song_info)
1038 {
1039     MPC::File file(song_info.file_path.c_str());
1040     auto tag = file.tag();
1041     SongInfoToTag(song_info, tag);
1042     bool saved = file.save();
1043     return saved;
1044 }
1045 
1046 bool CTagLibHelper::WriteOpusTag(SongInfo & song_info)
1047 {
1048     Ogg::Opus::File file(song_info.file_path.c_str());
1049     auto tag = file.tag();
1050     SongInfoToTag(song_info, tag);
1051     bool saved = file.save();
1052     return saved;
1053 }
1054 
1055 bool CTagLibHelper::WriteWavPackTag(SongInfo& song_info)
1056 {
1057     WavPack::File file(song_info.file_path.c_str());
1058     auto tag = file.tag();
1059     SongInfoToTag(song_info, tag);
1060     bool saved = file.save();
1061     return saved;
1062 }
1063 
1064 bool CTagLibHelper::WriteTtaTag(SongInfo& song_info)
1065 {
1066     TrueAudio::File file(song_info.file_path.c_str());
1067     auto tag = file.tag();
1068     SongInfoToTag(song_info, tag);
1069     bool saved = file.save();
1070     return saved;
1071 }
1072 
1073 bool CTagLibHelper::WriteAiffTag(SongInfo & song_info)
1074 {
1075     RIFF::AIFF::File file(song_info.file_path.c_str());
1076     auto tag = file.tag();
1077     SongInfoToTag(song_info, tag);
1078     bool saved = file.save();
1079     return saved;
1080 }
1081 
1082 bool CTagLibHelper::WriteAsfTag(SongInfo & song_info)
1083 {
1084     ASF::File file(song_info.file_path.c_str());
1085     auto tag = file.tag();
1086     SongInfoToTag(song_info, tag);
1087     bool saved = file.save();
1088     return saved;
1089 }
1090 
1091 bool CTagLibHelper::WriteSpxTag(SongInfo& song_info)
1092 {
1093     Ogg::Speex::File file(song_info.file_path.c_str());
1094     auto tag = file.tag();
1095     SongInfoToTag(song_info, tag);
1096     bool saved = file.save();
1097     return saved;
1098 }
1099