dev: MV dl (need mp4decrypt)
This commit is contained in:
parent
3726ac4c8a
commit
0f692422c0
44
main.go
44
main.go
@ -400,7 +400,7 @@ func writeCover(sanAlbumFolder, name string, url string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if exists {
|
if exists {
|
||||||
return nil
|
_ = os.Remove(covPath)
|
||||||
}
|
}
|
||||||
if Config.CoverFormat == "png" {
|
if Config.CoverFormat == "png" {
|
||||||
re := regexp.MustCompile(`\{w\}x\{h\}`)
|
re := regexp.MustCompile(`\{w\}x\{h\}`)
|
||||||
@ -970,7 +970,7 @@ func rip(albumId string, token string, storefront string, mediaUserToken string,
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if isInArray(selected, trackNum) {
|
if isInArray(selected, trackNum) {
|
||||||
counter.Total++
|
//counter.Total++
|
||||||
downloadTrack(trackNum, trackTotal, meta, track, albumId, token, storefront, mediaUserToken, sanAlbumFolder, Codec, &counter)
|
downloadTrack(trackNum, trackTotal, meta, track, albumId, token, storefront, mediaUserToken, sanAlbumFolder, Codec, &counter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1167,10 +1167,9 @@ func main() {
|
|||||||
counter = structs.Counter{}
|
counter = structs.Counter{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mvDownloader(adamID string, saveDir string, token string, mediaUserToken string)(error){
|
func mvDownloader(adamID string, saveDir string, token string, mediaUserToken string)(error){
|
||||||
vidPath := filepath.Join(saveDir, fmt.Sprintf("%s.mp4", adamID))
|
vidPath := filepath.Join(saveDir, fmt.Sprintf("%s_vid.mp4", adamID))
|
||||||
audPath := filepath.Join(saveDir, fmt.Sprintf("%s.m4a", adamID))
|
audPath := filepath.Join(saveDir, fmt.Sprintf("%s_aud.mp4", adamID))
|
||||||
mvOutPath := filepath.Join(saveDir, fmt.Sprintf("%s.mkv", adamID))
|
mvOutPath := filepath.Join(saveDir, fmt.Sprintf("%s.mkv", adamID))
|
||||||
exists, _ := fileExists(mvOutPath)
|
exists, _ := fileExists(mvOutPath)
|
||||||
if exists {
|
if exists {
|
||||||
@ -1183,33 +1182,28 @@ func mvDownloader(adamID string, saveDir string, token string, mediaUserToken st
|
|||||||
audiom3u8url, _ := extractMvAudio(mvm3u8url)
|
audiom3u8url, _ := extractMvAudio(mvm3u8url)
|
||||||
//fmt.Println(videom3u8url)
|
//fmt.Println(videom3u8url)
|
||||||
//fmt.Println(audiom3u8url)
|
//fmt.Println(audiom3u8url)
|
||||||
videokey, _ := runv3.Run(adamID, videom3u8url, token, mediaUserToken, true)
|
|
||||||
audiokey, _ := runv3.Run(adamID, audiom3u8url, token, mediaUserToken, true)
|
videokeyAndUrls, _ := runv3.Run(adamID, videom3u8url, token, mediaUserToken, true)
|
||||||
//fmt.Println(videokey)
|
audiokeyAndUrls, _ := runv3.Run(adamID, audiom3u8url, token, mediaUserToken, true)
|
||||||
//fmt.Println(audiokey)
|
//fmt.Println(videokeyAndUrls)
|
||||||
cmd1 := exec.Command("n-m3u8dl-re", videom3u8url, "--key", videokey, "--decryption-engine", "MP4DECRYPT", "--save-dir", saveDir, "--save-name", adamID)
|
//fmt.Println(audiokeyAndUrls)
|
||||||
cmd2 := exec.Command("n-m3u8dl-re", audiom3u8url, "--key", audiokey, "--decryption-engine", "MP4DECRYPT", "--save-dir", saveDir, "--save-name", adamID)
|
|
||||||
cmd3 := exec.Command("MP4Box", "-quiet", "-add", vidPath, "-add", audPath, "-keep-utc", "-new", mvOutPath)
|
fmt.Println("MV-VIDEO")
|
||||||
fmt.Printf("MVvid Downloading...")
|
_ = runv3.ExtMvData(videokeyAndUrls, vidPath)
|
||||||
if err := cmd1.Run(); err != nil {
|
|
||||||
fmt.Printf("MVvid Download failed: %v\n", err)
|
fmt.Println("MV-AUDIO")
|
||||||
return err
|
_ = runv3.ExtMvData(audiokeyAndUrls, audPath)
|
||||||
}
|
|
||||||
fmt.Printf("\rMVvid Downloaded. \n")
|
muxCmd := exec.Command("MP4Box", "-quiet", "-add", vidPath, "-add", audPath, "-keep-utc", "-new", mvOutPath)
|
||||||
fmt.Printf("MVaud Downloading...")
|
|
||||||
if err := cmd2.Run(); err != nil {
|
|
||||||
fmt.Printf("MVaud Download failed: %v\n", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("\rMVaud Downloaded. \n")
|
|
||||||
fmt.Printf("MV Remuxing...")
|
fmt.Printf("MV Remuxing...")
|
||||||
if err := cmd3.Run(); err != nil {
|
if err := muxCmd.Run(); err != nil {
|
||||||
fmt.Printf("MV mux failed: %v\n", err)
|
fmt.Printf("MV mux failed: %v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("\rMV Remuxed. \n")
|
fmt.Printf("\rMV Remuxed. \n")
|
||||||
_ = os.Remove(vidPath)
|
_ = os.Remove(vidPath)
|
||||||
_ = os.Remove(audPath)
|
_ = os.Remove(audPath)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,8 +64,8 @@ func (w *Key) GetKey(ctx context.Context, licenseServerURL string, PSSH string,
|
|||||||
|
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
if key.Type == wv.License_KeyContainer_CONTENT {
|
if key.Type == wv.License_KeyContainer_CONTENT {
|
||||||
command += hex.EncodeToString(key.ID) + ":" + hex.EncodeToString(key.Value)
|
//command += hex.EncodeToString(key.ID) + ":" + hex.EncodeToString(key.Value)
|
||||||
//command += hex.EncodeToString(key.Value)
|
command += hex.EncodeToString(key.Value)
|
||||||
keybt = key.Value
|
keybt = key.Value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/grafov/m3u8"
|
"github.com/grafov/m3u8"
|
||||||
"strings"
|
"strings"
|
||||||
"github.com/schollz/progressbar/v3"
|
"github.com/schollz/progressbar/v3"
|
||||||
|
"os/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PlaybackLicense struct {
|
type PlaybackLicense struct {
|
||||||
@ -151,7 +152,7 @@ func GetWebplayback(adamId string, authtoken string, mutoken string, mvmode bool
|
|||||||
// 遍历 Assets
|
// 遍历 Assets
|
||||||
for i, _ := range obj.List[0].Assets {
|
for i, _ := range obj.List[0].Assets {
|
||||||
if obj.List[0].Assets[i].Flavor == "28:ctrp256" {
|
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 {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
@ -174,7 +175,7 @@ type Songlist struct {
|
|||||||
Status int `json:"status"`
|
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)
|
resp, err := http.Get(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
@ -193,7 +194,7 @@ func extractKidBase64(b string) (string, string, error) {
|
|||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
var kidbase64 string
|
var kidbase64 string
|
||||||
var fileurl string
|
var urlBuilder strings.Builder
|
||||||
if listType == m3u8.MEDIA {
|
if listType == m3u8.MEDIA {
|
||||||
mediaPlaylist := from.(*m3u8.MediaPlaylist)
|
mediaPlaylist := from.(*m3u8.MediaPlaylist)
|
||||||
if mediaPlaylist.Key != nil {
|
if mediaPlaylist.Key != nil {
|
||||||
@ -201,15 +202,30 @@ func extractKidBase64(b string) (string, string, error) {
|
|||||||
kidbase64 = split[1]
|
kidbase64 = split[1]
|
||||||
lastSlashIndex := strings.LastIndex(b, "/")
|
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)
|
//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 {
|
} else {
|
||||||
fmt.Println("No key information found")
|
fmt.Println("No key information found")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Not a media playlist")
|
fmt.Println("Not a media playlist")
|
||||||
}
|
}
|
||||||
return kidbase64, fileurl, nil
|
return kidbase64, urlBuilder.String(), nil
|
||||||
}
|
}
|
||||||
func extsong(b string)(bytes.Buffer){
|
func extsong(b string)(bytes.Buffer){
|
||||||
resp, err := http.Get(b)
|
resp, err := http.Get(b)
|
||||||
@ -245,7 +261,7 @@ func Run(adamId string, trackpath string, authtoken string, mutoken string, mvmo
|
|||||||
var kidBase64 string
|
var kidBase64 string
|
||||||
var err error
|
var err error
|
||||||
if mvmode {
|
if mvmode {
|
||||||
kidBase64, _, err = extractKidBase64(trackpath)
|
kidBase64, fileurl, err = extractKidBase64(trackpath, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -283,7 +299,8 @@ func Run(adamId string, trackpath string, authtoken string, mutoken string, mvmo
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if mvmode {
|
if mvmode {
|
||||||
return keystr, nil
|
keyAndUrls := "1:" + keystr + ";" + fileurl
|
||||||
|
return keyAndUrls, nil
|
||||||
}
|
}
|
||||||
body := extsong(fileurl)
|
body := extsong(fileurl)
|
||||||
fmt.Print("Downloaded\n")
|
fmt.Print("Downloaded\n")
|
||||||
@ -312,23 +329,58 @@ func Run(adamId string, trackpath string, authtoken string, mutoken string, mvmo
|
|||||||
}
|
}
|
||||||
return "", nil
|
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 ExtMvData (keyAndUrls string, savePath string)(error) {
|
||||||
// func DecryptMP4Auto(r io.Reader, keys []*Key, w io.Writer) error {
|
segments := strings.Split(keyAndUrls, ";")
|
||||||
// // Extract content key
|
key := segments[0]
|
||||||
// var key []byte
|
//fmt.Println(key)
|
||||||
// for _, k := range keys {
|
urls := segments[1:]
|
||||||
// if k.Type == wvpb.License_KeyContainer_CONTENT {
|
tempFile, err := os.CreateTemp("", "enc_mv_data-*.mp4")
|
||||||
// key = k.Key
|
if err != nil {
|
||||||
// break
|
fmt.Printf("创建文件失败:%v\n", err)
|
||||||
// }
|
return err
|
||||||
// }
|
}
|
||||||
// if key == nil {
|
defer tempFile.Close()
|
||||||
// return fmt.Errorf("no %s key type found in the provided key set", wvpb.License_KeyContainer_CONTENT)
|
defer os.Remove(tempFile.Name())
|
||||||
// }
|
|
||||||
// // Execute decryption
|
// 依次下载每个链接并写入文件
|
||||||
// return DecryptMP4(r, key, w)
|
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.
|
// 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 {
|
func DecryptMP4(r io.Reader, key []byte, w io.Writer) error {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user