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