2020-12-25 18:54:07 +00:00
|
|
|
package kgm
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2022-11-18 23:25:42 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2022-11-18 23:25:38 +00:00
|
|
|
|
2021-03-02 10:16:19 +00:00
|
|
|
"github.com/unlock-music/cli/algo/common"
|
2020-12-25 18:54:07 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Decoder struct {
|
2022-11-18 23:25:42 +00:00
|
|
|
header Header
|
|
|
|
initializer kgmCryptoInitializer
|
|
|
|
|
|
|
|
file []byte
|
|
|
|
audio []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
type kgmCryptoInitializer func(header *Header, body io.Reader) (io.Reader, error)
|
|
|
|
|
|
|
|
var kgmCryptoInitializers = map[uint32]kgmCryptoInitializer{
|
|
|
|
3: newKgmCryptoV3,
|
2020-12-25 18:54:07 +00:00
|
|
|
}
|
|
|
|
|
2020-12-26 07:47:10 +00:00
|
|
|
func NewDecoder(file []byte) common.Decoder {
|
2020-12-25 18:54:07 +00:00
|
|
|
return &Decoder{
|
|
|
|
file: file,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-18 23:25:38 +00:00
|
|
|
func (d *Decoder) GetAudioData() []byte {
|
2020-12-25 18:54:07 +00:00
|
|
|
return d.audio
|
|
|
|
}
|
|
|
|
|
2022-11-18 23:25:38 +00:00
|
|
|
func (d *Decoder) GetAudioExt() string {
|
2021-05-23 11:58:23 +00:00
|
|
|
return "" // use sniffer
|
2020-12-25 18:54:07 +00:00
|
|
|
}
|
|
|
|
|
2022-11-18 23:25:38 +00:00
|
|
|
func (d *Decoder) GetMeta() common.Meta {
|
2020-12-25 18:54:07 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *Decoder) Validate() error {
|
2022-11-18 23:25:42 +00:00
|
|
|
if err := d.header.FromBytes(d.file); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// TODO; validate crypto version
|
|
|
|
|
|
|
|
var ok bool
|
|
|
|
d.initializer, ok = kgmCryptoInitializers[d.header.CryptoVersion]
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("kgm: unsupported crypto version %d", d.header.CryptoVersion)
|
2020-12-25 18:54:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *Decoder) Decode() error {
|
2022-11-18 23:25:42 +00:00
|
|
|
d.audio = d.file[d.header.AudioOffset:]
|
2020-12-25 18:54:07 +00:00
|
|
|
|
2022-11-18 23:25:42 +00:00
|
|
|
r, err := d.initializer(&d.header, bytes.NewReader(d.audio))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("kgm: failed to initialize crypto: %w", err)
|
|
|
|
}
|
|
|
|
d.audio, err = io.ReadAll(r)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("kgm: failed to decrypt audio: %w", err)
|
2020-12-25 18:54:07 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2022-11-18 23:25:42 +00:00
|
|
|
|
2020-12-26 07:47:10 +00:00
|
|
|
func init() {
|
|
|
|
// Kugou
|
2021-11-11 15:43:20 +00:00
|
|
|
common.RegisterDecoder("kgm", false, NewDecoder)
|
|
|
|
common.RegisterDecoder("kgma", false, NewDecoder)
|
2020-12-26 07:47:10 +00:00
|
|
|
// Viper
|
2021-11-11 15:43:20 +00:00
|
|
|
common.RegisterDecoder("vpr", false, NewDecoder)
|
2020-12-26 07:47:10 +00:00
|
|
|
}
|