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 properties["ALBUMARTIST"].clear(); 390 properties["DISCNUMBER"].clear(); 391 if (!song_info.album_artist.empty()) 392 properties["ALBUMARTIST"].append(song_info.album_artist); 393 if (song_info.disc_num != 0) 394 properties["DISCNUMBER"].append(std::to_wstring(static_cast<int>(song_info.disc_num))); 395 file.setProperties(properties); 396 } 397 398 //解析Windows资源管理器设置的分级信息 399 static int ParseAudioRating(int rate_raw) 400 { 401 //使用Windows资源管理器设置了分级后,POPM字段的内容为以下格式: 402 //Windows Media Player 9 Series rating=196 counter=0 403 //其中rating后面的数字为分级,rating与分级的对应关系如下所示 404 /* 405 rating | 分级 406 ---------|------------ 407 255 | 5 408 196 | 4 409 128 | 3 410 64 | 2 411 1 | 1 412 */ 413 414 //根据分级转换成1~5星 415 if (rate_raw == 1) 416 return 1; 417 else if (rate_raw <= 64) 418 return 2; 419 else if (rate_raw <= 128) 420 return 3; 421 else if (rate_raw <= 196) 422 return 4; 423 else if (rate_raw <= 255) 424 return 5; 425 return 0; 426 } 427 428 static int GenerateAudioRating(int rate) 429 { 430 switch (rate) 431 { 432 case 1: 433 return 1; 434 case 2: 435 return 64; 436 case 3: 437 return 128; 438 case 4: 439 return 196; 440 case 5: 441 return 255; 442 default: 443 return 0; 444 } 445 } 446 447 static int GetId3v2Rating(ID3v2::Tag* id3v2) 448 { 449 if (id3v2 != nullptr) 450 { 451 auto frame_list_map = id3v2->frameListMap(); 452 auto rate_frame = frame_list_map[STR_ID3V2_RATEING_TAG]; 453 if (!rate_frame.isEmpty()) 454 { 455 ID3v2::PopularimeterFrame* pFrame = dynamic_cast<ID3v2::PopularimeterFrame*>(rate_frame.front()); 456 if (pFrame != nullptr) 457 { 458 int rate_raw = pFrame->rating(); 459 return ParseAudioRating(rate_raw); 460 } 461 } 462 } 463 return 0; 464 } 465 466 static void WriteId3v2Rating(ID3v2::Tag* id3v2, int rate) 467 { 468 if (id3v2 != nullptr) 469 { 470 auto frameListMap = id3v2->frameListMap(); 471 472 //先删除POPM帧 473 auto rate_frame_list = id3v2->frameListMap()[STR_ID3V2_RATEING_TAG]; 474 if (!rate_frame_list.isEmpty()) 475 { 476 for (auto frame : rate_frame_list) 477 id3v2->removeFrame(frame); 478 } 479 480 if (rate >= 1 && rate <= 5) 481 { 482 ID3v2::PopularimeterFrame* rate_frame = new ID3v2::PopularimeterFrame(); 483 int rate_raw = GenerateAudioRating(rate); 484 rate_frame->setRating(rate_raw); 485 id3v2->addFrame(rate_frame); 486 } 487 } 488 } 489 490 static void getFlacPropertyMap(FLAC::File& file, std::map<std::wstring, std::wstring>& property_map) 491 { 492 if (file.hasXiphComment()) 493 GetTagPropertyMap(file.xiphComment(), property_map); 494 if (file.hasID3v2Tag()) 495 GetTagPropertyMap(file.ID3v2Tag(), property_map); 496 if (file.hasID3v1Tag()) 497 GetTagPropertyMap(file.ID3v1Tag(), property_map); 498 } 499 500 static void getM4aPropertyMap(MP4::File& file, std::map<std::wstring, std::wstring>& property_map) 501 { 502 auto tag = file.tag(); 503 GetTagPropertyMap(tag, property_map); 504 } 505 506 static void getMpegPropertyMap(MPEG::File& file, std::map<std::wstring, std::wstring>& property_map) 507 { 508 if (file.hasID3v2Tag()) 509 GetTagPropertyMap(file.ID3v2Tag(), property_map); 510 if (file.hasAPETag()) 511 GetTagPropertyMap(file.APETag(), property_map); 512 if (file.hasID3v1Tag()) 513 GetTagPropertyMap(file.ID3v1Tag(), property_map); 514 } 515 516 static void getAsfPropertyMap(ASF::File& file, std::map<std::wstring, std::wstring>& property_map) 517 { 518 auto tag = file.tag(); 519 GetTagPropertyMap(tag, property_map); 520 } 521 522 static void getApePropertyMap(APE::File& file, std::map<std::wstring, std::wstring>& property_map) 523 { 524 if (file.hasAPETag()) 525 GetTagPropertyMap(file.APETag(), property_map); 526 if (file.hasID3v1Tag()) 527 GetTagPropertyMap(file.ID3v1Tag(), property_map); 528 } 529 530 static void getWavPropertyMap(RIFF::WAV::File& file, std::map<std::wstring, std::wstring>& property_map) 531 { 532 if (file.hasID3v2Tag()) 533 GetTagPropertyMap(file.ID3v2Tag(), property_map); 534 if (file.hasInfoTag()) 535 GetTagPropertyMap(file.InfoTag(), property_map); 536 } 537 538 static void getOggPropertyMap(Vorbis::File& file, std::map<std::wstring, std::wstring>& property_map) 539 { 540 auto tag = file.tag(); 541 GetTagPropertyMap(tag, property_map); 542 } 543 544 static void getMpcPropertyMap(MPC::File& file, std::map<std::wstring, std::wstring>& property_map) 545 { 546 if (file.hasAPETag()) 547 GetTagPropertyMap(file.APETag(), property_map); 548 if (file.hasID3v1Tag()) 549 GetTagPropertyMap(file.ID3v1Tag(), property_map); 550 } 551 552 static void getOpusPropertyMap(Ogg::Opus::File& file, std::map<std::wstring, std::wstring>& property_map) 553 { 554 auto tag = file.tag(); 555 GetTagPropertyMap(tag, property_map); 556 } 557 558 static void getWavPackPropertyMap(WavPack::File& file, std::map<std::wstring, std::wstring>& property_map) 559 { 560 if (file.hasAPETag()) 561 GetTagPropertyMap(file.APETag(), property_map); 562 if (file.hasID3v1Tag()) 563 GetTagPropertyMap(file.ID3v1Tag(), property_map); 564 } 565 566 static void getTtaPropertyMap(TrueAudio::File& file, std::map<std::wstring, std::wstring>& property_map) 567 { 568 if (file.hasID3v2Tag()) 569 GetTagPropertyMap(file.ID3v2Tag(), property_map); 570 if (file.hasID3v1Tag()) 571 GetTagPropertyMap(file.ID3v1Tag(), property_map); 572 } 573 574 static void getAiffPropertyMap(RIFF::AIFF::File& file, std::map<std::wstring, std::wstring>& property_map) 575 { 576 auto tag = file.tag(); 577 GetTagPropertyMap(tag, property_map); 578 } 579 580 static void getSpxPropertyMap(Ogg::Speex::File& file, std::map<std::wstring, std::wstring>& property_map) 581 { 582 auto tag = file.tag(); 583 GetTagPropertyMap(tag, property_map); 584 } 585 586 static void getAnyFilePropertyMap(FileRef& file, std::map<std::wstring, std::wstring>& property_map) 587 { 588 auto tag = file.tag(); 589 GetTagPropertyMap(tag, property_map); 590 } 591 592 593 /////////////////////////////////////////////////////////////////////////////////// 594 /////////////////////////////////////////////////////////////////////////////////// 595 /////////////////////////////////////////////////////////////////////////////////// 596 597 bool CTagLibHelper::m_write_id3v2_3{ false }; 598 599 CTagLibHelper::CTagLibHelper() 600 { 601 } 602 603 CTagLibHelper::~CTagLibHelper() 604 { 605 } 606 607 void CTagLibHelper::SetWriteId3V2_3(bool write_id3v2_3) 608 { 609 m_write_id3v2_3 = write_id3v2_3; 610 } 611 612 string CTagLibHelper::GetM4aAlbumCover(const std::wstring& file_path, int& type) 613 { 614 string cover_contents; 615 MP4::File file(file_path.c_str()); 616 auto tag = file.tag(); 617 if (tag != nullptr) 618 { 619 auto cover_item = tag->item(STR_MP4_COVER_TAG).toCoverArtList(); 620 if (!cover_item.isEmpty()) 621 { 622 const auto& pic_data = cover_item.front().data(); 623 //获取专辑封面 624 cover_contents.assign(pic_data.data(), pic_data.size()); 625 626 //获取封面格式 627 switch (cover_item.front().format()) 628 { 629 case MP4::CoverArt::JPEG: 630 type = 0; 631 break; 632 case MP4::CoverArt::PNG: 633 type = 1; 634 break; 635 case MP4::CoverArt::BMP: 636 type = 3; 637 break; 638 case MP4::CoverArt::GIF: 639 type = 2; 640 break; 641 default: 642 type = -1; 643 break; 644 } 645 } 646 } 647 return cover_contents; 648 } 649 650 string CTagLibHelper::GetFlacAlbumCover(const std::wstring& file_path, int& type) 651 { 652 string cover_contents; 653 FLAC::File file(file_path.c_str()); 654 const auto& cover_list = file.pictureList(); 655 if (!cover_list.isEmpty()) 656 { 657 auto pic = cover_list.front(); 658 if (pic != nullptr) 659 { 660 const auto& pic_data = pic->data(); 661 //获取专辑封面 662 cover_contents.assign(pic_data.data(), pic_data.size()); 663 664 std::wstring img_type = pic->mimeType().toCWString(); 665 type = GetPicType(img_type); 666 } 667 } 668 return cover_contents; 669 } 670 671 string CTagLibHelper::GetMp3AlbumCover(const std::wstring& file_path, int& type) 672 { 673 string cover_contents; 674 MPEG::File file(file_path.c_str()); 675 auto id3v2 = file.ID3v2Tag(); 676 GetId3v2AlbumCover(id3v2, cover_contents, type); 677 return cover_contents; 678 } 679 680 string CTagLibHelper::GetAsfAlbumCover(const std::wstring& file_path, int& type) 681 { 682 string cover_contents; 683 ASF::File file(file_path.c_str()); 684 auto tag = file.tag(); 685 if (tag != nullptr) 686 { 687 ASF::AttributeList attr = tag->attribute("WM/Picture"); 688 if (!attr.isEmpty()) 689 { 690 ASF::Picture picture = attr.front().toPicture(); 691 auto pic_data = picture.picture(); 692 cover_contents.assign(pic_data.data(), pic_data.size()); 693 std::wstring img_type = picture.mimeType().toCWString(); 694 type = GetPicType(img_type); 695 } 696 } 697 return cover_contents; 698 } 699 700 string CTagLibHelper::GetWavAlbumCover(const std::wstring& file_path, int& type) 701 { 702 string cover_contents; 703 RIFF::WAV::File file(file_path.c_str()); 704 auto id3v2 = file.ID3v2Tag(); 705 GetId3v2AlbumCover(id3v2, cover_contents, type); 706 return cover_contents; 707 } 708 709 string CTagLibHelper::GetTtaAlbumCover(const std::wstring& file_path, int& type) 710 { 711 string cover_contents; 712 TrueAudio::File file(file_path.c_str()); 713 auto id3v2 = file.ID3v2Tag(); 714 GetId3v2AlbumCover(id3v2, cover_contents, type); 715 return cover_contents; 716 } 717 718 string CTagLibHelper::GetApeAlbumCover(const std::wstring& file_path, int& type) 719 { 720 string cover_contents; 721 APE::File file(file_path.c_str()); 722 auto tag = file.APETag(); 723 GetApeTagAlbumCover(tag, cover_contents, type); 724 return cover_contents; 725 } 726 727 728 string CTagLibHelper::GetOggAlbumCover(const std::wstring& file_path, int& type) 729 { 730 string cover_contents; 731 Ogg::Vorbis::File file(file_path.c_str()); 732 auto tag = file.tag(); 733 if (tag != nullptr) 734 { 735 GetXiphCommentAlbumCover(tag, cover_contents, type); 736 } 737 return cover_contents; 738 } 739 740 string CTagLibHelper::GetOpusAlbumCover(const std::wstring& file_path, int& type) 741 { 742 string cover_contents; 743 Ogg::Opus::File file(file_path.c_str()); 744 auto tag = file.tag(); 745 if (tag != nullptr) 746 { 747 GetXiphCommentAlbumCover(tag, cover_contents, type); 748 } 749 return cover_contents; 750 } 751 752 string CTagLibHelper::GetSpxAlbumCover(const std::wstring& file_path, int& type) 753 { 754 string cover_contents; 755 Ogg::Speex::File file(file_path.c_str()); 756 auto tag = file.tag(); 757 if (tag != nullptr) 758 { 759 GetXiphCommentAlbumCover(tag, cover_contents, type); 760 } 761 return cover_contents; 762 } 763 764 string CTagLibHelper::GetAiffAlbumCover(const std::wstring& file_path, int& type) 765 { 766 string cover_contents; 767 RIFF::AIFF::File file(file_path.c_str()); 768 auto id3v2 = file.tag(); 769 GetId3v2AlbumCover(id3v2, cover_contents, type); 770 return cover_contents; 771 772 } 773 774 string CTagLibHelper::GetMpcAlbumCover(const std::wstring& file_path, int& type) 775 { 776 string cover_contents; 777 MPC::File file(file_path.c_str()); 778 auto ape_tag = file.APETag(); 779 GetApeTagAlbumCover(ape_tag, cover_contents, type); 780 return cover_contents; 781 } 782 783 string CTagLibHelper::GetWavePackAlbumCover(const std::wstring& file_path, int& type) 784 { 785 string cover_contents; 786 WavPack::File file(file_path.c_str()); 787 auto ape_tag = file.APETag(); 788 GetApeTagAlbumCover(ape_tag, cover_contents, type); 789 return cover_contents; 790 } 791 792 void CTagLibHelper::GetFlacTagInfo(SongInfo& song_info) 793 { 794 FLAC::File file(song_info.file_path.c_str()); 795 if (file.hasID3v1Tag()) 796 song_info.tag_type |= T_ID3V1; 797 if (file.hasID3v2Tag()) 798 song_info.tag_type |= T_ID3V2; 799 auto tag = file.tag(); 800 if (tag != nullptr) 801 { 802 TagToSongInfo(song_info, tag, true); 803 } 804 std::map<std::wstring, std::wstring> property_map; 805 getFlacPropertyMap(file, property_map); 806 OtherPropertyToSongInfo(song_info, property_map); 807 } 808 809 void CTagLibHelper::GetM4aTagInfo(SongInfo& song_info) 810 { 811 MP4::File file(song_info.file_path.c_str()); 812 if (file.hasMP4Tag()) 813 song_info.tag_type |= T_MP4; 814 auto tag = file.tag(); 815 if (tag != nullptr) 816 { 817 TagToSongInfo(song_info, tag, false); 818 } 819 std::map<std::wstring, std::wstring> property_map; 820 getM4aPropertyMap(file, property_map); 821 OtherPropertyToSongInfo(song_info, property_map); 822 } 823 824 void CTagLibHelper::GetMpegTagInfo(SongInfo& song_info) 825 { 826 MPEG::File file(song_info.file_path.c_str()); 827 if (file.hasID3v1Tag()) 828 song_info.tag_type |= T_ID3V1; 829 if (file.hasID3v2Tag()) 830 song_info.tag_type |= T_ID3V2; 831 if (file.hasAPETag()) 832 song_info.tag_type |= T_APE; 833 834 auto tag = file.tag(); 835 if (tag != nullptr) 836 { 837 TagToSongInfo(song_info, tag, true); 838 } 839 std::map<std::wstring, std::wstring> property_map; 840 getMpegPropertyMap(file, property_map); 841 OtherPropertyToSongInfo(song_info, property_map); 842 } 843 844 void CTagLibHelper::GetAsfTagInfo(SongInfo& song_info) 845 { 846 ASF::File file(song_info.file_path.c_str()); 847 auto tag = file.tag(); 848 if (tag != nullptr) 849 { 850 TagToSongInfo(song_info, tag, false); 851 } 852 std::map<std::wstring, std::wstring> property_map; 853 getAsfPropertyMap(file, property_map); 854 OtherPropertyToSongInfo(song_info, property_map); 855 } 856 857 void CTagLibHelper::GetApeTagInfo(SongInfo& song_info) 858 { 859 APE::File file(song_info.file_path.c_str()); 860 if (file.hasID3v1Tag()) 861 song_info.tag_type |= T_ID3V1; 862 if (file.hasAPETag()) 863 song_info.tag_type |= T_APE; 864 865 auto tag = file.tag(); 866 if (tag != nullptr) 867 { 868 TagToSongInfo(song_info, tag, true); 869 } 870 std::map<std::wstring, std::wstring> property_map; 871 getApePropertyMap(file, property_map); 872 OtherPropertyToSongInfo(song_info, property_map); 873 } 874 875 void CTagLibHelper::GetWavTagInfo(SongInfo& song_info) 876 { 877 RIFF::WAV::File file(song_info.file_path.c_str()); 878 if (file.hasID3v2Tag()) 879 song_info.tag_type |= T_ID3V2; 880 if (file.hasInfoTag()) 881 song_info.tag_type |= T_RIFF; 882 auto tag = file.tag(); 883 if (tag != nullptr) 884 { 885 TagToSongInfo(song_info, tag, false); 886 } 887 std::map<std::wstring, std::wstring> property_map; 888 getWavPropertyMap(file, property_map); 889 OtherPropertyToSongInfo(song_info, property_map); 890 } 891 892 void CTagLibHelper::GetOggTagInfo(SongInfo& song_info) 893 { 894 Vorbis::File file(song_info.file_path.c_str()); 895 auto tag = file.tag(); 896 if (tag != nullptr) 897 { 898 TagToSongInfo(song_info, tag, false); 899 } 900 std::map<std::wstring, std::wstring> property_map; 901 getOggPropertyMap(file, property_map); 902 OtherPropertyToSongInfo(song_info, property_map); 903 } 904 905 void CTagLibHelper::GetMpcTagInfo(SongInfo& song_info) 906 { 907 MPC::File file(song_info.file_path.c_str()); 908 if (file.hasAPETag()) 909 song_info.tag_type |= T_APE; 910 if (file.hasID3v1Tag()) 911 song_info.tag_type |= T_ID3V1; 912 auto tag = file.tag(); 913 if (tag != nullptr) 914 { 915 TagToSongInfo(song_info, tag, true); 916 } 917 std::map<std::wstring, std::wstring> property_map; 918 getMpcPropertyMap(file, property_map); 919 OtherPropertyToSongInfo(song_info, property_map); 920 } 921 922 void CTagLibHelper::GetOpusTagInfo(SongInfo& song_info) 923 { 924 Ogg::Opus::File file(song_info.file_path.c_str()); 925 auto tag = file.tag(); 926 if (tag != nullptr) 927 { 928 TagToSongInfo(song_info, tag, false); 929 } 930 std::map<std::wstring, std::wstring> property_map; 931 getOpusPropertyMap(file, property_map); 932 OtherPropertyToSongInfo(song_info, property_map); 933 } 934 935 void CTagLibHelper::GetWavPackTagInfo(SongInfo& song_info) 936 { 937 WavPack::File file(song_info.file_path.c_str()); 938 if (file.hasAPETag()) 939 song_info.tag_type |= T_APE; 940 if (file.hasID3v1Tag()) 941 song_info.tag_type |= T_ID3V1; 942 auto tag = file.tag(); 943 if (tag != nullptr) 944 { 945 TagToSongInfo(song_info, tag, true); 946 } 947 std::map<std::wstring, std::wstring> property_map; 948 getWavPackPropertyMap(file, property_map); 949 OtherPropertyToSongInfo(song_info, property_map); 950 } 951 952 void CTagLibHelper::GetTtaTagInfo(SongInfo& song_info) 953 { 954 TrueAudio::File file(song_info.file_path.c_str()); 955 if (file.hasID3v1Tag()) 956 song_info.tag_type |= T_ID3V1; 957 if (file.hasID3v2Tag()) 958 song_info.tag_type |= T_ID3V2; 959 auto tag = file.tag(); 960 if (tag != nullptr) 961 { 962 TagToSongInfo(song_info, tag, true); 963 } 964 std::map<std::wstring, std::wstring> property_map; 965 getTtaPropertyMap(file, property_map); 966 OtherPropertyToSongInfo(song_info, property_map); 967 } 968 969 void CTagLibHelper::GetAiffTagInfo(SongInfo& song_info) 970 { 971 RIFF::AIFF::File file(song_info.file_path.c_str()); 972 if (file.hasID3v2Tag()) 973 song_info.tag_type |= T_ID3V2; 974 auto tag = file.tag(); 975 if (tag != nullptr) 976 { 977 TagToSongInfo(song_info, tag, false); 978 } 979 std::map<std::wstring, std::wstring> property_map; 980 getAiffPropertyMap(file, property_map); 981 OtherPropertyToSongInfo(song_info, property_map); 982 } 983 984 void CTagLibHelper::GetSpxTagInfo(SongInfo& song_info) 985 { 986 Ogg::Speex::File file(song_info.file_path.c_str()); 987 auto tag = file.tag(); 988 if (tag != nullptr) 989 { 990 TagToSongInfo(song_info, tag, false); 991 } 992 std::map<std::wstring, std::wstring> property_map; 993 getSpxPropertyMap(file, property_map); 994 OtherPropertyToSongInfo(song_info, property_map); 995 } 996 997 void CTagLibHelper::GetAnyFileTagInfo(SongInfo& song_info) 998 { 999 FileRef file(song_info.file_path.c_str()); 1000 auto tag = file.tag(); 1001 if (tag != nullptr) 1002 { 1003 TagToSongInfo(song_info, tag, false); 1004 } 1005 std::map<std::wstring, std::wstring> property_map; 1006 getAnyFilePropertyMap(file, property_map); 1007 OtherPropertyToSongInfo(song_info, property_map); 1008 } 1009 1010 void CTagLibHelper::GetFlacPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1011 { 1012 FLAC::File file(file_path.c_str()); 1013 getFlacPropertyMap(file, property_map); 1014 } 1015 1016 void CTagLibHelper::GetM4aPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1017 { 1018 MP4::File file(file_path.c_str()); 1019 getM4aPropertyMap(file, property_map); 1020 } 1021 1022 void CTagLibHelper::GetMpegPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1023 { 1024 MPEG::File file(file_path.c_str()); 1025 getMpegPropertyMap(file, property_map); 1026 } 1027 1028 void CTagLibHelper::GetAsfPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1029 { 1030 ASF::File file(file_path.c_str()); 1031 getAsfPropertyMap(file, property_map); 1032 } 1033 1034 void CTagLibHelper::GetApePropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1035 { 1036 APE::File file(file_path.c_str()); 1037 getApePropertyMap(file, property_map); 1038 } 1039 1040 void CTagLibHelper::GetWavPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1041 { 1042 RIFF::WAV::File file(file_path.c_str()); 1043 getWavPropertyMap(file, property_map); 1044 } 1045 1046 void CTagLibHelper::GetOggPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1047 { 1048 Vorbis::File file(file_path.c_str()); 1049 getOggPropertyMap(file, property_map); 1050 } 1051 1052 void CTagLibHelper::GetMpcPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1053 { 1054 MPC::File file(file_path.c_str()); 1055 getMpcPropertyMap(file, property_map); 1056 } 1057 1058 void CTagLibHelper::GetOpusPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1059 { 1060 Ogg::Opus::File file(file_path.c_str()); 1061 getOpusPropertyMap(file, property_map); 1062 } 1063 1064 void CTagLibHelper::GetWavPackPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1065 { 1066 WavPack::File file(file_path.c_str()); 1067 getWavPackPropertyMap(file, property_map); 1068 } 1069 1070 void CTagLibHelper::GetTtaPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1071 { 1072 TrueAudio::File file(file_path.c_str()); 1073 getTtaPropertyMap(file, property_map); 1074 } 1075 1076 void CTagLibHelper::GetAiffPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1077 { 1078 RIFF::AIFF::File file(file_path.c_str()); 1079 getAiffPropertyMap(file, property_map); 1080 } 1081 1082 void CTagLibHelper::GetSpxPropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1083 { 1084 Ogg::Speex::File file(file_path.c_str()); 1085 getSpxPropertyMap(file, property_map); 1086 } 1087 1088 void CTagLibHelper::GetAnyFilePropertyMap(const std::wstring& file_path, std::map<std::wstring, std::wstring>& property_map) 1089 { 1090 FileRef file(file_path.c_str()); 1091 getAnyFilePropertyMap(file, property_map); 1092 } 1093 1094 std::wstring CTagLibHelper::GetMpegLyric(const std::wstring& file_path) 1095 { 1096 MPEG::File file(file_path.c_str()); 1097 auto id3v2 = file.ID3v2Tag(); 1098 return GetId3v2Lyric(id3v2); 1099 } 1100 1101 std::wstring CTagLibHelper::GetM4aLyric(const std::wstring& file_path) 1102 { 1103 std::wstring lyrics; 1104 MP4::File file(file_path.c_str()); 1105 auto tag = file.tag(); 1106 if (tag != nullptr) 1107 { 1108 auto item_map = file.tag()->itemMap(); 1109 auto lyric_item = item_map[STR_MP4_LYRICS_TAG].toStringList();; 1110 if (!lyric_item.isEmpty()) 1111 lyrics = lyric_item.front().toWString(); 1112 } 1113 return lyrics; 1114 } 1115 1116 std::wstring CTagLibHelper::GetFlacLyric(const std::wstring& file_path) 1117 { 1118 std::wstring lyrics; 1119 FLAC::File file(file_path.c_str()); 1120 auto properties = file.properties(); 1121 if (file.isValid()) 1122 { 1123 auto lyric_item = properties[STR_FLAC_LYRIC_TAG]; 1124 if (!lyric_item.isEmpty()) 1125 { 1126 lyrics = lyric_item.front().toWString(); 1127 } 1128 } 1129 return lyrics; 1130 } 1131 1132 std::wstring CTagLibHelper::GetAsfLyric(const std::wstring& file_path) 1133 { 1134 std::wstring lyrics; 1135 ASF::File file(file_path.c_str()); 1136 if (file.isValid()) 1137 { 1138 auto properties = file.properties(); 1139 auto lyric_item = properties[STR_ASF_LYRIC_TAG]; 1140 if (!lyric_item.isEmpty()) 1141 { 1142 lyrics = lyric_item.front().toWString(); 1143 } 1144 } 1145 return lyrics; 1146 } 1147 1148 1149 std::wstring CTagLibHelper::GetWavLyric(const std::wstring& file_path) 1150 { 1151 RIFF::WAV::File file(file_path.c_str()); 1152 auto id3v2 = file.ID3v2Tag(); 1153 return GetId3v2Lyric(id3v2); 1154 1155 } 1156 1157 bool CTagLibHelper::WriteMpegLyric(const std::wstring& file_path, const std::wstring& lyric_contents) 1158 { 1159 std::wstring lyrics; 1160 MPEG::File file(file_path.c_str()); 1161 auto id3v2 = file.ID3v2Tag(); 1162 WriteId3v2Lyric(id3v2, lyric_contents); 1163 int tags = MPEG::File::ID3v2; 1164 if (file.hasAPETag()) 1165 tags |= MPEG::File::APE; 1166 bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version()); 1167 return saved; 1168 } 1169 1170 bool CTagLibHelper::WriteFlacLyric(const std::wstring& file_path, const std::wstring& lyric_contents) 1171 { 1172 FLAC::File file(file_path.c_str()); 1173 if (file.isValid()) 1174 { 1175 auto properties = file.properties(); 1176 if (lyric_contents.empty()) 1177 { 1178 properties.erase(STR_FLAC_LYRIC_TAG); 1179 } 1180 else 1181 { 1182 StringList lyric_item; 1183 lyric_item.append(lyric_contents); 1184 properties[STR_FLAC_LYRIC_TAG] = lyric_item; 1185 } 1186 file.setProperties(properties); 1187 bool saved = file.save(); 1188 return saved; 1189 } 1190 return false; 1191 } 1192 1193 bool CTagLibHelper::WriteM4aLyric(const std::wstring& file_path, const std::wstring& lyric_contents) 1194 { 1195 MP4::File file(file_path.c_str()); 1196 auto tag = file.tag(); 1197 if (tag != nullptr) 1198 { 1199 if (lyric_contents.empty()) 1200 { 1201 tag->removeItem(STR_MP4_LYRICS_TAG); 1202 } 1203 else 1204 { 1205 StringList lyric_list; 1206 lyric_list.append(lyric_contents); 1207 MP4::Item lyrics_item(lyric_list); 1208 tag->setItem(STR_MP4_LYRICS_TAG, lyrics_item); 1209 } 1210 bool saved = file.save(); 1211 return saved; 1212 } 1213 return false; 1214 } 1215 1216 bool CTagLibHelper::WriteAsfLyric(const std::wstring& file_path, const std::wstring& lyric_contents) 1217 { 1218 ASF::File file(file_path.c_str()); 1219 if (file.isValid()) 1220 { 1221 auto properties = file.properties(); 1222 if (lyric_contents.empty()) 1223 { 1224 properties.erase(STR_ASF_LYRIC_TAG); 1225 } 1226 else 1227 { 1228 StringList lyric_item; 1229 lyric_item.append(lyric_contents); 1230 properties[STR_ASF_LYRIC_TAG] = lyric_item; 1231 } 1232 file.setProperties(properties); 1233 bool saved = file.save(); 1234 return saved; 1235 } 1236 return false; 1237 } 1238 1239 bool CTagLibHelper::WriteWavLyric(const std::wstring& file_path, const std::wstring& lyric_contents) 1240 { 1241 std::wstring lyrics; 1242 RIFF::WAV::File file(file_path.c_str()); 1243 auto id3v2 = file.ID3v2Tag(); 1244 WriteId3v2Lyric(id3v2, lyric_contents); 1245 bool saved = file.save(RIFF::WAV::File::TagTypes::AllTags, File::StripOthers, GetWriteId3v2Version()); 1246 return saved; 1247 } 1248 1249 bool CTagLibHelper::WriteMp3AlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist) 1250 { 1251 MPEG::File file(file_path.c_str()); 1252 if (!file.isValid()) 1253 return false; 1254 1255 //先删除专辑封面 1256 if (remove_exist) 1257 { 1258 auto id3v2tag = file.ID3v2Tag(); 1259 DeleteId3v2AlbumCover(id3v2tag); 1260 } 1261 if (!album_cover_path.empty()) 1262 { 1263 auto id3v2tag = file.ID3v2Tag(true); 1264 WriteId3v2AlbumCover(id3v2tag, album_cover_path); 1265 } 1266 int tags = MPEG::File::ID3v2; 1267 if (file.hasAPETag()) 1268 tags |= MPEG::File::APE; 1269 bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version()); 1270 return saved; 1271 } 1272 1273 bool CTagLibHelper::WriteFlacAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist) 1274 { 1275 FLAC::File file(file_path.c_str()); 1276 if (!file.isValid()) 1277 return false; 1278 1279 //先删除专辑封面 1280 if (remove_exist) 1281 { 1282 file.removePictures(); 1283 } 1284 1285 if (!album_cover_path.empty()) 1286 { 1287 ByteVector pic_data; 1288 FileToByteVector(pic_data, album_cover_path); 1289 FLAC::Picture* newpic = new FLAC::Picture(); 1290 newpic->setType(FLAC::Picture::FrontCover); 1291 newpic->setData(pic_data); 1292 std::wstring ext = CFilePathHelper(album_cover_path).GetFileExtension(); 1293 newpic->setMimeType(L"image/" + ext); 1294 file.addPicture(newpic); 1295 } 1296 bool saved = file.save(); 1297 return saved; 1298 } 1299 1300 bool CTagLibHelper::WriteM4aAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1301 { 1302 MP4::File file(file_path.c_str()); 1303 if (!file.isValid()) 1304 return false; 1305 1306 auto tag = file.tag(); 1307 if (tag == nullptr) 1308 return false; 1309 1310 if (remove_exist) 1311 { 1312 if (tag->contains(STR_MP4_COVER_TAG)) 1313 { 1314 tag->removeItem(STR_MP4_COVER_TAG); 1315 } 1316 } 1317 1318 if (!album_cover_path.empty()) 1319 { 1320 ByteVector pic_data; 1321 FileToByteVector(pic_data, album_cover_path); 1322 MP4::CoverArt::Format format = MP4::CoverArt::Format::Unknown; 1323 std::wstring ext = CFilePathHelper(album_cover_path).GetFileExtension(); 1324 if (ext == L"jpg" || ext == L"jpeg") 1325 format = MP4::CoverArt::Format::JPEG; 1326 else if (ext == L"png") 1327 format = MP4::CoverArt::Format::PNG; 1328 else if (ext == L"gif") 1329 format = MP4::CoverArt::Format::GIF; 1330 else if (ext == L"bmp") 1331 format = MP4::CoverArt::Format::BMP; 1332 MP4::CoverArt cover_item(format, pic_data); 1333 1334 auto cover_item_list = tag->item(STR_MP4_COVER_TAG).toCoverArtList(); 1335 cover_item_list.append(cover_item); 1336 tag->setItem(STR_MP4_COVER_TAG, cover_item_list); 1337 } 1338 bool saved = file.save(); 1339 return saved; 1340 } 1341 1342 bool CTagLibHelper::WriteAsfAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1343 { 1344 ASF::File file(file_path.c_str()); 1345 if (!file.isValid()) 1346 return false; 1347 1348 auto tag = file.tag(); 1349 if (tag == nullptr) 1350 return false; 1351 1352 if (remove_exist) 1353 { 1354 if (tag->contains(STR_ASF_COVER_TAG)) 1355 { 1356 tag->removeItem(STR_ASF_COVER_TAG); 1357 } 1358 } 1359 1360 if (!album_cover_path.empty()) 1361 { 1362 ByteVector pic_data; 1363 FileToByteVector(pic_data, album_cover_path); 1364 1365 ASF::Picture picture; 1366 std::wstring str_mine_type = L"image/" + CFilePathHelper(album_cover_path).GetFileExtension(); 1367 picture.setMimeType(str_mine_type); 1368 picture.setType(ASF::Picture::FrontCover); 1369 picture.setPicture(pic_data); 1370 tag->setAttribute(STR_ASF_COVER_TAG, picture); 1371 } 1372 bool saved = file.save(); 1373 return saved; 1374 } 1375 1376 bool CTagLibHelper::WriteWavAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1377 { 1378 RIFF::WAV::File file(file_path.c_str()); 1379 if (!file.isValid()) 1380 return false; 1381 1382 //先删除专辑封面 1383 auto id3v2tag = file.ID3v2Tag(); 1384 if (remove_exist) 1385 { 1386 DeleteId3v2AlbumCover(id3v2tag); 1387 } 1388 if (!album_cover_path.empty()) 1389 { 1390 WriteId3v2AlbumCover(id3v2tag, album_cover_path); 1391 } 1392 bool saved = file.save(RIFF::WAV::File::AllTags, File::StripOthers, GetWriteId3v2Version()); 1393 return saved; 1394 } 1395 1396 bool CTagLibHelper::WriteTtaAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1397 { 1398 TrueAudio::File file(file_path.c_str()); 1399 if (!file.isValid()) 1400 return false; 1401 1402 if (remove_exist) 1403 { 1404 auto id3v2tag = file.ID3v2Tag(); 1405 DeleteId3v2AlbumCover(id3v2tag); 1406 } 1407 if (!album_cover_path.empty()) 1408 { 1409 auto id3v2tag = file.ID3v2Tag(true); 1410 WriteId3v2AlbumCover(id3v2tag, album_cover_path); 1411 } 1412 bool saved = file.save(); 1413 return saved; 1414 return false; 1415 } 1416 1417 bool CTagLibHelper::WriteApeAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1418 { 1419 APE::File file(file_path.c_str()); 1420 if (!file.isValid()) 1421 return false; 1422 1423 auto tag = file.APETag(true); 1424 WriteApeTagAlbumCover(tag, album_cover_path, remove_exist); 1425 bool saved = file.save(); 1426 return saved; 1427 } 1428 1429 bool CTagLibHelper::WriteOggAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1430 { 1431 Ogg::Vorbis::File file(file_path.c_str()); 1432 if (!file.isValid()) 1433 return false; 1434 1435 auto tag = file.tag(); 1436 if (tag != nullptr) 1437 { 1438 WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist); 1439 bool saved = file.save(); 1440 return saved; 1441 } 1442 return false; 1443 } 1444 1445 bool CTagLibHelper::WriteOpusAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist) 1446 { 1447 Ogg::Opus::File file(file_path.c_str()); 1448 if (!file.isValid()) 1449 return false; 1450 1451 auto tag = file.tag(); 1452 if (tag != nullptr) 1453 { 1454 WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist); 1455 bool saved = file.save(); 1456 return saved; 1457 } 1458 return false; 1459 } 1460 1461 bool CTagLibHelper::WriteSpxAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1462 { 1463 Ogg::Speex::File file(file_path.c_str()); 1464 if (!file.isValid()) 1465 return false; 1466 1467 auto tag = file.tag(); 1468 if (tag != nullptr) 1469 { 1470 WriteXiphCommentAlbumCover(tag, album_cover_path, remove_exist); 1471 bool saved = file.save(); 1472 return saved; 1473 } 1474 return false; 1475 } 1476 1477 bool CTagLibHelper::WriteAiffAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1478 { 1479 RIFF::AIFF::File file(file_path.c_str()); 1480 if (!file.isValid()) 1481 return false; 1482 1483 //先删除专辑封面 1484 auto id3v2tag = file.tag(); 1485 if (remove_exist) 1486 { 1487 DeleteId3v2AlbumCover(id3v2tag); 1488 } 1489 if (!album_cover_path.empty()) 1490 { 1491 WriteId3v2AlbumCover(id3v2tag, album_cover_path); 1492 } 1493 bool saved = file.save(GetWriteId3v2Version()); 1494 return saved; 1495 } 1496 1497 bool CTagLibHelper::WriteMpcAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1498 { 1499 MPC::File file(file_path.c_str()); 1500 if (!file.isValid()) 1501 return false; 1502 1503 auto tag = file.APETag(true); 1504 WriteApeTagAlbumCover(tag, album_cover_path, remove_exist); 1505 bool saved = file.save(); 1506 return saved; 1507 } 1508 1509 bool CTagLibHelper::WriteWavePackAlbumCover(const std::wstring& file_path, const std::wstring& album_cover_path, bool remove_exist /*= true*/) 1510 { 1511 WavPack::File file(file_path.c_str()); 1512 if (!file.isValid()) 1513 return false; 1514 1515 auto tag = file.APETag(true); 1516 WriteApeTagAlbumCover(tag, album_cover_path, remove_exist); 1517 bool saved = file.save(); 1518 return saved; 1519 } 1520 1521 bool CTagLibHelper::WriteMpegTag(const SongInfo& song_info) 1522 { 1523 MPEG::File file(song_info.file_path.c_str()); 1524 auto tag = file.tag(); 1525 SongInfoToTag(song_info, tag); 1526 int tags = MPEG::File::ID3v2; 1527 //if (file.hasID3v1Tag()) 1528 // tags |= MPEG::File::ID3v1; 1529 if (file.hasAPETag()) 1530 tags |= MPEG::File::APE; 1531 WriteOtherProperties(song_info, file); 1532 bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version()); 1533 return saved; 1534 } 1535 1536 bool CTagLibHelper::WriteFlacTag(const SongInfo& song_info) 1537 { 1538 FLAC::File file(song_info.file_path.c_str()); 1539 auto tag = file.tag(); 1540 SongInfoToTag(song_info, tag); 1541 WriteOtherProperties(song_info, file); 1542 bool saved = file.save(); 1543 return saved; 1544 } 1545 1546 bool CTagLibHelper::WriteM4aTag(const SongInfo& song_info) 1547 { 1548 MP4::File file(song_info.file_path.c_str()); 1549 auto tag = file.tag(); 1550 SongInfoToTag(song_info, tag); 1551 bool saved = file.save(); 1552 return saved; 1553 } 1554 1555 bool CTagLibHelper::WriteWavTag(const SongInfo& song_info) 1556 { 1557 RIFF::WAV::File file(song_info.file_path.c_str()); 1558 auto tag = file.tag(); 1559 SongInfoToTag(song_info, tag); 1560 WriteOtherProperties(song_info, file); 1561 bool saved = file.save(RIFF::WAV::File::AllTags, File::StripOthers, GetWriteId3v2Version()); 1562 return saved; 1563 } 1564 1565 bool CTagLibHelper::WriteOggTag(const SongInfo& song_info) 1566 { 1567 Vorbis::File file(song_info.file_path.c_str()); 1568 auto tag = file.tag(); 1569 SongInfoToTag(song_info, tag); 1570 WriteOtherProperties(song_info, file); 1571 bool saved = file.save(); 1572 return saved; 1573 } 1574 1575 bool CTagLibHelper::WriteApeTag(const SongInfo& song_info) 1576 { 1577 APE::File file(song_info.file_path.c_str()); 1578 auto tag = file.tag(); 1579 SongInfoToTag(song_info, tag); 1580 WriteOtherProperties(song_info, file); 1581 bool saved = file.save(); 1582 return saved; 1583 } 1584 1585 bool CTagLibHelper::WriteMpcTag(const SongInfo& song_info) 1586 { 1587 MPC::File file(song_info.file_path.c_str()); 1588 auto tag = file.tag(); 1589 SongInfoToTag(song_info, tag); 1590 WriteOtherProperties(song_info, file); 1591 bool saved = file.save(); 1592 return saved; 1593 } 1594 1595 bool CTagLibHelper::WriteOpusTag(const SongInfo& song_info) 1596 { 1597 Ogg::Opus::File file(song_info.file_path.c_str()); 1598 auto tag = file.tag(); 1599 SongInfoToTag(song_info, tag); 1600 WriteOtherProperties(song_info, file); 1601 bool saved = file.save(); 1602 return saved; 1603 } 1604 1605 bool CTagLibHelper::WriteWavPackTag(const SongInfo& song_info) 1606 { 1607 WavPack::File file(song_info.file_path.c_str()); 1608 auto tag = file.tag(); 1609 SongInfoToTag(song_info, tag); 1610 WriteOtherProperties(song_info, file); 1611 bool saved = file.save(); 1612 return saved; 1613 } 1614 1615 bool CTagLibHelper::WriteTtaTag(const SongInfo& song_info) 1616 { 1617 TrueAudio::File file(song_info.file_path.c_str()); 1618 auto tag = file.tag(); 1619 SongInfoToTag(song_info, tag); 1620 WriteOtherProperties(song_info, file); 1621 bool saved = file.save(); 1622 return saved; 1623 } 1624 1625 bool CTagLibHelper::WriteAiffTag(const SongInfo& song_info) 1626 { 1627 RIFF::AIFF::File file(song_info.file_path.c_str()); 1628 auto tag = file.tag(); 1629 SongInfoToTag(song_info, tag); 1630 WriteOtherProperties(song_info, file); 1631 bool saved = file.save(GetWriteId3v2Version()); 1632 return saved; 1633 } 1634 1635 bool CTagLibHelper::WriteAsfTag(const SongInfo& song_info) 1636 { 1637 ASF::File file(song_info.file_path.c_str()); 1638 auto tag = file.tag(); 1639 SongInfoToTag(song_info, tag); 1640 WriteOtherProperties(song_info, file); 1641 bool saved = file.save(); 1642 return saved; 1643 } 1644 1645 bool CTagLibHelper::WriteSpxTag(const SongInfo& song_info) 1646 { 1647 Ogg::Speex::File file(song_info.file_path.c_str()); 1648 auto tag = file.tag(); 1649 SongInfoToTag(song_info, tag); 1650 WriteOtherProperties(song_info, file); 1651 bool saved = file.save(); 1652 return saved; 1653 } 1654 1655 std::wstring CTagLibHelper::GetApeCue(const std::wstring& file_path) 1656 { 1657 std::wstring cue_contents; 1658 APE::File file(file_path.c_str()); 1659 auto tag = file.APETag(); 1660 if (tag != nullptr) 1661 { 1662 auto item_list_map = tag->itemListMap(); 1663 auto cue_item = item_list_map[STR_APE_CUE_TAG]; 1664 cue_contents = cue_item.toString().toWString(); 1665 } 1666 return cue_contents; 1667 } 1668 1669 int CTagLibHelper::GetMepgRating(const std::wstring& file_path) 1670 { 1671 MPEG::File file(file_path.c_str()); 1672 auto id3v2 = file.ID3v2Tag(); 1673 return GetId3v2Rating(id3v2); 1674 } 1675 1676 int CTagLibHelper::GetFlacRating(const std::wstring& file_path) 1677 { 1678 FLAC::File file(file_path.c_str()); 1679 auto properties = file.properties(); 1680 if (file.isValid()) 1681 { 1682 auto rating_item = properties[STR_FLAC_RATING_TAG]; 1683 if (!rating_item.isEmpty()) 1684 { 1685 int rating = _wtoi(rating_item.front().toWString().c_str()); 1686 return rating; 1687 } 1688 } 1689 return 0; 1690 1691 } 1692 1693 int CTagLibHelper::GetWmaRating(const std::wstring& file_path) 1694 { 1695 int rate{}; 1696 ASF::File file(file_path.c_str()); 1697 if (file.isValid()) 1698 { 1699 ASF::Tag* tag = file.tag(); 1700 auto rating_str = tag->rating(); 1701 rate = _wtoi(rating_str.toWString().c_str()); 1702 } 1703 return rate; 1704 } 1705 1706 bool CTagLibHelper::WriteMpegRating(const std::wstring& file_path, int rate) 1707 { 1708 MPEG::File file(file_path.c_str()); 1709 auto id3v2 = file.ID3v2Tag(); 1710 WriteId3v2Rating(id3v2, rate); 1711 int tags = MPEG::File::ID3v2; 1712 if (file.hasAPETag()) 1713 tags |= MPEG::File::APE; 1714 bool saved = file.save(tags, File::StripOthers, GetWriteId3v2Version()); 1715 return saved; 1716 } 1717 1718 bool CTagLibHelper::WriteFlacRating(const std::wstring& file_path, int rate) 1719 { 1720 FLAC::File file(file_path.c_str()); 1721 if (file.isValid()) 1722 { 1723 auto properties = file.properties(); 1724 properties[STR_FLAC_RATING_TAG].clear(); 1725 properties[STR_FLAC_RATING_TAG].append(std::to_wstring(rate).c_str()); 1726 file.setProperties(properties); 1727 bool saved = file.save(); 1728 return saved; 1729 } 1730 return false; 1731 } 1732 1733 bool CTagLibHelper::WriteWmaRating(const std::wstring& file_path, int rate) 1734 { 1735 ASF::File file(file_path.c_str()); 1736 if (file.isValid()) 1737 { 1738 auto tag = file.tag(); 1739 tag->setRating(std::to_wstring(rate)); 1740 bool saved = file.save(); 1741 return saved; 1742 } 1743 return false; 1744 } 1745 1746 TagLib::ID3v2::Version CTagLibHelper::GetWriteId3v2Version() 1747 { 1748 return (m_write_id3v2_3 ? ID3v2::Version::v3 : ID3v2::Version::v4); 1749 } 1750