cli/algo/kgm/kgm.go

68 lines
1.4 KiB
Go
Raw Normal View History

2020-12-25 18:54:07 +00:00
package kgm
import (
"fmt"
"io"
2022-11-18 23:25:38 +00:00
2022-11-18 23:44:44 +00:00
"unlock-music.dev/cli/algo/common"
2020-12-25 18:54:07 +00:00
)
type Decoder struct {
2022-11-19 18:47:28 +00:00
rd io.ReadSeeker
2022-11-19 18:47:28 +00:00
cipher common.StreamDecoder
offset int
2022-11-19 18:47:28 +00:00
header header
}
func NewDecoder(p *common.DecoderParams) common.Decoder {
return &Decoder{rd: p.Reader}
2020-12-25 18:54:07 +00:00
}
2022-11-19 18:47:28 +00:00
// 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) {
if err := d.header.FromFile(d.rd); err != nil {
return err
}
// TODO; validate crypto version
switch d.header.CryptoVersion {
case 3:
d.cipher, err = newKgmCryptoV3(&d.header)
if err != nil {
return fmt.Errorf("kgm init crypto v3: %w", err)
}
default:
return fmt.Errorf("kgm: unsupported crypto version %d", d.header.CryptoVersion)
2020-12-25 18:54:07 +00:00
}
// prepare for read
if _, err := d.rd.Seek(int64(d.header.AudioOffset), io.SeekStart); err != nil {
return fmt.Errorf("kgm seek to audio: %w", err)
}
2020-12-25 18:54:07 +00:00
return nil
}
func (d *Decoder) Read(buf []byte) (int, error) {
n, err := d.rd.Read(buf)
if n > 0 {
d.cipher.Decrypt(buf[:n], d.offset)
d.offset += n
}
return n, err
}
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)
// Kugou Android
common.RegisterDecoder("kgm.flac", false, NewDecoder)
common.RegisterDecoder("vpr.flac", false, NewDecoder)
2020-12-26 07:47:10 +00:00
}