Compare commits
No commits in common. "3794ff3154c4425c6f9fcbf8087ba4596982bcb1" and "110a78433a211e216a4871dfbd053e5b53bef3f2" have entirely different histories.
3794ff3154
...
110a78433a
@ -1,34 +0,0 @@
|
|||||||
package ximalaya
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
"encoding/binary"
|
|
||||||
)
|
|
||||||
|
|
||||||
const x2mHeaderSize = 1024
|
|
||||||
|
|
||||||
var x2mKey = [...]byte{'x', 'm', 'l', 'y'}
|
|
||||||
var x2mScrambleTable = [x2mHeaderSize]uint16{}
|
|
||||||
|
|
||||||
//go:embed x2m_scramble_table.bin
|
|
||||||
var x2mScrambleTableBytes []byte
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
if len(x2mScrambleTableBytes) != 2*x2mHeaderSize {
|
|
||||||
panic("invalid x3m scramble table")
|
|
||||||
}
|
|
||||||
for i := range x3mScrambleTable {
|
|
||||||
x3mScrambleTable[i] = binary.LittleEndian.Uint16(x2mScrambleTableBytes[i*2:])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// decryptX2MHeader decrypts the header of ximalaya .x2m file.
|
|
||||||
// make sure input src is 1024(x2mHeaderSize) bytes long.
|
|
||||||
func decryptX2MHeader(src []byte) []byte {
|
|
||||||
dst := make([]byte, len(src))
|
|
||||||
for dstIdx := range src {
|
|
||||||
srcIdx := x2mScrambleTable[dstIdx]
|
|
||||||
dst[dstIdx] = src[srcIdx] ^ x2mKey[dstIdx%len(x2mKey)]
|
|
||||||
}
|
|
||||||
return dst
|
|
||||||
}
|
|
Binary file not shown.
@ -1,40 +0,0 @@
|
|||||||
package ximalaya
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
"encoding/binary"
|
|
||||||
)
|
|
||||||
|
|
||||||
var x3mKey = [...]byte{
|
|
||||||
'3', '9', '8', '9', 'd', '1', '1', '1',
|
|
||||||
'a', 'a', 'd', '5', '6', '1', '3', '9',
|
|
||||||
'4', '0', 'f', '4', 'f', 'c', '4', '4',
|
|
||||||
'b', '6', '3', '9', 'b', '2', '9', '2',
|
|
||||||
}
|
|
||||||
|
|
||||||
const x3mHeaderSize = 1024
|
|
||||||
|
|
||||||
var x3mScrambleTable = [x3mHeaderSize]uint16{}
|
|
||||||
|
|
||||||
//go:embed x3m_scramble_table.bin
|
|
||||||
var x3mScrambleTableBytes []byte
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
if len(x3mScrambleTableBytes) != 2*x3mHeaderSize {
|
|
||||||
panic("invalid x3m scramble table")
|
|
||||||
}
|
|
||||||
for i := range x3mScrambleTable {
|
|
||||||
x3mScrambleTable[i] = binary.LittleEndian.Uint16(x3mScrambleTableBytes[i*2:])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// decryptX3MHeader decrypts the header of ximalaya .x3m file.
|
|
||||||
// make sure input src is 1024 (x3mHeaderSize) bytes long.
|
|
||||||
func decryptX3MHeader(src []byte) []byte {
|
|
||||||
dst := make([]byte, len(src))
|
|
||||||
for dstIdx := range src {
|
|
||||||
srcIdx := x3mScrambleTable[dstIdx]
|
|
||||||
dst[dstIdx] = src[srcIdx] ^ x3mKey[dstIdx%len(x3mKey)]
|
|
||||||
}
|
|
||||||
return dst
|
|
||||||
}
|
|
Binary file not shown.
@ -1,56 +0,0 @@
|
|||||||
package ximalaya
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"unlock-music.dev/cli/algo/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Decoder struct {
|
|
||||||
rd io.ReadSeeker
|
|
||||||
offset int
|
|
||||||
|
|
||||||
audio io.Reader
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDecoder(rd io.ReadSeeker) common.Decoder {
|
|
||||||
return &Decoder{rd: rd}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Decoder) Validate() error {
|
|
||||||
encryptedHeader := make([]byte, x2mHeaderSize)
|
|
||||||
if _, err := io.ReadFull(d.rd, encryptedHeader); err != nil {
|
|
||||||
return fmt.Errorf("ximalaya read header: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // try to decode with x2m
|
|
||||||
header := decryptX2MHeader(encryptedHeader)
|
|
||||||
if _, ok := common.SniffAll(header); ok {
|
|
||||||
d.audio = io.MultiReader(bytes.NewReader(header), d.rd)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // try to decode with x3m
|
|
||||||
// not read file again, since x2m and x3m have the same header size
|
|
||||||
header := decryptX3MHeader(encryptedHeader)
|
|
||||||
if _, ok := common.SniffAll(header); ok {
|
|
||||||
d.audio = io.MultiReader(bytes.NewReader(header), d.rd)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf("ximalaya: unknown format")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Decoder) Read(p []byte) (n int, err error) {
|
|
||||||
return d.audio.Read(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.RegisterDecoder("x2m", false, NewDecoder)
|
|
||||||
common.RegisterDecoder("x3m", false, NewDecoder)
|
|
||||||
common.RegisterDecoder("xm", false, NewDecoder)
|
|
||||||
}
|
|
@ -23,7 +23,6 @@ import (
|
|||||||
_ "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/xiami"
|
||||||
_ "unlock-music.dev/cli/algo/ximalaya"
|
|
||||||
"unlock-music.dev/cli/internal/logging"
|
"unlock-music.dev/cli/internal/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user