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