mirror of
https://github.com/zhaarey/apple-music-downloader.git
synced 2025-10-23 15:11:05 +00:00
dev: MV dl (need n-m3u8dl-re and mp4decrypt)
This commit is contained in:
100
main.go
100
main.go
@@ -100,6 +100,16 @@ func checkUrl(url string) (string, string) {
|
||||
return matches[0][1], matches[0][2]
|
||||
}
|
||||
}
|
||||
func checkUrlMv(url string) (string) {
|
||||
pat := regexp.MustCompile(`^(?:https:\/\/(?:beta\.music|music)\.apple\.com\/(\w{2})(?:\/music-video|\/music-video\/.+))\/(?:id)?(\d[^\D]+)(?:$|\?)`)
|
||||
matches := pat.FindAllStringSubmatch(url, -1)
|
||||
|
||||
if matches == nil {
|
||||
return ""
|
||||
} else {
|
||||
return matches[0][2]
|
||||
}
|
||||
}
|
||||
func checkUrlSong(url string) (string, string) {
|
||||
pat := regexp.MustCompile(`^(?:https:\/\/(?:beta\.music|music)\.apple\.com\/(\w{2})(?:\/song|\/song\/.+))\/(?:id)?(\d[^\D]+)(?:$|\?)`)
|
||||
matches := pat.FindAllStringSubmatch(url, -1)
|
||||
@@ -583,7 +593,7 @@ func downloadTrack(trackNum int, trackTotal int, meta *structs.AutoGenerated, tr
|
||||
counter.Error++
|
||||
return
|
||||
}
|
||||
err := runv3.Run(track.ID, trackPath, token, mediaUserToken)
|
||||
_, err := runv3.Run(track.ID, trackPath, token, mediaUserToken, false)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to dl aac-lc:", err)
|
||||
counter.Error++
|
||||
@@ -1093,6 +1103,11 @@ func main() {
|
||||
return
|
||||
}
|
||||
os.Args = args
|
||||
//mv dl dev
|
||||
if strings.Contains(os.Args[0], "/music-video/") {
|
||||
_ = mvDownloader(checkUrlMv(os.Args[0]), Config.AlacSaveFolder, token, Config.MediaUserToken)
|
||||
return
|
||||
}
|
||||
if strings.Contains(os.Args[0], "/artist/") {
|
||||
urlArtistName, err := getUrlArtistName(os.Args[0], token)
|
||||
if err != nil {
|
||||
@@ -1153,6 +1168,89 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func mvDownloader(adamID string, saveDir string, token string, mediaUserToken string)(error){
|
||||
vidPath := filepath.Join(saveDir, fmt.Sprintf("%s.mp4", adamID))
|
||||
audPath := filepath.Join(saveDir, fmt.Sprintf("%s.m4a", adamID))
|
||||
mvOutPath := filepath.Join(saveDir, fmt.Sprintf("%s.mkv", adamID))
|
||||
exists, _ := fileExists(mvOutPath)
|
||||
if exists {
|
||||
fmt.Println("MV already exists locally.")
|
||||
return nil
|
||||
}
|
||||
mvm3u8url, _, _ := runv3.GetWebplayback(adamID, token, mediaUserToken, true)
|
||||
//videom3u8url, audiom3u8url , _ := mvQualitySelect(mvm3u8url)
|
||||
videom3u8url, _ := extractVideo(mvm3u8url)
|
||||
audiom3u8url, _ := extractMvAudio(mvm3u8url)
|
||||
//fmt.Println(videom3u8url)
|
||||
//fmt.Println(audiom3u8url)
|
||||
videokey, _ := runv3.Run(adamID, videom3u8url, token, mediaUserToken, true)
|
||||
audiokey, _ := runv3.Run(adamID, audiom3u8url, token, mediaUserToken, true)
|
||||
//fmt.Println(videokey)
|
||||
//fmt.Println(audiokey)
|
||||
cmd1 := exec.Command("n-m3u8dl-re", videom3u8url, "--key", videokey, "--decryption-engine", "MP4DECRYPT", "--save-dir", saveDir, "--save-name", adamID)
|
||||
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.Printf("MVvid Downloading...")
|
||||
if err := cmd1.Run(); err != nil {
|
||||
fmt.Printf("MVvid Download failed: %v\n", err)
|
||||
return err
|
||||
}
|
||||
fmt.Printf("\rMVvid Downloaded. \n")
|
||||
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...")
|
||||
if err := cmd3.Run(); err != nil {
|
||||
fmt.Printf("MV mux failed: %v\n", err)
|
||||
return err
|
||||
}
|
||||
fmt.Printf("\rMV Remuxed. \n")
|
||||
_ = os.Remove(vidPath)
|
||||
_ = os.Remove(audPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractMvAudio(c string) (string, error) {
|
||||
MediaUrl, err := url.Parse(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp, err := http.Get(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", errors.New(resp.Status)
|
||||
}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
videoString := string(body)
|
||||
from, listType, err := m3u8.DecodeFrom(strings.NewReader(videoString), true)
|
||||
if err != nil || listType != m3u8.MASTER {
|
||||
return "", errors.New("m3u8 not of media type")
|
||||
}
|
||||
video := from.(*m3u8.MasterPlaylist)
|
||||
var streamUrl *url.URL
|
||||
for _, variant := range video.Variants {
|
||||
for _, audiov := range variant.Alternatives {
|
||||
if audiov.GroupId == "audio-stereo-256" {
|
||||
streamUrl, _ = MediaUrl.Parse(audiov.URI)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if streamUrl == nil {
|
||||
return "", errors.New("no video codec found")
|
||||
}
|
||||
return streamUrl.String(), nil
|
||||
}
|
||||
|
||||
func conventSyllableTTMLToLRC(ttml string) (string, error) {
|
||||
parsedTTML := etree.NewDocument()
|
||||
err := parsedTTML.ReadFromString(ttml)
|
||||
|
||||
Reference in New Issue
Block a user