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