Compare commits
No commits in common. "f6748d644d220169d397199413fa0d3dbab7c005" and "14c9d49d463980aa023d4ceb26d015211cef5d17" have entirely different histories.
f6748d644d
...
14c9d49d46
@ -8,20 +8,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
rd io.ReadSeeker
|
|
||||||
|
|
||||||
cipher common.StreamDecoder
|
|
||||||
offset int
|
|
||||||
|
|
||||||
header header
|
header header
|
||||||
|
cipher common.StreamDecoder
|
||||||
|
|
||||||
|
rd io.ReadSeeker
|
||||||
|
offset int
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
@ -16,9 +16,9 @@ const magicHeader = "yeelion-kuwo-tme"
|
|||||||
const keyPreDefined = "MoOtOiTvINGwd2E6n0E1i7L5t2IoOoNk"
|
const keyPreDefined = "MoOtOiTvINGwd2E6n0E1i7L5t2IoOoNk"
|
||||||
|
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
rd io.ReadSeeker
|
|
||||||
|
|
||||||
cipher common.StreamDecoder
|
cipher common.StreamDecoder
|
||||||
|
|
||||||
|
rd io.ReadSeeker
|
||||||
offset int
|
offset int
|
||||||
|
|
||||||
outputExt string
|
outputExt string
|
||||||
@ -33,8 +33,6 @@ 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)
|
||||||
|
@ -36,19 +36,22 @@ func NewDecoder(rd io.ReadSeeker) common.Decoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
rd io.ReadSeeker // rd is the original file reader
|
rd io.ReadSeeker
|
||||||
|
|
||||||
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
|
||||||
|
@ -13,15 +13,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
raw io.ReadSeeker // raw is the original file reader
|
raw io.ReadSeeker
|
||||||
|
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
|
||||||
}
|
}
|
||||||
@ -101,29 +100,23 @@ func (d *Decoder) searchKey() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
buf, err := io.ReadAll(io.LimitReader(d.raw, 4))
|
||||||
suffixBuf := make([]byte, 4)
|
if err != nil {
|
||||||
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()
|
||||||
case "STag":
|
} else if string(buf) == "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")
|
||||||
default:
|
} else {
|
||||||
size := binary.LittleEndian.Uint32(suffixBuf)
|
size := binary.LittleEndian.Uint32(buf)
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -13,10 +13,9 @@ 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 is the original file reader
|
raw io.ReadSeeker
|
||||||
|
|
||||||
offset int
|
offset int
|
||||||
audio io.Reader // audio is the decrypted audio data
|
audio io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Decoder) Validate() error {
|
func (d *Decoder) Validate() error {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package xiami
|
package xm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -22,11 +22,13 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
rd io.ReadSeeker // rd is the original file reader
|
rd io.ReadSeeker
|
||||||
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 {
|
||||||
@ -41,8 +43,6 @@ 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
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package xiami
|
package xm
|
||||||
|
|
||||||
type xmCipher struct {
|
type xmCipher struct {
|
||||||
mask byte
|
mask byte
|
@ -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/xiami"
|
_ "unlock-music.dev/cli/algo/xm"
|
||||||
"unlock-music.dev/cli/internal/logging"
|
"unlock-music.dev/cli/internal/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ 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()
|
||||||
|
Loading…
Reference in New Issue
Block a user