qmc_meta.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package qmc
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "strings"
  7. "github.com/samber/lo"
  8. "unlock-music.dev/cli/algo/common"
  9. "unlock-music.dev/cli/algo/qmc/client"
  10. "unlock-music.dev/cli/internal/ffmpeg"
  11. )
  12. func (d *Decoder) GetAudioMeta(ctx context.Context) (common.AudioMeta, error) {
  13. if d.meta != nil {
  14. return d.meta, nil
  15. }
  16. if d.songID != 0 {
  17. if err := d.getMetaBySongID(ctx); err != nil {
  18. return nil, err
  19. }
  20. return d.meta, nil
  21. }
  22. embedMeta, err := ffmpeg.ProbeReader(ctx, d.probeBuf)
  23. if err != nil {
  24. return nil, fmt.Errorf("qmc[GetAudioMeta] probe reader: %w", err)
  25. }
  26. d.meta = embedMeta
  27. d.embeddedCover = embedMeta.HasAttachedPic()
  28. if !d.embeddedCover && embedMeta.HasMetadata() {
  29. if err := d.searchMetaOnline(ctx, embedMeta); err != nil {
  30. return nil, err
  31. }
  32. return d.meta, nil
  33. }
  34. return d.meta, nil
  35. }
  36. func (d *Decoder) getMetaBySongID(ctx context.Context) error {
  37. c := client.NewQQMusicClient() // todo: use global client
  38. trackInfo, err := c.GetTrackInfo(ctx, d.songID)
  39. if err != nil {
  40. return fmt.Errorf("qmc[GetAudioMeta] get track info: %w", err)
  41. }
  42. d.meta = trackInfo
  43. d.albumID = trackInfo.Album.Id
  44. if trackInfo.Album.Pmid == "" {
  45. d.albumMediaID = trackInfo.Album.Pmid
  46. } else {
  47. d.albumMediaID = trackInfo.Album.Mid
  48. }
  49. return nil
  50. }
  51. func (d *Decoder) searchMetaOnline(ctx context.Context, original common.AudioMeta) error {
  52. c := client.NewQQMusicClient() // todo: use global client
  53. keyword := lo.WithoutEmpty(append(
  54. []string{original.GetTitle(), original.GetAlbum()},
  55. original.GetArtists()...),
  56. )
  57. if len(keyword) == 0 {
  58. return errors.New("qmc[searchMetaOnline] no keyword")
  59. }
  60. trackList, err := c.Search(ctx, strings.Join(keyword, " "))
  61. if err != nil {
  62. return fmt.Errorf("qmc[searchMetaOnline] search: %w", err)
  63. }
  64. if len(trackList) == 0 {
  65. return errors.New("qmc[searchMetaOnline] no result")
  66. }
  67. meta := trackList[0]
  68. d.meta = meta
  69. d.albumID = meta.Album.Id
  70. if meta.Album.Pmid == "" {
  71. d.albumMediaID = meta.Album.Pmid
  72. } else {
  73. d.albumMediaID = meta.Album.Mid
  74. }
  75. return nil
  76. }
  77. func (d *Decoder) GetCoverImage(ctx context.Context) ([]byte, error) {
  78. if d.cover != nil {
  79. return d.cover, nil
  80. }
  81. if d.embeddedCover {
  82. img, err := ffmpeg.ExtractAlbumArt(ctx, d.probeBuf)
  83. if err != nil {
  84. return nil, fmt.Errorf("qmc[GetCoverImage] extract album art: %w", err)
  85. }
  86. d.cover = img.Bytes()
  87. return d.cover, nil
  88. }
  89. c := client.NewQQMusicClient() // todo: use global client
  90. var err error
  91. if d.albumMediaID != "" {
  92. d.cover, err = c.AlbumCoverByMediaID(ctx, d.albumMediaID)
  93. if err != nil {
  94. return nil, fmt.Errorf("qmc[GetCoverImage] get cover by media id: %w", err)
  95. }
  96. } else if d.albumID != 0 {
  97. d.cover, err = c.AlbumCoverByID(ctx, d.albumID)
  98. if err != nil {
  99. return nil, fmt.Errorf("qmc[GetCoverImage] get cover by id: %w", err)
  100. }
  101. } else {
  102. return nil, errors.New("qmc[GetAudioMeta] album (or media) id is empty")
  103. }
  104. return d.cover, nil
  105. }