tm.go 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. package tm
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "unlock-music.dev/cli/algo/common"
  8. "unlock-music.dev/cli/internal/sniff"
  9. )
  10. var replaceHeader = []byte{0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70}
  11. var magicHeader = []byte{0x51, 0x51, 0x4D, 0x55} //0x15, 0x1D, 0x1A, 0x21
  12. type Decoder struct {
  13. raw io.ReadSeeker // raw is the original file reader
  14. offset int
  15. audio io.Reader // audio is the decrypted audio data
  16. }
  17. func (d *Decoder) Validate() error {
  18. header := make([]byte, 8)
  19. if _, err := io.ReadFull(d.raw, header); err != nil {
  20. return fmt.Errorf("tm read header: %w", err)
  21. }
  22. if bytes.Equal(magicHeader, header[:len(magicHeader)]) { // replace m4a header
  23. d.audio = io.MultiReader(bytes.NewReader(replaceHeader), d.raw)
  24. return nil
  25. }
  26. if _, ok := sniff.AudioExtension(header); ok { // not encrypted
  27. d.audio = io.MultiReader(bytes.NewReader(header), d.raw)
  28. return nil
  29. }
  30. return errors.New("tm: valid magic header")
  31. }
  32. func (d *Decoder) Read(buf []byte) (int, error) {
  33. return d.audio.Read(buf)
  34. }
  35. func NewTmDecoder(p *common.DecoderParams) common.Decoder {
  36. return &Decoder{raw: p.Reader}
  37. }
  38. func init() {
  39. // QQ Music IOS M4a (replace header)
  40. common.RegisterDecoder("tm2", false, NewTmDecoder)
  41. common.RegisterDecoder("tm6", false, NewTmDecoder)
  42. // QQ Music IOS Mp3 (not encrypted)
  43. common.RegisterDecoder("tm0", false, NewTmDecoder)
  44. common.RegisterDecoder("tm3", false, NewTmDecoder)
  45. }