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 #include "taglib/id3v2frame.h" 29 #include "taglib/popularimeterframe.h" 30 31 32 using namespace TagLib; 33 34 #define STR_MP4_COVER_TAG "covr" 35 #define STR_ASF_COVER_TAG "WM/Picture" 36 #define STR_APE_COVER_TAG "COVER ART (FRONT)" 37 38 #define STR_MP4_LYRICS_TAG "----:com.apple.iTunes:Lyrics" 39 #define STR_ID3V2_LYRIC_TAG "USLT" 40 #define STR_FLAC_LYRIC_TAG "LYRICS" 41 #define STR_ASF_LYRIC_TAG "LYRICS" 42 43 #define STR_APE_CUE_TAG "CUESHEET" 44 45 #define STR_ID3V2_RATEING_TAG "POPM" 46 #define STR_FLAC_RATING_TAG "RATING" 47 //#define STR_WMA_RATING_TAG "RATING WMP" 48 49 //将taglib中的字符串转换成std::wstring类型。 50 //由于taglib将所有非unicode编码全部作为Latin编码处理,因此无法正确处理本地代码页 51 //这里将Latin编码的字符串按本地代码页处理 52 static std::wstring TagStringToWstring(const String& str, bool to_local) 53 { 54 std::wstring result; 55 if (to_local && str.isLatin1()) 56 result = CCommon::StrToUnicode(str.to8Bit(), CodeType::ANSI); 57 else 58 result = str.toWString(); 59 return result; 60 } 61 62 static void SongInfoToTag(const SongInfo& song_info, Tag* tag) 63 { 64 if (tag != nullptr) 65 { 66 tag->setTitle(song_info.title); 67 tag->setArtist(song_info.artist); 68 tag->setAlbum(song_info.album); 69 tag->setGenre(song_info.genre); 70 tag->setTrack(song_info.track); 71 tag->setComment(song_info.comment); 72 tag->setYear(song_info.year); 73 } 74 } 75 76 static bool IsStringNumber(std::wstring str, int num) 77 { 78 if (!str.empty() && str.front() == L'(') 79 str = str.substr(1); 80 if (!str.empty() && str.back() == L')') 81 str.pop_back(); 82 if (CCommon::StrIsNumber(str)) 83 { 84 num = _wtoi(str.c_str()); 85 return true; 86 } 87 return false; 88 } 89 90 static void TagToSongInfo(SongInfo& song_info, Tag* tag, bool to_local) 91 { 92 if (tag != nullptr) 93 { 94 song_info.title = TagStringToWstring(tag->title(), to_local); 95 song_info.artist = TagStringToWstring(tag->artist(), to_local); 96 song_info.album = TagStringToWstring(tag->album(), to_local); 97 song_info.genre = TagStringToWstring(tag->genre(), to_local); 98 int genre_num{}; 99 if (IsStringNumber(song_info.genre, genre_num)) 100 { 101 song_info.genre = CAudioCommon::GetGenre(static_cast<BYTE>(genre_num)); 102 } 103 104 song_info.year = tag->year(); 105 song_info.track = tag->track(); 106 song_info.comment = TagStringToWstring(tag->comment(), to_local); 107 } 108 } 109 110 //将文件内容读取到ByteVector 111 static void FileToByteVector(ByteVector& data, const std::wstring& file_path) 112 { 113 std::ifstream file{ file_path, std::ios::binary | std::ios::in }; 114 if (file.fail()) 115 return; 116 117 //获取文件长度 118 file.seekg(0, file.end); 119 unsigned int length = static_cast<unsigned int>(file.tellg()); 120 file.seekg(0, file.beg); 121 122 data.clear(); 123 data.resize(length); 124 125 file.read(data.data(), length); 126 127 file.close(); 128 } 129 130 int GetPicType(const std::wstring& mimeType) 131 { 132 int type{ -1 }; 133 if (mimeType == L"image/jpeg" || mimeType == L"image/jpg") 134 type = 0; 135 else if (mimeType == L"image/png") 136 type = 1; 137 else if (mimeType == L"image/gif") 138 type = 2; 139 else if (mimeType == L"image/bmp") 140 type = 3; 141 else 142 type = -1; 143 return type; 144 } 145 146 static void GetId3v2AlbumCover(ID3v2::Tag* id3v2, string& cover_contents, int& type) 147 { 148 if (id3v2 != nullptr) 149 { 150 auto pic_frame_list = id3v2->frameListMap()["APIC"]; 151 if (!pic_frame_list.isEmpty()) 152 { 153 ID3v2::AttachedPictureFrame* frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(pic_frame_list.front()); 154 if (frame != nullptr) 155 { 156 auto pic_data = frame->picture(); 157 //获取专辑封面 158 cover_contents.assign(pic_data.data(), pic_data.size()); 159 std::wstring img_type = frame->mimeType().toCWString(); 160 type = GetPicType(img_type); 161 } 162 } 163 } 164 } 165 166 static void DeleteId3v2AlbumCover(ID3v2::Tag* id3v2tag) 167 { 168 if (id3v2tag != nullptr) 169 { 170 auto pic_frame_list = id3v2tag->frameListMap()["APIC"]; 171 if (!pic_frame_list.isEmpty()) 172 { 173 for (auto frame : pic_frame_list) 174 id3v2tag->removeFrame(frame); 175 } 176 } 177 } 178 179 static void WriteId3v2AlbumCover(ID3v2::Tag* id3v2tag, const std::wstring& album_cover_path) 180 { 181 if (id3v2tag != nullptr) 182 { 183 //读取图片文件 184 ByteVector pic_data; 185 FileToByteVector(pic_data, album_cover_path); 186 //向音频文件写入图片文件 187 ID3v2::AttachedPictureFrame* pic_frame = new ID3v2::AttachedPictureFrame(); 188 pic_frame->setPicture(pic_data); 189 pic_frame->setType(ID3v2::AttachedPictureFrame::FrontCover); 190 std::wstring ext = CFilePathHelper(album_cover_path).GetFileExtension(); 191 pic_frame->setMimeType(L"image/" + ext); 192 id3v2tag->addFrame(pic_frame); 193 } 194 } 195 196 197 static void GetApeTagAlbumCover(APE::Tag* tag, string& cover_contents, int& type) 198 { 199 if (tag != nullptr) 200 { 201 auto item_list_map = tag->itemListMap(); 202 auto pic_item = item_list_map[STR_APE_COVER_TAG]; 203 auto pic_data = pic_item.binaryData(); 204 if (!pic_data.isEmpty()) 205 { 206 cover_contents.assign(pic_data.data(), pic_data.size()); 207 208 size_t index{}; 209 index = cover_contents.find('\0'); 210 std::string pic_desc; 211 if (index != std::string::npos) 212 { 213 pic_desc = cover_contents.substr(0, index); 214 cover_contents = cover_contents.substr(index + 1); 215 } 216 217 if (!pic_desc.empty()) 218 { 219 std::string img_type; 220 index = pic_desc.rfind('.'); 221 if (index != std::string::npos && index < pic_desc.size() - 1) 222 { 223 img_type = pic_desc.substr(index + 1); 224 img_type = "image/" + img_type; 225 type = GetPicType(CCommon::ASCIIToUnicode(img_type)); 226 } 227 } 228 } 229 } 230 } 231 232 static void WriteApeTagAlbumCover(APE::Tag* tag, const std::wstring& album_cover_path, bool remove_exist) 233 { 234 if (remove_exist) 235 { 236 tag->removeItem(STR_APE_COVER_TAG); 237 } 238 239 if (!album_cover_path.empty()) 240 { 241 ByteVector pic_data; 242 FileToByteVector(pic_data, album_cover_path); 243 244 ByteVector pic_item_data; 245 pic_item_data = "Cover Art (Front)."; 246 std::wstring file_type = CFilePathHelper(album_cover_path).GetFileExtension(); 247 for (wchar_t ch : file_type) 248 pic_item_data.append(static_cast<char>(ch)); 249 pic_item_data.append('\0'); 250 pic_item_data.append(pic_data); 251 252 APE::Item pic_item(STR_APE_COVER_TAG, pic_item_data, true); 253 tag->setItem(STR_APE_COVER_TAG, pic_item); 254 } 255 } 256 257 static void WriteXiphCommentAlbumCover(Ogg::XiphComment* tag, const std::wstring& album_cover_path, bool remove_exist) 258 { 259 //先删除专辑封面 260 if (remove_exist) 261 { 262 tag->removeAllPictures(); 263 } 264 265 if (!album_cover_path.empty()) 266 { 267 ByteVector pic_data; 268 FileToByteVector(pic_data, album_cover_path); 269 FLAC::Picture* newpic = new FLAC::Picture(); 270 newpic->setType(FLAC::Picture::FrontCover); 271 newpic->setData(pic_data); 272 std::wstring ext = CFilePathHelper(album_cover_path).GetFileExtension(); 273 newpic->setMimeType(L"image/" + ext); 274 tag->addPicture(newpic); 275 } 276 } 277 278 279 static void GetXiphCommentAlbumCover(Ogg::XiphComment* tag, string& cover_contents, int& type) 280 { 281 const auto& cover_list = tag->pictureList(); 282 if (!cover_list.isEmpty()) 283 { 284 auto pic = cover_list.front(); 285 if (pic != nullptr) 286 { 287 const auto& pic_data = pic->data(); 288 //获取专辑封面 289 cover_contents.assign(pic_data.data(), pic_data.size()); 290 291 std::wstring img_type = pic->mimeType().toCWString(); 292 type = GetPicType(img_type); 293 } 294 } 295 } 296 297 static std::wstring GetId3v2Lyric(ID3v2::Tag* id3v2) 298 { 299 std::wstring lyrics; 300 if (id3v2 != nullptr) 301 { 302 auto frame_list_map = id3v2->frameListMap(); 303 auto lyric_frame = frame_list_map[STR_ID3V2_LYRIC_TAG]; 304 if (!lyric_frame.isEmpty()) 305 lyrics = lyric_frame.front()->toString().toWString(); 306 } 307 return lyrics; 308 } 309 310 311 static void WriteId3v2Lyric(ID3v2::Tag* id3v2, const std::wstring& lyric_contents) 312 { 313 if (id3v2 != nullptr) 314 { 315 //先删除歌词帧 316 auto lyric_frame_list = id3v2->frameListMap()[STR_ID3V2_LYRIC_TAG]; 317 if (!lyric_frame_list.isEmpty()) 318 { 319 for (auto frame : lyric_frame_list) 320 id3v2->removeFrame(frame); 321 } 322 323 if (!lyric_contents.empty()) 324 { 325 //写入歌词帧 326 ID3v2::UnsynchronizedLyricsFrame* lyric_frame = new ID3v2::UnsynchronizedLyricsFrame(); 327 lyric_frame->setText(lyric_contents.c_str()); 328 id3v2->addFrame(lyric_frame); 329 } 330 } 331 } 332 333 334 template<class T> 335 void GetTagPropertyMap(T* tag, std::map<std::wstring, std::wstring>& property_map) 336 { 337 if (tag != nullptr) 338 { 339 auto properties = tag->properties(); 340 for (const auto& prop : properties) 341 { 342 std::wstring key = prop.first.toWString(); 343 std::wstring value = TagStringToWstring(prop.second.toString(L";"), true); 344 auto iter = property_map.find(key); 345 if (iter == property_map.end()) 346 property_map[key] = value; 347 else if (iter->second.empty()) 348 iter->second = value; 349 } 350 } 351 } 352 353 static std::wstring GetMapValue(const std::wstring& key, const std::map<std::wstring, std::wstring>& property_map) 354 { 355 auto iter = property_map.find(key); 356 if (iter != property_map.end()) 357 return iter->second; 358 return std::wstring(); 359 } 360 361 //将标签属性中额外的信息保存到SongInfo中 362 static void OtherPropertyToSongInfo(SongInfo& song_info, const std::map<std::wstring, std::wstring>& property_map) 363 { 364 //获取唱片集艺术家 365 song_info.album_artist = GetMapValue(L"ALBUMARTIST", property_map); 366 367 //获取音轨总数 368 std::wstring track_number = GetMapValue(L"TRACKNUMBER", property_map); 369 size_t index = track_number.find(L'/'); 370 if (index != std::wstring::npos) 371 { 372 song_info.total_tracks = static_cast<BYTE>(_wtoi(track_number.substr(index + 1).c_str())); 373 } 374 375 //获取CD序号和CD总数 376 std::wstring disc_number = GetMapValue(L"DISCNUMBER", property_map); 377 index = disc_number.find(L'/'); 378 if (index != std::wstring::npos) 379 { 380 song_info.total_discs = static_cast<BYTE>(_wtoi(disc_number.substr(index + 1).c_str())); 381 } 382 song_info.disc_num = static_cast<BYTE>(_wtoi(disc_number.substr(0, index).c_str())); 383 } 384 385 template<class T> 386 static void WriteOtherProperties(const SongInfo& song_info, T& file) 387 { 388 TagLib::PropertyMap properties = file.properties(); 389 if (!song_info.album_artist.empty()) 390 properties["ALBUMARTIST"].append(song_info.album_artist); 391 if (song_info.disc_num != 0) 392 properties["DISCNUMBER"].append(std::to_wstring(static_cast<int>(song_info.disc_num))); 393 file.setProperties(properties); 394 } 395 396 //解析Windows资源管理器设置的分级信息 397 static int ParseAudioRating(int rate_raw) 398 { 399 //使用Windows资源管理器设置了分级后,POPM字段的内容为以下格式: 400 //Windows Media Player 9 Series rating=196 counter=0 401 //其中rating后面的数字为分级,rating与分级的对应关系如下所示 402 /* 403 rating | 分级 404 ---------|------------ 405 255 | 5 406 196 | 4 407 128 | 3 408 64 | 2 409 1 | 1 410 */ 411 412 //根据分级转换成1~5星 413 if (rate_raw == 1) 414 return 1; 415 else if (rate_raw <= 64) 416 return 2; 417 else if (rate_raw <= 128) 418 return 3; 419 else if (rate_raw <= 196) 420 return 4; 421 else if (rate_raw <= 255) 422 return 5; 423 return 0; 424 } 425 426 static int GenerateAudioRating(int rate) 427 { 428 switch (rate) 429 { 430 case 1: 431 return 1; 432 case 2: 433 return 64; 434 case 3: 435 return 128; 436 case 4: 437 return 196; 438 case 5: 439 return 255; 440 default: 441 return 0; 442 } 443 } 444 445 static int GetId3v2Rating(ID3v2::Tag* id3v2) 446 { 447 if (id3v2 != nullptr) 448 { 449 auto frame_list_map = id3v2->frameListMap(); 450 auto rate_frame = frame_list_map[STR_ID3V2_RATEING_TAG]; 451 if (!rate_frame.isEmpty()) 452 { 453 ID3v2::PopularimeterFrame* pFrame = dynamic_cast<ID3v2::PopularimeterFrame*>(rate_frame.front()); 454 if (pFrame != nullptr) 455 { 456 int rate_raw = pFrame->rating(); 457 return ParseAudioRating(rate_raw); 458 } 459 } 460 } 461 return 0; 462 } 463 464 static void WriteId3v2Rating(ID3v2::Tag* id3v2, int rate) 465 { 466 if (id3v2 != nullptr) 467 { 468 auto frameListMap = id3v2->frameListMap(); 469 470 //先删除POPM帧 471 auto rate_frame_list = id3v2->frameListMap()[STR_ID3V2_RATEING_TAG]; 472 if (!rate_frame_list.isEmpty()) 473 { 474 for (auto frame : rate_frame_list) 475 id3v2->removeFrame(frame); 476 } 477 478 if (rate >= 1 && rate <= 5) 479 { 480 ID3v2::PopularimeterFrame* rate_frame = new ID3v2::PopularimeterFrame(); 481 int rate_raw = GenerateAudioRating(rate); 482 rate_frame->setRating(rate_raw); 483 id3v2->addFrame(rate_frame); 484 } 485 } 486 } 487 488 static void getFlacPropertyMap(FLAC::File& file, std::map<std::wstring, std::wstring>& property_map) 489 { 490 if (file.hasXiphComment()) 491 GetTagPropertyMap(file.xiphComment(), property_map); 492 if (file.hasID3v2Tag()) 493 GetTagPropertyMap(file.ID3v2Tag(), property_map); 494 if (file.hasID3v1Tag()) 495 GetTagPropertyMap(file.ID3v1Tag(), property_map); 496 } 497 498 static void getM4aPropertyMap(MP4::File& file, std::map<std::wstring, std::wstring>& property_map) 499 { 500 auto tag = file.tag(); 501 GetTagPropertyMap(tag, property_map); 502 } 503 504 static void getMpegPropertyMap(MPEG::File& file, std::map<std::wstring, std::wstring>& property_map) 505 { 506 if (file.hasID3v2Tag()) 507 GetTagPropertyMap(file.ID3v2Tag(), property_map); 508 if (file.hasAPETag()) 509 GetTagPropertyMap(file.APETag(), property_map); 510 if (file.hasID3v1Tag()) 511 GetTagPropertyMap(file.ID3v1Tag(), property_map); 512 } 513 514 static void getAsfPropertyMap(ASF::File& file, std::map<std::wstring, std::wstring>& property_map) 515 { 516 auto tag = file.tag(); 517 GetTagPropertyMap(tag, property_map); 518 } 519 520 static void getApePropertyMap(APE::File& file, std::map<std::wstring, std::wstring>& property_map) 521 { 522 if (file.hasAPETag()) 523 GetTagPropertyMap(file.APETag(), property_map); 524 if (file.hasID3v1Tag()) 525 GetTagPropertyMap(file.ID3v1Tag(), property_map); 526 } 527 528 static void getWavPropertyMap(RIFF::WAV::File& file, std::map<std::wstring, std::wstring>& property_map) 529 { 530 if (file.hasID3v2Tag()) 531 GetTagPropertyMap(file.ID3v2Tag(), property_map); 532 if (file.hasInfoTag()) 533 GetTagPropertyMap(file.InfoTag(), property_map); 534 } 535 536 static void getOggPropertyMap(Vorbis::File& file, std::map<std::wstring, std::wstring>& property_map) 537 { 538 auto tag = file.tag(); 539 GetTagPropertyMap(tag, property_map); 540 } 541 542 static void getMpcPropertyMap(MPC::File& file, std::map<std::wstring, std::wstring>& property_map) 543 { 544 if (file.hasAPETag()) 545 GetTagPropertyMap(file.APETag(), property_map); 546 if (file.hasID3v1Tag()) 547 GetTagPropertyMap(file.ID3v1Tag(), property_map); 548 } 549 550 static void getOpusPropertyMap(Ogg::Opus::File& file, std::map<std::wstring, std::wstring>& property_map) 551 { 552 auto tag = file.tag(); 553 GetTagPropertyMap(tag, property_map); 554 } 555 556 static void getWavPackPropertyMap(WavPack::File& file, std::map<std::wstring, std::wstring>& property_map) 557 { 558 if (file.hasAPETag()) 559 GetTagPropertyMap(file.APETag(), property_map); 560 if (file.hasID3v1Tag()) 561 GetTagPropertyMap(file.ID3v1Tag(), property_map); 562 } 563 564 static void getTtaPropertyMap(TrueAudio::File& file, std::map<std::wstring, std::wstring>& property_map) 565 { 566 if (file.hasID3v2Tag()) 567 GetTagPropertyMap(file.ID3v2Tag(), property_map); 568 if (file.hasID3v1Tag()) 569 GetTagPropertyMap(file.ID3v1Tag(), property_map); 570 } 571 572 static void getAiffPropertyMap(RIFF::AIFF::File& file, std::map<std::wstring, std::wstring>& property_map) 573 { 574 auto tag = file.tag(); 575 GetTagPropertyMap(tag, property_map); 576 } 577 578 static void getSpxPropertyMap(Ogg::Speex::File& file, std::map<std::wstring, std::wstring>& property_map) 579 { 580 auto tag = file.tag(); 581 GetTagPropertyMap(tag, property_map); 582 } 583 584 static void getAnyFilePropertyMap(FileRef& file, std::map<std::wstring, std::wstring>& property_map) 585 { 586 auto tag = file.tag(); 587 GetTagPropertyMap(tag, property_map); 588 } 589 590 591 /////////////////////////////////////////////////////////////////////////////////// 592 /////////////////////////////////////////////////////////////////////////////////// 593 /////////////////////////////////////////////////////////////////////////////////// 594 595 bool CTagLibHelper::m_write_id3v2_3{ false }; 596 597 CTagLibHelper::CTagLibHelper() 598 { 599 } 600 601 CTagLibHelper::~CTagLibHelper() 602 { 603 } 604 605 void CTagLibHelper::SetWriteId3V2_3(bool write_id3v2_3) 606 { 607 m_write_id3v2_3 = write_id3v2_3; 608 } 609 610 string CTagLibHelper::GetM4aAlbumCover(const std::wstring& file_path, int& type) 611 { 612 string cover_contents; 613 MP4::File file(file_path.c_str()); 614 auto tag = file.tag(); 615 if (tag != nullptr) 616 { 617 auto cover_item = tag->item(STR_MP4_COVER_TAG).toCoverArtList(); 618 if (!cover_item.isEmpty()) 619 { 620 const auto& pic_data = cover_item.front().data(); 621 //获取专辑封面 622 cover_contents.assign(pic_data.data(), pic_data.size()); 623 624 //获取封面格式 625 switch (cover_item.front().format()) 626 { 627 case MP4::CoverArt::JPEG: 628 type = 0; 629 break; 630 case MP4::CoverArt::PNG: 631 type = 1; 632 break; 633 case MP4::CoverArt::BMP: 634 type = 3; 635 break; 636 case MP4::CoverArt::GIF: 637 type = 2; 638 break; 639 default: 640 type = -1; 641 break; 642 } 643 } 644 } 645 return cover_contents; 646 } 647 648 string CTagLibHelper::GetFlacAlbumCover(const std::wstring& file_path, int& type) 649 { 650 string cover_contents; 651 FLAC::File file(file_path.c_str()); 652 const auto& cover_list = file.pictureList(); 653 if (!cover_list.isEmpty()) 654 { 655 auto pic = cover_list.front(); 656 if (pic != nullptr) 657 { 658 const auto& pic_data = pic->data(); 659 //获取专辑封面 660 cover_contents.assign(pic_data.data(), pic_data.size()); 661 662 std::wstring img_type = pic->mimeType().toCWString(); 663 type = GetPicType(img_type); 664 } 665 } 666 return cover_contents; 667 } 668 669 string CTagLibHelper::GetMp3AlbumCover(const std::wstring& file_path, int& type) 670 { 671 string cover_contents; 672 MPEG::File file(file_path.c_str()); 673 auto id3v2 = file.ID3v2Tag(); 674 GetId3v2AlbumCover(id3v2, cover_contents, type); 675 return cover_contents; 676 } 677 678 string CTagLibHelper::GetAsfAlbumCover(const std::wstring& file_path, int& type) 679 { 680 string cover_contents; 681 ASF::File file(file_path.c_str()); 682 auto tag = file.tag(); 683 if (tag != nullptr) 684 { 685 ASF::AttributeList attr = tag->attribute("WM/Picture"); 686 if (!attr.isEmpty()) 687 { 688 ASF::Picture picture = attr.front().toPicture(); 689 auto pic_data = picture.picture(); 690 cover_contents.assign(pic_data.data(), pic_data.size()); 691 std::wstring img_type = picture.mimeType().toCWString(); 692 type = GetPicType(img_type); 693 } 694 } 695 return cover_contents; 696 } 697 698 string CTagLibHelper::GetWavAlbumCover(const std::wstring& file_path, int& type) 699 { 700 string cover_contents; 701 RIFF::WAV::File file(file_path.c_str()); 702 auto id3v2 = file.ID3v2Tag(); 703 GetId3v2AlbumCover(id3v2, cover_contents, type); 704 return cover_contents; 705 } 706 707 string CTagLibHelper::GetTtaAlbumCover(const std::wstring& file_path, int& type) 708 { 709 string cover_contents; 710 TrueAudio::File file(file_path.c_str()); 711 auto id3v2 = file.ID3v2Tag(); 712 GetId3v2AlbumCover(id3v2, cover_contents, type); 713 return cover_contents; 714 } 715 716 string CTagLibHelper::GetApeAlbumCover(const std::wstring& file_path, int& type) 717 { 718 string cover_contents; 719 APE::File file(file_path.c_str()); 720 auto tag = file.APETag(); 721 GetApeTagAlbumCover(tag, cover_contents, type); 722 return cover_contents; 723 } 724 725 726 string CTagLibHelper::GetOggAlbumCover(const std::wstring& file_path, int& type) 727 { 728 string cover_contents; 729 Ogg::Vorbis::File file(file_path.c_str()); 730 auto tag = file.tag(); 731 if (tag != nullptr) 732 { 733 GetXiphCommentAlbumCover(tag, cover_contents, type); 734 } 735 return cover_contents; 736 } 737 738 string CTagLibHelper::GetOpusAlbumCover(const std::wstring& file_path, int& type) 739 { 740 string cover_contents; 741 Ogg::Opus::File file(file_path.c_str()); 742 auto tag = file.tag(); 743 if (tag != nullptr) 744 { 745 GetXiphCommentAlbumCover(tag, cover_contents, type); 746 } 747 return cover_contents; 748 } 749 750 string CTagLibHelper::GetSpxAlbumCover(const std::wstring& file_path, int& type) 751 { 752 string cover_contents; 753 Ogg::Speex::File file(file_path.c_str()); 754 auto tag = file.tag(); 755 if (tag != nullptr) 756 { 757 GetXiphCommentAlbumCover(tag, cover_contents, type); 758 } 759 return cover_contents; 760 } 761 762 string CTagLibHelper::GetAiffAlbumCover(const std::wstring& file_path, int& type) 763 { 764 string cover_contents; 765 RIFF::AIFF::File file(file_path.c_str()); 766 auto id3v2 = file.tag(); 767 GetId3v2AlbumCover(id3v2, cover_contents, type); 768 return cover_contents; 769 770 } 771 772 string CTagLibHelper::GetMpcAlbumCover(const std::wstring& file_path, int& type) 773 { 774 string cover_contents; 775 MPC::File file(file_path.c_str()); 776 auto ape_tag = file.APETag(); 777 GetApeTagAlbumCover(ape_tag, cover_contents, type); 778 return cover_contents; 779 } 780 781 string CTagLibHelper::GetWavePackAlbumCover(const std::wstring& file_path, int& type) 782 { 783 string cover_contents; 784 WavPack::File file(file_path.c_str()); 785 auto ape_tag = file.APETag(); 786 GetApeTagAlbumCover(ape_tag, cover_contents, type); 787 return cover_contents; 788 } 789 790 void CTagLibHelper::GetFlacTagInfo(SongInfo& song_info) 791 { 792 FLAC::File file(song_info.file_path.c_str()); 793 if (file.hasID3v1Tag()) 794 song_info.tag_type |= T_ID3V1; 795 if (file.hasID3v2Tag()) 796 song_info.tag_type |= T_ID3V2; 797 auto tag = file.tag(); 798 if (tag != nullptr) 799 { 800 TagToSongInfo(song_info, tag, true); 801 } 802 std::map<std::wstring, std::wstring> property_map; 803 getFlacPropertyMap(file, property_map); 804 OtherPropertyToSongInfo(song_info, property_map); 805 } 806 807 void CTagLibHelper::GetM4aTagInfo(SongInfo& song_info) 808 { 809 MP4::File file(song_info.file_path.c_str()); 810 if (file.hasMP4Tag()) 811 song_info.tag_type |= T_MP4; 812 auto tag = file.tag(); 813 if (tag != nullptr) 814 { 815 TagToSongInfo(song_info, tag, false); 816 } 817 std::map<std::wstring, std::wstring> property_map; 818 getM4aPropertyMap(file, property_map); 819 OtherPropertyToSongInfo(song_info, property_map); 820 } 821 822 void CTagLibHelper::GetMpegTagInfo(SongInfo& song_info) 823 { 824 MPEG::File file(song_info.file_path.c_str()); 825 if (file.hasID3v1Tag()) 826 song_info.tag_type |= T_ID3V1; 827 if (file.hasID3v2Tag()) 828 song_info.tag_type |= T_ID3V2; 829 if (file.hasAPETag()) 830 song_info.tag_type |= T_APE; 831 832 auto tag = file.tag(); 833 if (tag != nullptr) 834 { 835 TagToSongInfo(song_info, tag, true); 836 } 837 std::map<std::wstring, std::wstring> property_map; 838 getMpegPropertyMap(file, property_map); 839 OtherPropertyToSongInfo(song_info, property_map); 840 } 841 842 void CTagLibHelper::GetAsfTagInfo(SongInfo& song_info) 843 { 844 ASF::File file(song_info.file_path.c_str()); 845 auto tag = file.tag(); 846 if (tag != nullptr) 847 { 848 TagToSongInfo(song_info, tag, false); 849 } 850 std::map<std::wstring, std::wstring> property_map; 851 getAsfPropertyMap(file, property_map); 852 OtherPropertyToSongInfo(song_info, property_map); 853 } 854 855 void CTagLibHelper::GetApeTagInfo(SongInfo& song_info) 856 { 857 APE::File file(song_info.file_path.c_str()); 858 if (file.hasID3v1Tag()) 859 song_info.tag_type |= T_ID3V1; 860 if (file.hasAPETag()) 861 song_info.tag_type |= T_APE; 862 863 auto tag = file.tag(); 864 if (tag != nullptr) 865 { 866 TagToSongInfo(song_info, tag, true); 867 } 868 std::map<std::wstring, std::wstring> property_map; 869 getApePropertyMap(file, property_map); 870 OtherPropertyToSongInfo(song_info, property_map); 871 } 872 873 void CTagLibHelper::GetWavTagInfo(SongInfo& song_info) 874 { 875 RIFF::WAV::File file(song_info.file_path.c_str()); 876 if (file.hasID3v2Tag()) 877 song_info.tag_type |= T_ID3V2; 878 if (file.hasInfoTag()) 879 song_info.tag_type |= T_RIFF; 880 auto tag = file.tag(); 881 if (tag != nullptr) 882 { 883 TagToSongInfo(song_info, tag, false); 884 } 885 std::map<std::wstring, std::wstring> property_map; 886 getWavPropertyMap(file, property_map); 887 OtherPropertyToSongInfo(song_info, property_map); 888 } 889 890 void CTagLibHelper::GetOggTagInfo(SongInfo& song_info) 891 { 892 Vorbis::File file(song_info.file_path.c_str()); 893 auto tag = file.tag(); 894 if (tag != nullptr) 895 { 896 TagToSongInfo(song_info, tag, false); 897 } 898 std::map<std::wstring, std::wstring> property_map; 899 getOggPropertyMap(file, property_map); 900 OtherPropertyToSongInfo(song_info, property_map); 901 } 902 903 void CTagLibHelper::GetMpcTagInfo(SongInfo& song_info) 904 { 905 MPC::File file(song_info.file_path.c_str()); 906 if (file.hasAPETag()) 907 song_info.tag_type |= T_APE; 908 if (file.hasID3v1Tag()) 909 song_info.tag_type |= T_ID3V1; 910 auto tag = file.tag(); 911 if (tag != nullptr) 912 { 913 TagToSongInfo(song_info, tag, true); 914 } 915 std::map<std::wstring, std::wstring> property_map; 916 getMpcPropertyMap(file, property_map); 917 OtherPropertyToSongInfo(song_info, property_map); 918 } 919 920 void CTagLibHelper::GetOpusTagInfo(SongInfo& song_info) 921 { 922 Ogg::Opus::File file(song_info.file_path.c_str()); 923 auto tag = file.tag(); 924 if (tag != nullptr) 925 { 926 TagToSongInfo(song_info, tag, false); 927 } 928 std::map<std::wstring, std::wstring> property_map; 929 getOpusPropertyMap(file, property_map); 930 OtherPropertyToSongInfo(song_info, property_map); 931 } 932 933 void CTagLibHelper::GetWavPackTagInfo(SongInfo& song_info) 934 { 935 WavPack::File file(song_info.file_path.c_str()); 936 if (file.hasAPETag()) 937 song_info.tag_type |= T_APE; 938 if (file.hasID3v1Tag()) 939 song_info.tag_type |= T_ID3V1; 940 auto tag = file.tag(); 941 if (tag != nullptr) 942 { 943 TagToSongInfo(song_info, tag, true); 944 } 945 std::map<std::wstring, std::wstring> property_map; 946 getWavPackPropertyMap(file, property_map); 947 OtherPropertyToSongInfo(song_info, property_map); 948 } 949 950 void CTagLibHelper::GetTtaTagInfo(SongInfo& song_info) 951 { 952 TrueAudio::File file(song_info.file_path.c_str()); 953 if (file.hasID3v1Tag()) 954 song_info.tag_type |= T_ID3V1; 955 if (file.hasID3v2Tag()) 956 song_info.tag_type |= T_ID3V2; 957 auto tag = file.tag(); 958 if (tag != nullptr) 959 { 960 TagToSongInfo(song_info, tag, true); 961 } 962 std::map<std::wstring, std::wstring> property_map; 963 getTtaPropertyMap(file, property_map); 964 OtherPropertyToSongInfo(song_info, property_map); 965 } 966 967 void CTagLibHelper::GetAiffTagInfo(SongInfo& song_info) 968 { 969 RIFF::AIFF::File file(song_info.file_path.c_str()); 970 if (file.hasID3v2Tag()) 971 song_info.tag_type |= T_ID3V2; 972 auto tag = file.tag(); 973 if (tag != nullptr) 974 { 975 TagToSongInfo(song_info, tag, false); 976 } 977 std::map<std::wstring, std::wstring> property_map; 978 getAiffPropertyMap(file, property_map); 979 OtherPropertyToSongInfo(song_info, property_map); 980 } 981 982 void CTagLibHelper::GetSpxTagInfo(SongInfo& song_info) 983 { 984 Ogg::Speex::File file(song_info.file_path.c_str()); 985 auto tag = file.tag(); 986 if (tag != nullptr) 987 { 988 TagToSongInfo(song_info, tag, false); 989 } 990 std::map<std::wstring, std::wstring> property_map; 991 getSpxPropertyMap(file, property_map); 992 OtherPropertyToSongInfo(song_info, property_map); 993 } 994 995 void CTagLibHelper::GetAnyFileTagInfo(SongInfo& song_info) 996 { 997 FileRef file(song_info.file_path.c_str()); 998 auto tag = file.tag(); 999 if (tag != nullptr) 1000 { 1001 TagToSongInfo(song_info, tag, false); 1002 } 1003 std::map<std::wstring, std::wstring> property_map; 1004 getAnyFilePropertyMap(file, property_map); 1005 OtherPropertyToSongInfo(song_info, property_map); 1006 } 1007 1008 void CTagLibHelper::GetFlacPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1009 { 1010 FLAC::File file(file_path.c_str()); 1011 getFlacPropertyMap(file, property_map); 1012 } 1013 1014 void CTagLibHelper::GetM4aPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1015 { 1016 MP4::File file(file_path.c_str()); 1017 getM4aPropertyMap(file, property_map); 1018 } 1019 1020 void CTagLibHelper::GetMpegPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1021 { 1022 MPEG::File file(file_path.c_str()); 1023 getMpegPropertyMap(file, property_map); 1024 } 1025 1026 void CTagLibHelper::GetAsfPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1027 { 1028 ASF::File file(file_path.c_str()); 1029 getAsfPropertyMap(file, property_map); 1030 } 1031 1032 void CTagLibHelper::GetApePropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1033 { 1034 APE::File file(file_path.c_str()); 1035 getApePropertyMap(file, property_map); 1036 } 1037 1038 void CTagLibHelper::GetWavPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1039 { 1040 RIFF::WAV::File file(file_path.c_str()); 1041 getWavPropertyMap(file, property_map); 1042 } 1043 1044 void CTagLibHelper::GetOggPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1045 { 1046 Vorbis::File file(file_path.c_str()); 1047 getOggPropertyMap(file, property_map); 1048 } 1049 1050 void CTagLibHelper::GetMpcPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1051 { 1052 MPC::File file(file_path.c_str()); 1053 getMpcPropertyMap(file, property_map); 1054 } 1055 1056 void CTagLibHelper::GetOpusPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1057 { 1058 Ogg::Opus::File file(file_path.c_str()); 1059 getOpusPropertyMap(file, property_map); 1060 } 1061 1062 void CTagLibHelper::GetWavPackPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1063 { 1064 WavPack::File file(file_path.c_str()); 1065 getWavPackPropertyMap(file, property_map); 1066 } 1067 1068 void CTagLibHelper::GetTtaPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1069 { 1070 TrueAudio::File file(file_path.c_str()); 1071 getTtaPropertyMap(file, property_map); 1072 } 1073 1074 void CTagLibHelper::GetAiffPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1075 { 1076 RIFF::AIFF::File file(file_path.c_str()); 1077 getAiffPropertyMap(file, property_map); 1078 } 1079 1080 void CTagLibHelper::GetSpxPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1081 { 1082 Ogg::Speex::File file(file_path.c_str()); 1083 getSpxPropertyMap(file, property_map); 1084 } 1085 1086 void CTagLibHelper::GetAnyFilePropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1087 { 1088 FileRef file(file_path.c_str()); 1089 getAnyFilePropertyMap(file, property_map); 1090 } 1091 1092 std::wstring CTagLibHelper::GetMpegLyric(const std::wstring& file_path) 1093 { 1094 MPEG::File file(file_path.c_str()); 1095 auto id3v2 = file.ID3v2Tag(); 1096 return GetId3v2Lyric(id3v2); 1097 } 1098 1099 std::wstring CTagLibHelper::GetM4aLyric(const std::wstring& file_path) 1100 { 1101 std::wstring lyrics; 1102 MP4::File file(file_path.c_str()); 1103 auto tag = file.tag(); 1104 if (tag != nullptr) 1105 { 1106 auto item_map = file.tag()->itemMap(); 1107 auto lyric_item = item_map[STR_MP4_LYRICS_TAG].toStringList();; 1108 if (!lyric_item.isEmpty()) 1109 lyrics = lyric_item.front().toWString(); 1110 } 1111 return lyrics; 1112 } 1113 1114 std::wstring CTagLibHelper::GetFlacLyric(const std::wstring& file_path) 1115 { 1116 std::wstring lyrics; 1117 FLAC::File file(file_path.c_str()); 1118 auto properties = file.properties(); 1119 if (file.isValid()) 1120 { 1121 auto lyric_item = properties[STR_FLAC_LYRIC_TAG]; 1122 if (!lyric_item.isEmpty()) 1123 { 1124 lyrics = lyric_item.front().toWString(); 1125 } 1126 } 1127 return lyrics; 1128 } 1129 1130 std::wstring CTagLibHelper::GetAsfLyric(const std::wstring& file_path) 1131 { 1132 std::wstring lyrics; 1133 ASF::File file(file_path.c_str()); 1134 if (file.isValid()) 1135 { 1136 auto properties = file.properties(); 1137 auto lyric_item = properties[STR_ASF_LYRIC_TAG]; 1138 if (!lyric_item.isEmpty()) 1139 { 1140 lyrics = lyric_item.front().toWString(); 1141 } 1142 } 1143 return lyrics; 1144 } 1145 1146 1147 std::wstring CTagLibHelper::GetWavLyric(const std::wstring& file_path) 1148 { 1149 RIFF::WAV::File file(file_path.c_str()); 1150 auto id3v2 = file.ID3v2Tag(); 1151 return GetId3v2Lyric(id3v2); 1152 1153 } 1154 1155 bool CTagLibHelper::WriteMpegLyric(const std::wstring& file_path, const std::wstring& lyric_contents) 1156 { 1157 std::wstring lyrics; 1158 MPEG::File file(file_path.c_str()); 1159 auto id3v2 = file.ID3v2Tag(); 1160 WriteId3v2Lyric(id3v2, lyric_contents); 1161 int tags = MPEG::File::ID3v2; 1162 if (file.hasAPETag()) 1163 tags |= MPEG::File::APE; 1164 bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version()); 1165 return saved; 1166 } 1167 1168 bool CTagLibHelper::WriteFlacLyric(const std::wstring& file_path, const std::wstring& lyric_contents) 1169 { 1170 FLAC::File file(file_path.c_str()); 1171 if (file.isValid()) 1172 { 1173 auto properties = file.properties(); 1174 if (lyric_contents.empty()) 1175 { 1176 properties.erase(STR_FLAC_LYRIC_TAG); 1177 } 1178 else 1179 { 1180 StringList lyric_item; 1181 lyric_item.append(lyric_contents); 1182 properties[STR_FLAC_LYRIC_TAG] = lyric_item; 1183 } 1184 file.setProperties(properties); 1185 bool saved = file.save(); 1186 return saved; 1187 } 1188 return false; 1189 } 1190 1191 bool CTagLibHelper::WriteM4aLyric(const std::wstring& file_path, const std::wstring& lyric_contents) 1192 { 1193 MP4::File file(file_path.c_str()); 1194 auto tag = file.tag(); 1195 if (tag != nullptr) 1196 { 1197 if (lyric_contents.empty()) 1198 { 1199 tag->removeItem(STR_MP4_LYRICS_TAG); 1200 } 1201 else 1202 { 1203 StringList lyric_list; 1204 lyric_list.append(lyric_contents); 1205 MP4::Item lyrics_item(lyric_list); 1206 tag->setItem(STR_MP4_LYRICS_TAG, lyrics_item); 1207 } 1208 bool saved = file.save(); 1209 return saved; 1210 } 1211 return false; 1212 } 1213 1214 bool CTagLibHelper::WriteAsfLyric(const std::wstring& file_path, const std::wstring& lyric_contents) 1215 { 1216 ASF::File file(file_path.c_str()); 1217 if (file.isValid()) 1218 { 1219 auto properties = file.properties(); 1220 if (lyric_contents.empty()) 1221 { 1222 properties.erase(STR_ASF_LYRIC_TAG); 1223 } 1224 else 1225 { 1226 StringList lyric_item; 1227 lyric_item.append(lyric_contents); 1228 properties[STR_ASF_LYRIC_TAG] = lyric_item; 1229 } 1230 file.setProperties(properties); 1231 bool saved = file.save(); 1232 return saved; 1233 } 1234 return false; 1235 } 1236 1237 bool CTagLibHelper::WriteWavLyric(const std::wstring& file_path, const std::wstring& lyric_contents) 1238 { 1239 std::wstring lyrics; 1240 RIFF::WAV::File file(file_path.c_str()); 1241 auto id3v2 = file.ID3v2Tag(); 1242 WriteId3v2Lyric(id3v2, lyric_contents); 1243 bool saved = file.save(RIFF::WAV::File::TagTypes::AllTags, File::StripOthers, GetWriteId3v2Version()); 1244 return saved; 1245 } 1246 1247 bool CTagLibHelper::WriteMp3AlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist) 1248 { 1249 MPEG::File file(file_path.c_str()); 1250 if (!file.isValid()) 1251 return false; 1252 1253 //先删除专辑封面 1254 if (remove_exist) 1255 { 1256 auto id3v2tag = file.ID3v2Tag(); 1257 DeleteId3v2AlbumCover(id3v2tag); 1258 } 1259 if (!album_cover_path.empty()) 1260 { 1261 auto id3v2tag = file.ID3v2Tag(true); 1262 WriteId3v2AlbumCover(id3v2tag, album_cover_path); 1263 } 1264 int tags = MPEG::File::ID3v2; 1265 if (file.hasAPETag()) 1266 tags |= MPEG::File::APE; 1267 bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version()); 1268 return saved; 1269 } 1270 1271 bool CTagLibHelper::WriteFlacAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist) 1272 { 1273 FLAC::File file(file_path.c_str()); 1274 if (!file.isValid()) 1275 return false; 1276 1277 //先删除专辑封面 1278 if (remove_exist) 1279 { 1280 file.removePictures(); 1281 } 1282 1283 if (!album_cover_path.empty()) 1284 { 1285 ByteVector pic_data; 1286 FileToByteVector(pic_data, album_cover_path); 1287 FLAC::Picture* newpic = new FLAC::Picture(); 1288 newpic->setType(FLAC::Picture::FrontCover); 1289 newpic->setData(pic_data); 1290 std::wstring ext = CFilePathHelper(album_cover_path).GetFileExtension(); 1291 newpic->setMimeType(L"image/" + ext); 1292 file.addPicture(newpic); 1293 } 1294 bool saved = file.save(); 1295 return saved; 1296 } 1297 1298 bool CTagLibHelper::WriteM4aAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1299 { 1300 MP4::File file(file_path.c_str()); 1301 if (!file.isValid()) 1302 return false; 1303 1304 auto tag = file.tag(); 1305 if (tag == nullptr) 1306 return false; 1307 1308 if (remove_exist) 1309 { 1310 if (tag->contains(STR_MP4_COVER_TAG)) 1311 { 1312 tag->removeItem(STR_MP4_COVER_TAG); 1313 } 1314 } 1315 1316 if (!album_cover_path.empty()) 1317 { 1318 ByteVector pic_data; 1319 FileToByteVector(pic_data, album_cover_path); 1320 MP4::CoverArt::Format format = MP4::CoverArt::Format::Unknown; 1321 std::wstring ext = CFilePathHelper(album_cover_path).GetFileExtension(); 1322 if (ext == L"jpg" || ext == L"jpeg") 1323 format = MP4::CoverArt::Format::JPEG; 1324 else if (ext == L"png") 1325 format = MP4::CoverArt::Format::PNG; 1326 else if (ext == L"gif") 1327 format = MP4::CoverArt::Format::GIF; 1328 else if (ext == L"bmp") 1329 format = MP4::CoverArt::Format::BMP; 1330 MP4::CoverArt cover_item(format, pic_data); 1331 1332 auto cover_item_list = tag->item(STR_MP4_COVER_TAG).toCoverArtList(); 1333 cover_item_list.append(cover_item); 1334 tag->setItem(STR_MP4_COVER_TAG, cover_item_list); 1335 } 1336 bool saved = file.save(); 1337 return saved; 1338 } 1339 1340 bool CTagLibHelper::WriteAsfAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1341 { 1342 ASF::File file(file_path.c_str()); 1343 if (!file.isValid()) 1344 return false; 1345 1346 auto tag = file.tag(); 1347 if (tag == nullptr) 1348 return false; 1349 1350 if (remove_exist) 1351 { 1352 if (tag->contains(STR_ASF_COVER_TAG)) 1353 { 1354 tag->removeItem(STR_ASF_COVER_TAG); 1355 } 1356 } 1357 1358 if (!album_cover_path.empty()) 1359 { 1360 ByteVector pic_data; 1361 FileToByteVector(pic_data, album_cover_path); 1362 1363 ASF::Picture picture; 1364 std::wstring str_mine_type = L"image/" + CFilePathHelper(album_cover_path).GetFileExtension(); 1365 picture.setMimeType(str_mine_type); 1366 picture.setType(ASF::Picture::FrontCover); 1367 picture.setPicture(pic_data); 1368 tag->setAttribute(STR_ASF_COVER_TAG, picture); 1369 } 1370 bool saved = file.save(); 1371 return saved; 1372 } 1373 1374 bool CTagLibHelper::WriteWavAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1375 { 1376 RIFF::WAV::File file(file_path.c_str()); 1377 if (!file.isValid()) 1378 return false; 1379 1380 //先删除专辑封面 1381 auto id3v2tag = file.ID3v2Tag(); 1382 if (remove_exist) 1383 { 1384 DeleteId3v2AlbumCover(id3v2tag); 1385 } 1386 if (!album_cover_path.empty()) 1387 { 1388 WriteId3v2AlbumCover(id3v2tag, album_cover_path); 1389 } 1390 bool saved = file.save(RIFF::WAV::File::AllTags, File::StripOthers, GetWriteId3v2Version()); 1391 return saved; 1392 } 1393 1394 bool CTagLibHelper::WriteTtaAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1395 { 1396 TrueAudio::File file(file_path.c_str()); 1397 if (!file.isValid()) 1398 return false; 1399 1400 if (remove_exist) 1401 { 1402 auto id3v2tag = file.ID3v2Tag(); 1403 DeleteId3v2AlbumCover(id3v2tag); 1404 } 1405 if (!album_cover_path.empty()) 1406 { 1407 auto id3v2tag = file.ID3v2Tag(true); 1408 WriteId3v2AlbumCover(id3v2tag, album_cover_path); 1409 } 1410 bool saved = file.save(); 1411 return saved; 1412 return false; 1413 } 1414 1415 bool CTagLibHelper::WriteApeAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1416 { 1417 APE::File file(file_path.c_str()); 1418 if (!file.isValid()) 1419 return false; 1420 1421 auto tag = file.APETag(true); 1422 WriteApeTagAlbumCover(tag, album_cover_path, remove_exist); 1423 bool saved = file.save(); 1424 return saved; 1425 } 1426 1427 bool CTagLibHelper::WriteOggAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1428 { 1429 Ogg::Vorbis::File file(file_path.c_str()); 1430 if (!file.isValid()) 1431 return false; 1432 1433 auto tag = file.tag(); 1434 if (tag != nullptr) 1435 { 1436 WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist); 1437 bool saved = file.save(); 1438 return saved; 1439 } 1440 return false; 1441 } 1442 1443 bool CTagLibHelper::WriteOpusAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist) 1444 { 1445 Ogg::Opus::File file(file_path.c_str()); 1446 if (!file.isValid()) 1447 return false; 1448 1449 auto tag = file.tag(); 1450 if (tag != nullptr) 1451 { 1452 WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist); 1453 bool saved = file.save(); 1454 return saved; 1455 } 1456 return false; 1457 } 1458 1459 bool CTagLibHelper::WriteSpxAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1460 { 1461 Ogg::Speex::File file(file_path.c_str()); 1462 if (!file.isValid()) 1463 return false; 1464 1465 auto tag = file.tag(); 1466 if (tag != nullptr) 1467 { 1468 WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist); 1469 bool saved = file.save(); 1470 return saved; 1471 } 1472 return false; 1473 } 1474 1475 bool CTagLibHelper::WriteAiffAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1476 { 1477 RIFF::AIFF::File file(file_path.c_str()); 1478 if (!file.isValid()) 1479 return false; 1480 1481 //先删除专辑封面 1482 auto id3v2tag = file.tag(); 1483 if (remove_exist) 1484 { 1485 DeleteId3v2AlbumCover(id3v2tag); 1486 } 1487 if (!album_cover_path.empty()) 1488 { 1489 WriteId3v2AlbumCover(id3v2tag, album_cover_path); 1490 } 1491 bool saved = file.save(GetWriteId3v2Version()); 1492 return saved; 1493 } 1494 1495 bool CTagLibHelper::WriteMpcAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1496 { 1497 MPC::File file(file_path.c_str()); 1498 if (!file.isValid()) 1499 return false; 1500 1501 auto tag = file.APETag(true); 1502 WriteApeTagAlbumCover(tag, album_cover_path, remove_exist); 1503 bool saved = file.save(); 1504 return saved; 1505 } 1506 1507 bool CTagLibHelper::WriteWavePackAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1508 { 1509 WavPack::File file(file_path.c_str()); 1510 if (!file.isValid()) 1511 return false; 1512 1513 auto tag = file.APETag(true); 1514 WriteApeTagAlbumCover(tag, album_cover_path, remove_exist); 1515 bool saved = file.save(); 1516 return saved; 1517 } 1518 1519 bool CTagLibHelper::WriteMpegTag(const SongInfo& song_info) 1520 { 1521 MPEG::File file(song_info.file_path.c_str()); 1522 auto tag = file.tag(); 1523 SongInfoToTag(song_info, tag); 1524 int tags = MPEG::File::ID3v2; 1525 //if (file.hasID3v1Tag()) 1526 // tags |= MPEG::File::ID3v1; 1527 if (file.hasAPETag()) 1528 tags |= MPEG::File::APE; 1529 WriteOtherProperties(song_info, file); 1530 bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version()); 1531 return saved; 1532 } 1533 1534 bool CTagLibHelper::WriteFlacTag(const SongInfo& song_info) 1535 { 1536 FLAC::File file(song_info.file_path.c_str()); 1537 auto tag = file.tag(); 1538 SongInfoToTag(song_info, tag); 1539 WriteOtherProperties(song_info, file); 1540 bool saved = file.save(); 1541 return saved; 1542 } 1543 1544 bool CTagLibHelper::WriteM4aTag(const SongInfo& song_info) 1545 { 1546 MP4::File file(song_info.file_path.c_str()); 1547 auto tag = file.tag(); 1548 SongInfoToTag(song_info, tag); 1549 bool saved = file.save(); 1550 return saved; 1551 } 1552 1553 bool CTagLibHelper::WriteWavTag(const SongInfo& song_info) 1554 { 1555 RIFF::WAV::File file(song_info.file_path.c_str()); 1556 auto tag = file.tag(); 1557 SongInfoToTag(song_info, tag); 1558 WriteOtherProperties(song_info, file); 1559 bool saved = file.save(RIFF::WAV::File::AllTags, File::StripOthers, GetWriteId3v2Version()); 1560 return saved; 1561 } 1562 1563 bool CTagLibHelper::WriteOggTag(const SongInfo& song_info) 1564 { 1565 Vorbis::File file(song_info.file_path.c_str()); 1566 auto tag = file.tag(); 1567 SongInfoToTag(song_info, tag); 1568 WriteOtherProperties(song_info, file); 1569 bool saved = file.save(); 1570 return saved; 1571 } 1572 1573 bool CTagLibHelper::WriteApeTag(const SongInfo& song_info) 1574 { 1575 APE::File file(song_info.file_path.c_str()); 1576 auto tag = file.tag(); 1577 SongInfoToTag(song_info, tag); 1578 WriteOtherProperties(song_info, file); 1579 bool saved = file.save(); 1580 return saved; 1581 } 1582 1583 bool CTagLibHelper::WriteMpcTag(const SongInfo& song_info) 1584 { 1585 MPC::File file(song_info.file_path.c_str()); 1586 auto tag = file.tag(); 1587 SongInfoToTag(song_info, tag); 1588 WriteOtherProperties(song_info, file); 1589 bool saved = file.save(); 1590 return saved; 1591 } 1592 1593 bool CTagLibHelper::WriteOpusTag(const SongInfo& song_info) 1594 { 1595 Ogg::Opus::File file(song_info.file_path.c_str()); 1596 auto tag = file.tag(); 1597 SongInfoToTag(song_info, tag); 1598 WriteOtherProperties(song_info, file); 1599 bool saved = file.save(); 1600 return saved; 1601 } 1602 1603 bool CTagLibHelper::WriteWavPackTag(const SongInfo& song_info) 1604 { 1605 WavPack::File file(song_info.file_path.c_str()); 1606 auto tag = file.tag(); 1607 SongInfoToTag(song_info, tag); 1608 WriteOtherProperties(song_info, file); 1609 bool saved = file.save(); 1610 return saved; 1611 } 1612 1613 bool CTagLibHelper::WriteTtaTag(const SongInfo& song_info) 1614 { 1615 TrueAudio::File file(song_info.file_path.c_str()); 1616 auto tag = file.tag(); 1617 SongInfoToTag(song_info, tag); 1618 WriteOtherProperties(song_info, file); 1619 bool saved = file.save(); 1620 return saved; 1621 } 1622 1623 bool CTagLibHelper::WriteAiffTag(const SongInfo& song_info) 1624 { 1625 RIFF::AIFF::File file(song_info.file_path.c_str()); 1626 auto tag = file.tag(); 1627 SongInfoToTag(song_info, tag); 1628 WriteOtherProperties(song_info, file); 1629 bool saved = file.save(GetWriteId3v2Version()); 1630 return saved; 1631 } 1632 1633 bool CTagLibHelper::WriteAsfTag(const SongInfo& song_info) 1634 { 1635 ASF::File file(song_info.file_path.c_str()); 1636 auto tag = file.tag(); 1637 SongInfoToTag(song_info, tag); 1638 WriteOtherProperties(song_info, file); 1639 bool saved = file.save(); 1640 return saved; 1641 } 1642 1643 bool CTagLibHelper::WriteSpxTag(const SongInfo& song_info) 1644 { 1645 Ogg::Speex::File file(song_info.file_path.c_str()); 1646 auto tag = file.tag(); 1647 SongInfoToTag(song_info, tag); 1648 WriteOtherProperties(song_info, file); 1649 bool saved = file.save(); 1650 return saved; 1651 } 1652 1653 std::wstring CTagLibHelper::GetApeCue(const std::wstring& file_path) 1654 { 1655 std::wstring cue_contents; 1656 APE::File file(file_path.c_str()); 1657 auto tag = file.APETag(); 1658 if (tag != nullptr) 1659 { 1660 auto item_list_map = tag->itemListMap(); 1661 auto cue_item = item_list_map[STR_APE_CUE_TAG]; 1662 cue_contents = cue_item.toString().toWString(); 1663 } 1664 return cue_contents; 1665 } 1666 1667 int CTagLibHelper::GetMepgRating(const std::wstring& file_path) 1668 { 1669 MPEG::File file(file_path.c_str()); 1670 auto id3v2 = file.ID3v2Tag(); 1671 return GetId3v2Rating(id3v2); 1672 } 1673 1674 int CTagLibHelper::GetFlacRating(const std::wstring& file_path) 1675 { 1676 FLAC::File file(file_path.c_str()); 1677 auto properties = file.properties(); 1678 if (file.isValid()) 1679 { 1680 auto rating_item = properties[STR_FLAC_RATING_TAG]; 1681 if (!rating_item.isEmpty()) 1682 { 1683 int rating = _wtoi(rating_item.front().toWString().c_str()); 1684 return rating; 1685 } 1686 } 1687 return 0; 1688 1689 } 1690 1691 int CTagLibHelper::GetWmaRating(const std::wstring& file_path) 1692 { 1693 int rate{}; 1694 ASF::File file(file_path.c_str()); 1695 if (file.isValid()) 1696 { 1697 ASF::Tag* tag = file.tag(); 1698 auto rating_str = tag->rating(); 1699 rate = _wtoi(rating_str.toWString().c_str()); 1700 } 1701 return rate; 1702 } 1703 1704 bool CTagLibHelper::WriteMpegRating(const std::wstring& file_path, int rate) 1705 { 1706 MPEG::File file(file_path.c_str()); 1707 auto id3v2 = file.ID3v2Tag(); 1708 WriteId3v2Rating(id3v2, rate); 1709 int tags = MPEG::File::ID3v2; 1710 if (file.hasAPETag()) 1711 tags |= MPEG::File::APE; 1712 bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version()); 1713 return saved; 1714 } 1715 1716 bool CTagLibHelper::WriteFlacRating(const std::wstring& file_path, int rate) 1717 { 1718 FLAC::File file(file_path.c_str()); 1719 if (file.isValid()) 1720 { 1721 auto properties = file.properties(); 1722 properties[STR_FLAC_RATING_TAG].clear(); 1723 properties[STR_FLAC_RATING_TAG].append(std::to_wstring(rate).c_str()); 1724 file.setProperties(properties); 1725 bool saved = file.save(); 1726 return saved; 1727 } 1728 return false; 1729 } 1730 1731 bool CTagLibHelper::WriteWmaRating(const std::wstring& file_path, int rate) 1732 { 1733 ASF::File file(file_path.c_str()); 1734 if (file.isValid()) 1735 { 1736 auto tag = file.tag(); 1737 tag->setRating(std::to_wstring(rate)); 1738 bool saved = file.save(); 1739 return saved; 1740 } 1741 return false; 1742 } 1743 1744 TagLib::ID3v2::Version CTagLibHelper::GetWriteId3v2Version() 1745 { 1746 return (m_write_id3v2_3 ? ID3v2::Version::v3 : ID3v2::Version::v4); 1747 } 1748