Skip to content

Commit

Permalink
add mv-audio-type mv-max
Browse files Browse the repository at this point in the history
  • Loading branch information
zhaarey committed Feb 11, 2025
1 parent 60942cd commit 560a6b4
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 19 deletions.
2 changes: 2 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ apple-master-choice : "[M]"
use-songinfo-for-playlist: false
#if set true,will download album cover for playlist
dl-albumcover-for-playlist: false
mv-audio-type: atmos #atmos ac3 aac
mv-max: 2160
107 changes: 88 additions & 19 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ var (
debug_mode bool
alac_max *int
atmos_max *int
mv_max *int
mv_audio_type *string
aac_type *string
Config structs.ConfigSet
counter structs.Counter
Expand Down Expand Up @@ -100,7 +102,7 @@ func checkUrl(url string) (string, string) {
return matches[0][1], matches[0][2]
}
}
func checkUrlMv(url string) (string) {
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)

Expand Down Expand Up @@ -478,7 +480,7 @@ func downloadTrack(trackNum int, trackTotal int, meta *structs.AutoGenerated, tr
return
}
err := mvDownloader(track.ID, sanAlbumFolder, token, mediaUserToken)
if err !=nil {
if err != nil {
fmt.Println("\u26A0 Failed to dl MV:", err)
counter.Error++
return
Expand Down Expand Up @@ -1104,6 +1106,8 @@ func main() {
alac_max = pflag.Int("alac-max", Config.AlacMax, "Specify the max quality for download alac")
atmos_max = pflag.Int("atmos-max", Config.AtmosMax, "Specify the max quality for download atmos")
aac_type = pflag.String("aac-type", Config.AacType, "Select AAC type, aac aac-binaural aac-downmix")
mv_audio_type = pflag.String("mv-audio-type", Config.MVAudioType, "Select MV audio type, atmos ac3 aac")
mv_max = pflag.Int("mv-max", Config.MVMax, "Specify the max quality for download MV")

// Custom usage message for help
pflag.Usage = func() {
Expand All @@ -1117,6 +1121,8 @@ func main() {
Config.AlacMax = *alac_max
Config.AtmosMax = *atmos_max
Config.AacType = *aac_type
Config.MVAudioType = *mv_audio_type
Config.MVMax = *mv_max

args := pflag.Args()
if len(args) == 0 {
Expand Down Expand Up @@ -1164,7 +1170,7 @@ func main() {
continue
}
err := mvDownloader(checkUrlMv(urlRaw), Config.AlacSaveFolder, token, Config.MediaUserToken)
if err !=nil {
if err != nil {
fmt.Println("\u26A0 Failed to dl MV:", err)
counter.Error++
continue
Expand Down Expand Up @@ -1209,10 +1215,10 @@ func main() {
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_vid.mp4", 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.mp4", adamID))
exists, _ := fileExists(mvOutPath)
if exists {
fmt.Println("MV already exists locally.")
Expand All @@ -1222,7 +1228,6 @@ func mvDownloader(adamID string, saveDir string, token string, mediaUserToken st
//videom3u8url, audiom3u8url , _ := mvQualitySelect(mvm3u8url)
videom3u8url, _ := extractVideo(mvm3u8url)
audiom3u8url, _ := extractMvAudio(mvm3u8url)
//fmt.Println(videom3u8url)
//fmt.Println(audiom3u8url)

videokeyAndUrls, _ := runv3.Run(adamID, videom3u8url, token, mediaUserToken, true)
Expand Down Expand Up @@ -1255,37 +1260,77 @@ func extractMvAudio(c string) (string, error) {
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

var audioPriority = []string{"audio-atmos", "audio-ac3", "audio-stereo-256"}
if Config.MVAudioType == "ac3" {
audioPriority = []string{"audio-ac3", "audio-stereo-256"}
} else if Config.MVAudioType == "aac" {
audioPriority = []string{"audio-stereo-256"}
}

re := regexp.MustCompile(`_gr(\d+)_`)

type AudioStream struct {
URL string
Rank int
GroupID string
}
var audioStreams []AudioStream

for _, variant := range video.Variants {
for _, audiov := range variant.Alternatives {
if audiov.GroupId == "audio-stereo-256" {
streamUrl, _ = MediaUrl.Parse(audiov.URI)
break
if audiov.URI != "" {
for _, priority := range audioPriority {
if audiov.GroupId == priority {
matches := re.FindStringSubmatch(audiov.URI)
if len(matches) == 2 {
var rank int
fmt.Sscanf(matches[1], "%d", &rank)
streamUrl, _ := MediaUrl.Parse(audiov.URI)
audioStreams = append(audioStreams, AudioStream{
URL: streamUrl.String(),
Rank: rank,
GroupID: audiov.GroupId,
})
}
}
}
}
}
}
if streamUrl == nil {
return "", errors.New("no video codec found")

if len(audioStreams) == 0 {
return "", errors.New("no suitable audio stream found")
}
return streamUrl.String(), nil

sort.Slice(audioStreams, func(i, j int) bool {
return audioStreams[i].Rank > audioStreams[j].Rank
})

return audioStreams[0].URL, nil
}

func conventSyllableTTMLToLRC(ttml string) (string, error) {
Expand Down Expand Up @@ -1775,38 +1820,62 @@ func extractVideo(c string) (string, error) {
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)

re := regexp.MustCompile(`_(\d+)x(\d+)_`)

var streamUrl *url.URL
sort.Slice(video.Variants, func(i, j int) bool {
return video.Variants[i].AverageBandwidth > video.Variants[j].AverageBandwidth
})
if len(video.Variants) > 0 {
highestBandwidthVariant := video.Variants[0]
streamUrl, err = MediaUrl.Parse(highestBandwidthVariant.URI)
if err != nil {
return "", err

maxHeight := Config.MVMax

for _, variant := range video.Variants {
matches := re.FindStringSubmatch(variant.URI)
if len(matches) == 3 {
height := matches[2]
var h int
_, err := fmt.Sscanf(height, "%d", &h)
if err != nil {
continue
}
if h <= maxHeight {
streamUrl, err = MediaUrl.Parse(variant.URI)
if err != nil {
return "", err
}
break
}
}
}

if streamUrl == nil {
return "", errors.New("no video codec found")
return "", errors.New("no suitable video stream found")
}

return streamUrl.String(), nil
}

Expand Down
2 changes: 2 additions & 0 deletions utils/structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ type ConfigSet struct {
LimitMax int `yaml:"limit-max"`
UseSongInfoForPlaylist bool `yaml:"use-songinfo-for-playlist"`
DlAlbumcoverForPlaylist bool `yaml:"dl-albumcover-for-playlist"`
MVAudioType string `yaml:"mv-audio-type"`
MVMax int `yaml:"mv-max"`
}

type Counter struct {
Expand Down

0 comments on commit 560a6b4

Please sign in to comment.