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