Merge pull request #44 from GenzPN/main
Add --debug, Fix download Dolby Audio and download 4:3 animation cover video
This commit is contained in:
commit
16f3ba6d83
309
main.go
309
main.go
@ -41,6 +41,7 @@ var (
|
|||||||
dl_select bool
|
dl_select bool
|
||||||
dl_song bool
|
dl_song bool
|
||||||
artist_select bool
|
artist_select bool
|
||||||
|
debug_mode bool
|
||||||
alac_max *int
|
alac_max *int
|
||||||
atmos_max *int
|
atmos_max *int
|
||||||
aac_type *string
|
aac_type *string
|
||||||
@ -428,7 +429,7 @@ func contains(slice []string, item string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 下载单曲逻辑
|
// 下载单曲逻辑
|
||||||
func downloadTrack(trackNum int, trackTotal int, meta *structs.AutoGenerated, track structs.TrackData, albumId, token, storefront, userToken, sanAlbumFolder, Codec string, counter *structs.Counter) {
|
func downloadTrack(trackNum int, trackTotal int, meta *structs.AutoGenerated, track structs.TrackData, albumId, token, storefront, mediaUserToken, sanAlbumFolder, Codec string, counter *structs.Counter) {
|
||||||
counter.Total++
|
counter.Total++
|
||||||
fmt.Printf("Track %d of %d:\n", trackNum, trackTotal)
|
fmt.Printf("Track %d of %d:\n", trackNum, trackTotal)
|
||||||
manifest, err := getInfoFromAdam(track.ID, token, storefront)
|
manifest, err := getInfoFromAdam(track.ID, token, storefront)
|
||||||
@ -514,8 +515,8 @@ func downloadTrack(trackNum int, trackTotal int, meta *structs.AutoGenerated, tr
|
|||||||
|
|
||||||
//get lrc
|
//get lrc
|
||||||
var lrc string = ""
|
var lrc string = ""
|
||||||
if userToken != "your-media-user-token" && (Config.EmbedLrc || Config.SaveLrcFile) {
|
if mediaUserToken != "" && len(mediaUserToken) > 10 {
|
||||||
ttml, err := getSongLyrics(track.ID, storefront, token, userToken)
|
ttml, err := getSongLyrics(track.ID, storefront, token, mediaUserToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to get lyrics")
|
fmt.Println("Failed to get lyrics")
|
||||||
} else if Config.LrcFormat == "ttml" {
|
} else if Config.LrcFormat == "ttml" {
|
||||||
@ -555,12 +556,12 @@ func downloadTrack(trackNum int, trackTotal int, meta *structs.AutoGenerated, tr
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if needDlAacLc {
|
if needDlAacLc {
|
||||||
if userToken == "your-media-user-token" {
|
if mediaUserToken == "" || len(mediaUserToken) <= 10 {
|
||||||
fmt.Println("media-user-token Unset!")
|
fmt.Println("Invalid media-user-token")
|
||||||
counter.Error++
|
counter.Error++
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := runv3.Run(track.ID, trackPath, token, userToken)
|
err := runv3.Run(track.ID, trackPath, token, mediaUserToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to dl aac-lc:", err)
|
fmt.Println("Failed to dl aac-lc:", err)
|
||||||
counter.Error++
|
counter.Error++
|
||||||
@ -621,7 +622,52 @@ func downloadTrack(trackNum int, trackTotal int, meta *structs.AutoGenerated, tr
|
|||||||
okDict[albumId] = append(okDict[albumId], trackNum)
|
okDict[albumId] = append(okDict[albumId], trackNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
func rip(albumId string, token string, storefront string, userToken string, urlArg_i string) error {
|
func rip(albumId string, token string, storefront string, mediaUserToken string, urlArg_i string) error {
|
||||||
|
meta, err := getMeta(albumId, token, storefront)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if debug_mode {
|
||||||
|
// Print album info
|
||||||
|
fmt.Println(meta.Data[0].Attributes.ArtistName)
|
||||||
|
fmt.Println(meta.Data[0].Attributes.Name)
|
||||||
|
|
||||||
|
for trackNum, track := range meta.Data[0].Relationships.Tracks.Data {
|
||||||
|
trackNum++
|
||||||
|
fmt.Printf("\nTrack %d of %d:\n", trackNum, len(meta.Data[0].Relationships.Tracks.Data))
|
||||||
|
fmt.Printf("%02d. %s\n", trackNum, track.Attributes.Name)
|
||||||
|
|
||||||
|
manifest, err := getInfoFromAdam(track.ID, token, storefront)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to get manifest for track %d: %v\n", trackNum, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var m3u8Url string
|
||||||
|
if manifest.Attributes.ExtendedAssetUrls.EnhancedHls != "" {
|
||||||
|
m3u8Url = manifest.Attributes.ExtendedAssetUrls.EnhancedHls
|
||||||
|
} else if mediaUserToken != "" && len(mediaUserToken) > 10 {
|
||||||
|
// Try to get m3u8 from device if media-user-token is set
|
||||||
|
m3u8Url, err = checkM3u8(track.ID, "song")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to get m3u8 from device for track %d: %v\n", trackNum, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if m3u8Url != "" {
|
||||||
|
_, err = extractMediaQuality(m3u8Url)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to extract quality info for track %d: %v\n", trackNum, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("\nNo audio formats available - valid media-user-token may be required")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil // Return directly without showing statistics
|
||||||
|
}
|
||||||
var Codec string
|
var Codec string
|
||||||
if dl_atmos {
|
if dl_atmos {
|
||||||
Codec = "ATMOS"
|
Codec = "ATMOS"
|
||||||
@ -630,11 +676,6 @@ func rip(albumId string, token string, storefront string, userToken string, urlA
|
|||||||
} else {
|
} else {
|
||||||
Codec = "ALAC"
|
Codec = "ALAC"
|
||||||
}
|
}
|
||||||
meta, err := getMeta(albumId, token, storefront)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Failed to get album metadata.\n")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var singerFoldername string
|
var singerFoldername string
|
||||||
if Config.ArtistFolderFormat != "" {
|
if Config.ArtistFolderFormat != "" {
|
||||||
if strings.Contains(albumId, "pl.") {
|
if strings.Contains(albumId, "pl.") {
|
||||||
@ -770,31 +811,63 @@ func rip(albumId string, token string, storefront string, userToken string, urlA
|
|||||||
//get animated artwork
|
//get animated artwork
|
||||||
if Config.SaveAnimatedArtwork && meta.Data[0].Attributes.EditorialVideo.MotionDetailSquare.Video != "" {
|
if Config.SaveAnimatedArtwork && meta.Data[0].Attributes.EditorialVideo.MotionDetailSquare.Video != "" {
|
||||||
fmt.Println("Found Animation Artwork.")
|
fmt.Println("Found Animation Artwork.")
|
||||||
motionvideoUrl, err := extractVideo(meta.Data[0].Attributes.EditorialVideo.MotionDetailSquare.Video)
|
|
||||||
|
// Download tall version
|
||||||
|
motionvideoUrlTall, err := extractVideo(meta.Data[0].Attributes.EditorialVideo.MotionDetailTall.Video)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("no motion video.\n", err)
|
fmt.Println("no motion video tall.\n", err)
|
||||||
}
|
|
||||||
exists, err := fileExists(filepath.Join(sanAlbumFolder, "animated_artwork.mp4"))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Failed to check if animated artwork exists.")
|
|
||||||
}
|
|
||||||
if exists {
|
|
||||||
fmt.Println("Animated artwork already exists locally.")
|
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Animation Artwork Downloading...")
|
exists, err := fileExists(filepath.Join(sanAlbumFolder, "animated_artwork_tall.mp4"))
|
||||||
cmd := exec.Command("ffmpeg", "-loglevel", "quiet", "-y", "-i", motionvideoUrl, "-c", "copy", filepath.Join(sanAlbumFolder, "animated_artwork.mp4"))
|
if err != nil {
|
||||||
if err := cmd.Run(); err != nil {
|
fmt.Println("Failed to check if animated artwork tall exists.")
|
||||||
fmt.Printf("animated artwork dl err: %v\n", err)
|
|
||||||
} else {
|
|
||||||
fmt.Println("Animation Artwork Downloaded")
|
|
||||||
}
|
}
|
||||||
if Config.EmbyAnimatedArtwork {
|
if exists {
|
||||||
cmd2 := exec.Command("ffmpeg", "-i", filepath.Join(sanAlbumFolder, "animated_artwork.mp4"), "-vf", "scale=440:-1", "-r", "24", "-f", "gif", filepath.Join(sanAlbumFolder, "folder.jpg"))
|
fmt.Println("Animated artwork tall already exists locally.")
|
||||||
if err := cmd2.Run(); err != nil {
|
} else {
|
||||||
fmt.Printf("animated artwork to gif err: %v\n", err)
|
fmt.Println("Animation Artwork Tall Downloading...")
|
||||||
|
cmd := exec.Command("ffmpeg", "-loglevel", "quiet", "-y", "-i", motionvideoUrlTall, "-c", "copy", filepath.Join(sanAlbumFolder, "animated_artwork_tall.mp4"))
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
fmt.Printf("animated artwork tall dl err: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Animation Artwork Tall Downloaded")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download square version
|
||||||
|
motionvideoUrlSquare, err := extractVideo(meta.Data[0].Attributes.EditorialVideo.MotionDetailSquare.Video)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("no motion video square.\n", err)
|
||||||
|
} else {
|
||||||
|
exists, err := fileExists(filepath.Join(sanAlbumFolder, "animated_artwork_square.mp4"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to check if animated artwork square exists.")
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
fmt.Println("Animated artwork square already exists locally.")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Animation Artwork Square Downloading...")
|
||||||
|
cmd := exec.Command("ffmpeg", "-loglevel", "quiet", "-y", "-i", motionvideoUrlSquare, "-c", "copy", filepath.Join(sanAlbumFolder, "animated_artwork_square.mp4"))
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
fmt.Printf("animated artwork square dl err: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Animation Artwork Square Downloaded")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if Config.EmbyAnimatedArtwork {
|
||||||
|
// Convert tall version to gif
|
||||||
|
cmd2 := exec.Command("ffmpeg", "-i", filepath.Join(sanAlbumFolder, "animated_artwork_tall.mp4"), "-vf", "scale=440:-1", "-r", "24", "-f", "gif", filepath.Join(sanAlbumFolder, "folder_tall.jpg"))
|
||||||
|
if err := cmd2.Run(); err != nil {
|
||||||
|
fmt.Printf("animated artwork tall to gif err: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert square version to gif
|
||||||
|
cmd3 := exec.Command("ffmpeg", "-i", filepath.Join(sanAlbumFolder, "animated_artwork_square.mp4"), "-vf", "scale=440:-1", "-r", "24", "-f", "gif", filepath.Join(sanAlbumFolder, "folder_square.jpg"))
|
||||||
|
if err := cmd3.Run(); err != nil {
|
||||||
|
fmt.Printf("animated artwork square to gif err: %v\n", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trackTotal := len(meta.Data[0].Relationships.Tracks.Data)
|
trackTotal := len(meta.Data[0].Relationships.Tracks.Data)
|
||||||
@ -812,7 +885,7 @@ func rip(albumId string, token string, storefront string, userToken string, urlA
|
|||||||
for trackNum, track := range meta.Data[0].Relationships.Tracks.Data {
|
for trackNum, track := range meta.Data[0].Relationships.Tracks.Data {
|
||||||
trackNum++
|
trackNum++
|
||||||
if urlArg_i == track.ID {
|
if urlArg_i == track.ID {
|
||||||
downloadTrack(trackNum, trackTotal, meta, track, albumId, token, storefront, userToken, sanAlbumFolder, Codec, &counter)
|
downloadTrack(trackNum, trackTotal, meta, track, albumId, token, storefront, mediaUserToken, sanAlbumFolder, Codec, &counter)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -866,7 +939,7 @@ func rip(albumId string, token string, storefront string, userToken string, urlA
|
|||||||
}
|
}
|
||||||
if isInArray(selected, trackNum) {
|
if isInArray(selected, trackNum) {
|
||||||
counter.Total++
|
counter.Total++
|
||||||
downloadTrack(trackNum, trackTotal, meta, track, albumId, token, storefront, userToken, sanAlbumFolder, Codec, &counter)
|
downloadTrack(trackNum, trackTotal, meta, track, albumId, token, storefront, mediaUserToken, sanAlbumFolder, Codec, &counter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -973,6 +1046,7 @@ func main() {
|
|||||||
pflag.BoolVar(&dl_select, "select", false, "Enable selective download")
|
pflag.BoolVar(&dl_select, "select", false, "Enable selective download")
|
||||||
pflag.BoolVar(&dl_song, "song", false, "Enable single song download mode")
|
pflag.BoolVar(&dl_song, "song", false, "Enable single song download mode")
|
||||||
pflag.BoolVar(&artist_select, "all-album", false, "Download all artist albums")
|
pflag.BoolVar(&artist_select, "all-album", false, "Download all artist albums")
|
||||||
|
pflag.BoolVar(&debug_mode, "debug", false, "Enable debug mode to show audio quality information")
|
||||||
alac_max = pflag.Int("alac-max", Config.AlacMax, "Specify the max quality for download alac")
|
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")
|
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")
|
aac_type = pflag.String("aac-type", Config.AacType, "Select AAC type, aac aac-binaural aac-downmix")
|
||||||
@ -1265,36 +1339,120 @@ func extractMediaQuality(b string) (string, error) {
|
|||||||
return "", errors.New("m3u8 not of master type")
|
return "", errors.New("m3u8 not of master type")
|
||||||
}
|
}
|
||||||
master := from.(*m3u8.MasterPlaylist)
|
master := from.(*m3u8.MasterPlaylist)
|
||||||
sort.Slice(master.Variants, func(i, j int) bool {
|
if debug_mode {
|
||||||
return master.Variants[i].AverageBandwidth > master.Variants[j].AverageBandwidth
|
fmt.Println("\nDebug: All Available Variants:")
|
||||||
})
|
fmt.Println("-----------------------------")
|
||||||
|
for _, variant := range master.Variants {
|
||||||
|
fmt.Printf("Codec: %s, Audio: %s, Bandwidth: %d\n",
|
||||||
|
variant.Codecs, variant.Audio, variant.Bandwidth)
|
||||||
|
}
|
||||||
|
fmt.Println("-----------------------------")
|
||||||
|
|
||||||
|
var hasAAC, hasLossless, hasHiRes, hasAtmos, hasDolbyAudio bool
|
||||||
|
var aacQuality, losslessQuality, hiResQuality, atmosQuality, dolbyAudioQuality string
|
||||||
|
|
||||||
|
// Check for all formats
|
||||||
|
for _, variant := range master.Variants {
|
||||||
|
if variant.Codecs == "mp4a.40.2" { // AAC
|
||||||
|
hasAAC = true
|
||||||
|
split := strings.Split(variant.Audio, "-")
|
||||||
|
if len(split) >= 3 {
|
||||||
|
bitrate, _ := strconv.Atoi(split[2])
|
||||||
|
currentBitrate := 0
|
||||||
|
if aacQuality != "" {
|
||||||
|
current := strings.Split(aacQuality, " | ")[2]
|
||||||
|
current = strings.Split(current, " ")[0]
|
||||||
|
currentBitrate, _ = strconv.Atoi(current)
|
||||||
|
}
|
||||||
|
if bitrate > currentBitrate {
|
||||||
|
aacQuality = fmt.Sprintf("AAC | 2 Channel | %d kbps", bitrate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if variant.Codecs == "ec-3" && strings.Contains(variant.Audio, "atmos") { // Dolby Atmos
|
||||||
|
hasAtmos = true
|
||||||
|
split := strings.Split(variant.Audio, "-")
|
||||||
|
if len(split) > 0 {
|
||||||
|
bitrateStr := split[len(split)-1]
|
||||||
|
// Remove leading "2" if present in "2768"
|
||||||
|
if len(bitrateStr) == 4 && bitrateStr[0] == '2' {
|
||||||
|
bitrateStr = bitrateStr[1:]
|
||||||
|
}
|
||||||
|
bitrate, _ := strconv.Atoi(bitrateStr)
|
||||||
|
currentBitrate := 0
|
||||||
|
if atmosQuality != "" {
|
||||||
|
current := strings.Split(strings.Split(atmosQuality, " | ")[2], " ")[0]
|
||||||
|
currentBitrate, _ = strconv.Atoi(current)
|
||||||
|
}
|
||||||
|
if bitrate > currentBitrate {
|
||||||
|
atmosQuality = fmt.Sprintf("E-AC-3 | 16 Channel | %d kbps", bitrate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if variant.Codecs == "alac" { // ALAC (Lossless or Hi-Res)
|
||||||
|
split := strings.Split(variant.Audio, "-")
|
||||||
|
if len(split) >= 3 {
|
||||||
|
bitDepth := split[len(split)-1]
|
||||||
|
sampleRate := split[len(split)-2]
|
||||||
|
sampleRateInt, _ := strconv.Atoi(sampleRate)
|
||||||
|
if sampleRateInt > 48000 { // Hi-Res
|
||||||
|
hasHiRes = true
|
||||||
|
hiResQuality = fmt.Sprintf("ALAC | 2 Channel | %s-bit/%d kHz", bitDepth, sampleRateInt/1000)
|
||||||
|
} else { // Standard Lossless
|
||||||
|
hasLossless = true
|
||||||
|
losslessQuality = fmt.Sprintf("ALAC | 2 Channel | %s-bit/%d kHz", bitDepth, sampleRateInt/1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if variant.Codecs == "ac-3" { // Dolby Audio
|
||||||
|
hasDolbyAudio = true
|
||||||
|
split := strings.Split(variant.Audio, "-")
|
||||||
|
if len(split) > 0 {
|
||||||
|
bitrate, _ := strconv.Atoi(split[len(split)-1])
|
||||||
|
dolbyAudioQuality = fmt.Sprintf("AC-3 | 16 Channel | %d kbps", bitrate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Available Audio Formats:")
|
||||||
|
fmt.Println("------------------------")
|
||||||
|
fmt.Printf("AAC : %s\n", formatAvailability(hasAAC, aacQuality))
|
||||||
|
fmt.Printf("Lossless : %s\n", formatAvailability(hasLossless, losslessQuality))
|
||||||
|
fmt.Printf("Hi-Res Lossless : %s\n", formatAvailability(hasHiRes, hiResQuality))
|
||||||
|
fmt.Printf("Dolby Atmos : %s\n", formatAvailability(hasAtmos, atmosQuality))
|
||||||
|
fmt.Printf("Dolby Audio : %s\n", formatAvailability(hasDolbyAudio, dolbyAudioQuality))
|
||||||
|
fmt.Println("------------------------")
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
var Quality string
|
var Quality string
|
||||||
for _, variant := range master.Variants {
|
for _, variant := range master.Variants {
|
||||||
if dl_aac {
|
if dl_atmos {
|
||||||
if variant.Codecs == "mp4a.40.2" {
|
if variant.Codecs == "ec-3" && strings.Contains(variant.Audio, "atmos") {
|
||||||
aacregex := regexp.MustCompile(`audio-stereo-\d+`)
|
|
||||||
replaced := aacregex.ReplaceAllString(variant.Audio, "aac")
|
|
||||||
split := strings.Split(variant.Audio, "-")
|
split := strings.Split(variant.Audio, "-")
|
||||||
if replaced == Config.AacType {
|
if len(split) > 0 {
|
||||||
Quality = fmt.Sprintf("%skbps", split[2])
|
Quality = fmt.Sprintf("%s kbps", split[len(split)-1])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if variant.Codecs == "ac-3" { // Add Dolby Audio support for --atmos flag
|
||||||
|
split := strings.Split(variant.Audio, "-")
|
||||||
|
if len(split) > 0 {
|
||||||
|
Quality = fmt.Sprintf("%s kbps", split[len(split)-1])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if dl_aac {
|
||||||
|
if variant.Codecs == "mp4a.40.2" {
|
||||||
|
split := strings.Split(variant.Audio, "-")
|
||||||
|
if len(split) >= 3 {
|
||||||
|
Quality = fmt.Sprintf("%s kbps", split[2])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if variant.Codecs == "alac" {
|
if variant.Codecs == "alac" {
|
||||||
split := strings.Split(variant.Audio, "-")
|
split := strings.Split(variant.Audio, "-")
|
||||||
length := len(split)
|
if len(split) >= 3 {
|
||||||
length_int, err := strconv.Atoi(split[length-2])
|
bitDepth := split[len(split)-1]
|
||||||
if err != nil {
|
sampleRate := split[len(split)-2]
|
||||||
return "", err
|
Quality = fmt.Sprintf("%s-bit / %s Hz", bitDepth, sampleRate)
|
||||||
}
|
|
||||||
if length_int <= Config.AlacMax {
|
|
||||||
HZ, err := strconv.Atoi(split[length-2])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
KHZ := float64(HZ) / 1000.0
|
|
||||||
Quality = fmt.Sprintf("%sB-%.1fkHz", split[length-1], KHZ)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1303,6 +1461,13 @@ func extractMediaQuality(b string) (string, error) {
|
|||||||
return Quality, nil
|
return Quality, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func formatAvailability(available bool, quality string) string {
|
||||||
|
if !available {
|
||||||
|
return "Not Available"
|
||||||
|
}
|
||||||
|
return quality
|
||||||
|
}
|
||||||
|
|
||||||
func extractMedia(b string) (string, error) {
|
func extractMedia(b string) (string, error) {
|
||||||
masterUrl, err := url.Parse(b)
|
masterUrl, err := url.Parse(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1332,30 +1497,37 @@ func extractMedia(b string) (string, error) {
|
|||||||
})
|
})
|
||||||
for _, variant := range master.Variants {
|
for _, variant := range master.Variants {
|
||||||
if dl_atmos {
|
if dl_atmos {
|
||||||
if variant.Codecs == "ec-3" {
|
if variant.Codecs == "ec-3" && strings.Contains(variant.Audio, "atmos") {
|
||||||
split := strings.Split(variant.Audio, "-")
|
if debug_mode {
|
||||||
length := len(split)
|
fmt.Printf("Debug: Found Dolby Atmos variant - %s (Bitrate: %d kbps)\n",
|
||||||
length_int, err := strconv.Atoi(split[length-1])
|
variant.Audio, variant.Bandwidth/1000)
|
||||||
|
}
|
||||||
|
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if length_int <= Config.AtmosMax {
|
streamUrl = streamUrlTemp
|
||||||
fmt.Printf("%s\n", variant.Audio)
|
break
|
||||||
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
} else if variant.Codecs == "ac-3" { // Add Dolby Audio support
|
||||||
if err != nil {
|
if debug_mode {
|
||||||
panic(err)
|
fmt.Printf("Debug: Found Dolby Audio variant - %s (Bitrate: %d kbps)\n",
|
||||||
}
|
variant.Audio, variant.Bandwidth/1000)
|
||||||
streamUrl = streamUrlTemp
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
streamUrl = streamUrlTemp
|
||||||
|
break
|
||||||
}
|
}
|
||||||
} else if dl_aac {
|
} else if dl_aac {
|
||||||
if variant.Codecs == "mp4a.40.2" {
|
if variant.Codecs == "mp4a.40.2" {
|
||||||
|
if debug_mode {
|
||||||
|
fmt.Printf("Debug: Found AAC variant - %s (Bitrate: %d)\n", variant.Audio, variant.Bandwidth)
|
||||||
|
}
|
||||||
aacregex := regexp.MustCompile(`audio-stereo-\d+`)
|
aacregex := regexp.MustCompile(`audio-stereo-\d+`)
|
||||||
replaced := aacregex.ReplaceAllString(variant.Audio, "aac")
|
replaced := aacregex.ReplaceAllString(variant.Audio, "aac")
|
||||||
//split := strings.Split(variant.Audio, "-")
|
|
||||||
if replaced == Config.AacType {
|
if replaced == Config.AacType {
|
||||||
fmt.Printf("%s\n", variant.Audio)
|
|
||||||
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -1373,7 +1545,6 @@ func extractMedia(b string) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if length_int <= Config.AlacMax {
|
if length_int <= Config.AlacMax {
|
||||||
fmt.Printf("%s-bit / %s Hz\n", split[length-1], split[length-2])
|
|
||||||
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -274,12 +274,12 @@ type AutoGenerated struct {
|
|||||||
} `json:"playParams"`
|
} `json:"playParams"`
|
||||||
IsCompilation bool `json:"isCompilation"`
|
IsCompilation bool `json:"isCompilation"`
|
||||||
EditorialVideo struct {
|
EditorialVideo struct {
|
||||||
|
MotionDetailTall struct {
|
||||||
|
Video string `json:"video"`
|
||||||
|
} `json:"motionDetailTall"`
|
||||||
MotionDetailSquare struct {
|
MotionDetailSquare struct {
|
||||||
Video string `json:"video"`
|
Video string `json:"video"`
|
||||||
} `json:"motionDetailSquare"`
|
} `json:"motionDetailSquare"`
|
||||||
MotionSquareVideo1x1 struct {
|
|
||||||
Video string `json:"video"`
|
|
||||||
} `json:"motionSquareVideo1x1"`
|
|
||||||
} `json:"editorialVideo"`
|
} `json:"editorialVideo"`
|
||||||
} `json:"attributes"`
|
} `json:"attributes"`
|
||||||
Relationships struct {
|
Relationships struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user