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