Compare commits

...

2 Commits

Author SHA1 Message Date
f6748d644d
refactor: code cleaning 2022-11-20 02:47:28 +08:00
8e068b9c8d
refactor: rename xm -> xiami 2022-11-20 02:18:50 +08:00
9 changed files with 44 additions and 33 deletions

View File

@ -8,17 +8,20 @@ import (
) )
type Decoder struct { type Decoder struct {
header header
cipher common.StreamDecoder
rd io.ReadSeeker rd io.ReadSeeker
cipher common.StreamDecoder
offset int offset int
header header
} }
func NewDecoder(rd io.ReadSeeker) common.Decoder { func NewDecoder(rd io.ReadSeeker) common.Decoder {
return &Decoder{rd: rd} return &Decoder{rd: rd}
} }
// Validate checks if the file is a valid Kugou (.kgm, .vpr, .kgma) file.
// rd will be seeked to the beginning of the encrypted audio.
func (d *Decoder) Validate() (err error) { func (d *Decoder) Validate() (err error) {
if err := d.header.FromFile(d.rd); err != nil { if err := d.header.FromFile(d.rd); err != nil {
return err return err

View File

@ -16,9 +16,9 @@ const magicHeader = "yeelion-kuwo-tme"
const keyPreDefined = "MoOtOiTvINGwd2E6n0E1i7L5t2IoOoNk" const keyPreDefined = "MoOtOiTvINGwd2E6n0E1i7L5t2IoOoNk"
type Decoder struct { type Decoder struct {
cipher common.StreamDecoder
rd io.ReadSeeker rd io.ReadSeeker
cipher common.StreamDecoder
offset int offset int
outputExt string outputExt string
@ -33,6 +33,8 @@ func NewDecoder(rd io.ReadSeeker) common.Decoder {
return &Decoder{rd: rd} return &Decoder{rd: rd}
} }
// Validate checks if the file is a valid Kuwo .kw file.
// rd will be seeked to the beginning of the encrypted audio.
func (d *Decoder) Validate() error { func (d *Decoder) Validate() error {
header := make([]byte, 0x400) // kwm header is fixed to 1024 bytes header := make([]byte, 0x400) // kwm header is fixed to 1024 bytes
_, err := io.ReadFull(d.rd, header) _, err := io.ReadFull(d.rd, header)

View File

@ -36,22 +36,19 @@ func NewDecoder(rd io.ReadSeeker) common.Decoder {
} }
type Decoder struct { type Decoder struct {
rd io.ReadSeeker rd io.ReadSeeker // rd is the original file reader
offset int offset int
cipher common.StreamDecoder cipher common.StreamDecoder
key []byte
box []byte
metaRaw []byte metaRaw []byte
metaType string metaType string
meta RawMeta meta RawMeta
cover []byte cover []byte
audio []byte
} }
// Validate checks if the file is a valid Netease .ncm file.
// rd will be seeked to the beginning of the encrypted audio.
func (d *Decoder) Validate() error { func (d *Decoder) Validate() error {
if err := d.validateMagicHeader(); err != nil { if err := d.validateMagicHeader(); err != nil {
return err return err

View File

@ -13,14 +13,15 @@ import (
) )
type Decoder struct { type Decoder struct {
raw io.ReadSeeker raw io.ReadSeeker // raw is the original file reader
audio io.Reader
offset int
audioLen int
audio io.Reader // audio is the encrypted audio data
audioLen int // audioLen is the audio data length
offset int // offset is the current audio read position
decodedKey []byte // decodedKey is the decoded key for cipher
cipher common.StreamDecoder cipher common.StreamDecoder
decodedKey []byte
rawMetaExtra1 int rawMetaExtra1 int
rawMetaExtra2 int rawMetaExtra2 int
} }
@ -100,23 +101,29 @@ func (d *Decoder) searchKey() error {
if err != nil { if err != nil {
return err return err
} }
buf, err := io.ReadAll(io.LimitReader(d.raw, 4))
if err != nil { suffixBuf := make([]byte, 4)
if _, err := io.ReadFull(d.raw, suffixBuf); err != nil {
return err return err
} }
if string(buf) == "QTag" {
switch string(suffixBuf) {
case "QTag":
return d.readRawMetaQTag() return d.readRawMetaQTag()
} else if string(buf) == "STag" { case "STag":
return errors.New("qmc: file with 'STag' suffix doesn't contains media key") return errors.New("qmc: file with 'STag' suffix doesn't contains media key")
} else { default:
size := binary.LittleEndian.Uint32(buf) size := binary.LittleEndian.Uint32(suffixBuf)
if size <= 0xFFFF && size != 0 { // assume size is key len if size <= 0xFFFF && size != 0 { // assume size is key len
return d.readRawKey(int64(size)) return d.readRawKey(int64(size))
} }
// try to use default static cipher // try to use default static cipher
d.audioLen = int(fileSizeM4 + 4) d.audioLen = int(fileSizeM4 + 4)
return nil return nil
} }
} }
func (d *Decoder) readRawKey(rawKeyLen int64) error { func (d *Decoder) readRawKey(rawKeyLen int64) error {

View File

@ -13,9 +13,10 @@ var replaceHeader = []byte{0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70}
var magicHeader = []byte{0x51, 0x51, 0x4D, 0x55} //0x15, 0x1D, 0x1A, 0x21 var magicHeader = []byte{0x51, 0x51, 0x4D, 0x55} //0x15, 0x1D, 0x1A, 0x21
type Decoder struct { type Decoder struct {
raw io.ReadSeeker raw io.ReadSeeker // raw is the original file reader
offset int offset int
audio io.Reader audio io.Reader // audio is the decrypted audio data
} }
func (d *Decoder) Validate() error { func (d *Decoder) Validate() error {

View File

@ -1,4 +1,4 @@
package xm package xiami
import ( import (
"bytes" "bytes"
@ -22,13 +22,11 @@ var (
) )
type Decoder struct { type Decoder struct {
rd io.ReadSeeker rd io.ReadSeeker // rd is the original file reader
offset int offset int
cipher common.StreamDecoder cipher common.StreamDecoder
outputExt string outputExt string
mask byte
audio []byte
} }
func (d *Decoder) GetAudioExt() string { func (d *Decoder) GetAudioExt() string {
@ -43,6 +41,8 @@ func NewDecoder(rd io.ReadSeeker) common.Decoder {
return &Decoder{rd: rd} return &Decoder{rd: rd}
} }
// Validate checks if the file is a valid xiami .xm file.
// rd will set to the beginning of the encrypted audio data.
func (d *Decoder) Validate() error { func (d *Decoder) Validate() error {
header := make([]byte, 16) // xm header is fixed to 16 bytes header := make([]byte, 16) // xm header is fixed to 16 bytes

View File

@ -1,4 +1,4 @@
package xm package xiami
type xmCipher struct { type xmCipher struct {
mask byte mask byte

View File

@ -22,7 +22,7 @@ import (
_ "unlock-music.dev/cli/algo/ncm" _ "unlock-music.dev/cli/algo/ncm"
_ "unlock-music.dev/cli/algo/qmc" _ "unlock-music.dev/cli/algo/qmc"
_ "unlock-music.dev/cli/algo/tm" _ "unlock-music.dev/cli/algo/tm"
_ "unlock-music.dev/cli/algo/xm" _ "unlock-music.dev/cli/algo/xiami"
"unlock-music.dev/cli/internal/logging" "unlock-music.dev/cli/internal/logging"
) )

View File

@ -7,6 +7,7 @@ import (
func NewZapLogger() (*zap.Logger, error) { func NewZapLogger() (*zap.Logger, error) {
zapCfg := zap.NewDevelopmentConfig() zapCfg := zap.NewDevelopmentConfig()
zapCfg.DisableStacktrace = true
zapCfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder zapCfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
zapCfg.EncoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout("2006/01/02 15:04:05.000") zapCfg.EncoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout("2006/01/02 15:04:05.000")
return zapCfg.Build() return zapCfg.Build()