1
0
forked from um/cli
cli/algo/tm/tm.go

59 lines
1.4 KiB
Go
Raw Permalink Normal View History

2020-12-25 20:54:59 +00:00
package tm
import (
"bytes"
"errors"
"fmt"
"io"
2022-11-18 23:25:40 +00:00
2022-11-18 23:44:44 +00:00
"unlock-music.dev/cli/algo/common"
"unlock-music.dev/cli/internal/sniff"
2020-12-25 20:54:59 +00:00
)
2020-12-26 07:03:34 +00:00
var replaceHeader = []byte{0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70}
var magicHeader = []byte{0x51, 0x51, 0x4D, 0x55} //0x15, 0x1D, 0x1A, 0x21
2020-12-25 20:54:59 +00:00
type Decoder struct {
2022-11-19 18:47:28 +00:00
raw io.ReadSeeker // raw is the original file reader
offset int
2022-11-19 18:47:28 +00:00
audio io.Reader // audio is the decrypted audio data
2020-12-25 20:54:59 +00:00
}
func (d *Decoder) Validate() error {
header := make([]byte, 8)
if _, err := io.ReadFull(d.raw, header); err != nil {
return fmt.Errorf("tm read header: %w", err)
2020-12-25 20:54:59 +00:00
}
2022-11-18 23:25:44 +00:00
if bytes.Equal(magicHeader, header[:len(magicHeader)]) { // replace m4a header
d.audio = io.MultiReader(bytes.NewReader(replaceHeader), d.raw)
return nil
}
if _, ok := sniff.AudioExtension(header); ok { // not encrypted
2022-11-18 23:25:44 +00:00
d.audio = io.MultiReader(bytes.NewReader(header), d.raw)
return nil
2020-12-25 20:54:59 +00:00
}
2022-11-18 23:25:44 +00:00
return errors.New("tm: valid magic header")
2020-12-25 20:54:59 +00:00
}
2020-12-26 07:47:10 +00:00
func (d *Decoder) Read(buf []byte) (int, error) {
return d.audio.Read(buf)
2020-12-26 07:47:10 +00:00
}
func NewTmDecoder(rd io.ReadSeeker) common.Decoder {
return &Decoder{raw: rd}
}
2020-12-26 07:47:10 +00:00
func init() {
2022-11-18 23:25:44 +00:00
// QQ Music IOS M4a (replace header)
common.RegisterDecoder("tm2", false, NewTmDecoder)
common.RegisterDecoder("tm6", false, NewTmDecoder)
2022-11-18 23:25:44 +00:00
// QQ Music IOS Mp3 (not encrypted)
common.RegisterDecoder("tm0", false, NewTmDecoder)
common.RegisterDecoder("tm3", false, NewTmDecoder)
2020-12-26 07:47:10 +00:00
}