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