dev: MV dl (need mp4decrypt)

This commit is contained in:
itouakirai
2025-02-11 05:27:55 +08:00
parent 3726ac4c8a
commit 0f692422c0
3 changed files with 97 additions and 51 deletions

View File

@@ -64,8 +64,8 @@ func (w *Key) GetKey(ctx context.Context, licenseServerURL string, PSSH string,
for _, key := range keys {
if key.Type == wv.License_KeyContainer_CONTENT {
command += hex.EncodeToString(key.ID) + ":" + hex.EncodeToString(key.Value)
//command += hex.EncodeToString(key.Value)
//command += hex.EncodeToString(key.ID) + ":" + hex.EncodeToString(key.Value)
command += hex.EncodeToString(key.Value)
keybt = key.Value
}
}

View File

@@ -22,6 +22,7 @@ import (
"github.com/grafov/m3u8"
"strings"
"github.com/schollz/progressbar/v3"
"os/exec"
)
type PlaybackLicense struct {
@@ -151,7 +152,7 @@ func GetWebplayback(adamId string, authtoken string, mutoken string, mvmode bool
// 遍历 Assets
for i, _ := range obj.List[0].Assets {
if obj.List[0].Assets[i].Flavor == "28:ctrp256" {
kidBase64, fileurl, err := extractKidBase64(obj.List[0].Assets[i].URL)
kidBase64, fileurl, err := extractKidBase64(obj.List[0].Assets[i].URL, false)
if err != nil {
return "", "", err
}
@@ -174,7 +175,7 @@ type Songlist struct {
Status int `json:"status"`
}
func extractKidBase64(b string) (string, string, error) {
func extractKidBase64(b string, mvmode bool) (string, string, error) {
resp, err := http.Get(b)
if err != nil {
return "", "", err
@@ -193,7 +194,7 @@ func extractKidBase64(b string) (string, string, error) {
return "", "", err
}
var kidbase64 string
var fileurl string
var urlBuilder strings.Builder
if listType == m3u8.MEDIA {
mediaPlaylist := from.(*m3u8.MediaPlaylist)
if mediaPlaylist.Key != nil {
@@ -201,15 +202,30 @@ func extractKidBase64(b string) (string, string, error) {
kidbase64 = split[1]
lastSlashIndex := strings.LastIndex(b, "/")
// 截取最后一个斜杠之前的部分
fileurl = b[:lastSlashIndex] + "/" + mediaPlaylist.Map.URI
urlBuilder.WriteString(b[:lastSlashIndex])
urlBuilder.WriteString("/")
urlBuilder.WriteString(mediaPlaylist.Map.URI)
//fileurl = b[:lastSlashIndex] + "/" + mediaPlaylist.Map.URI
//fmt.Println("Extracted URI:", mediaPlaylist.Map.URI)
if mvmode {
for _, segment := range mediaPlaylist.Segments {
if segment != nil {
fmt.Println("Extracted URI:", segment.URI)
urlBuilder.WriteString(";")
urlBuilder.WriteString(b[:lastSlashIndex])
urlBuilder.WriteString("/")
urlBuilder.WriteString(segment.URI)
//fileurl = fileurl + ";" + b[:lastSlashIndex] + "/" + segment.URI
}
}
}
} else {
fmt.Println("No key information found")
}
} else {
fmt.Println("Not a media playlist")
}
return kidbase64, fileurl, nil
return kidbase64, urlBuilder.String(), nil
}
func extsong(b string)(bytes.Buffer){
resp, err := http.Get(b)
@@ -245,7 +261,7 @@ func Run(adamId string, trackpath string, authtoken string, mutoken string, mvmo
var kidBase64 string
var err error
if mvmode {
kidBase64, _, err = extractKidBase64(trackpath)
kidBase64, fileurl, err = extractKidBase64(trackpath, true)
if err != nil {
return "", err
}
@@ -283,7 +299,8 @@ func Run(adamId string, trackpath string, authtoken string, mutoken string, mvmo
return "", err
}
if mvmode {
return keystr, nil
keyAndUrls := "1:" + keystr + ";" + fileurl
return keyAndUrls, nil
}
body := extsong(fileurl)
fmt.Print("Downloaded\n")
@@ -312,23 +329,58 @@ func Run(adamId string, trackpath string, authtoken string, mutoken string, mvmo
}
return "", nil
}
// DecryptMP4Auto decrypts a fragmented MP4 file with the set of keys retreived from the widevice license
// by automatically selecting the appropriate key. Supports CENC and CBCS schemes.
// func DecryptMP4Auto(r io.Reader, keys []*Key, w io.Writer) error {
// // Extract content key
// var key []byte
// for _, k := range keys {
// if k.Type == wvpb.License_KeyContainer_CONTENT {
// key = k.Key
// break
// }
// }
// if key == nil {
// return fmt.Errorf("no %s key type found in the provided key set", wvpb.License_KeyContainer_CONTENT)
// }
// // Execute decryption
// return DecryptMP4(r, key, w)
// }
func ExtMvData (keyAndUrls string, savePath string)(error) {
segments := strings.Split(keyAndUrls, ";")
key := segments[0]
//fmt.Println(key)
urls := segments[1:]
tempFile, err := os.CreateTemp("", "enc_mv_data-*.mp4")
if err != nil {
fmt.Printf("创建文件失败:%v\n", err)
return err
}
defer tempFile.Close()
defer os.Remove(tempFile.Name())
// 依次下载每个链接并写入文件
bar := progressbar.DefaultBytes(
-1,
"Downloading...",
)
barWriter := io.MultiWriter(tempFile, bar)
for _, url := range urls {
resp, err := http.Get(url)
if err != nil {
fmt.Printf("下载链接 %s 失败:%v\n", url, err)
return err
}
// 将响应体写入输出文件
_, err = io.Copy(barWriter, resp.Body)
defer resp.Body.Close() // 注意及时关闭响应体,避免资源泄露
if err != nil {
fmt.Printf("写入文件失败:%v\n", err)
return err
}
//fmt.Printf("第 %d 个链接 %s 下载并写入完成\n", idx+1, url)
}
tempFile.Close()
fmt.Println("\nDownloaded.")
cmd1 := exec.Command("mp4decrypt", "--key", key, tempFile.Name(), savePath)
//outlog, err := cmd1.CombinedOutput()
if err := cmd1.Run(); err != nil {
fmt.Printf("Decrypt failed: %v\n", err)
//fmt.Printf("Output:\n%s\n", outlog)
return err
} else {
fmt.Println("Decrypted.")
}
return nil
}
// DecryptMP4 decrypts a fragmented MP4 file with keys from widevice license. Supports CENC and CBCS schemes.
func DecryptMP4(r io.Reader, key []byte, w io.Writer) error {