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