mirror of
https://github.com/zhaarey/apple-music-downloader.git
synced 2025-10-23 15:11:05 +00:00
opt: mv and radio dl speed
This commit is contained in:
32
main.go
32
main.go
@@ -442,7 +442,7 @@ func ripTrack(track *task.Track, token string, mediaUserToken string) {
|
|||||||
counter.Unavailable++
|
counter.Unavailable++
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Println("Unavailable, Try DL AAC-LC")
|
fmt.Println("Unavailable, trying to dl aac-lc")
|
||||||
needDlAacLc = true
|
needDlAacLc = true
|
||||||
}
|
}
|
||||||
needCheck := false
|
needCheck := false
|
||||||
@@ -463,7 +463,7 @@ func ripTrack(track *task.Track, token string, mediaUserToken string) {
|
|||||||
var Quality string
|
var Quality string
|
||||||
if strings.Contains(Config.SongFileFormat, "Quality") {
|
if strings.Contains(Config.SongFileFormat, "Quality") {
|
||||||
if dl_atmos {
|
if dl_atmos {
|
||||||
Quality = fmt.Sprintf("%dkbps", Config.AtmosMax-2000)
|
Quality = fmt.Sprintf("%dKbps", Config.AtmosMax-2000)
|
||||||
} else if needDlAacLc {
|
} else if needDlAacLc {
|
||||||
Quality = "256Kbps"
|
Quality = "256Kbps"
|
||||||
} else {
|
} else {
|
||||||
@@ -549,6 +549,10 @@ func ripTrack(track *task.Track, token string, mediaUserToken string) {
|
|||||||
_, err := runv3.Run(track.ID, trackPath, token, mediaUserToken, false)
|
_, err := runv3.Run(track.ID, trackPath, token, mediaUserToken, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to dl aac-lc:", err)
|
fmt.Println("Failed to dl aac-lc:", err)
|
||||||
|
if err.Error() == "Unavailable"{
|
||||||
|
counter.Unavailable++
|
||||||
|
return
|
||||||
|
}
|
||||||
counter.Error++
|
counter.Error++
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -903,9 +907,9 @@ func ripAlbum(albumId string, token string, storefront string, mediaUserToken st
|
|||||||
var Quality string
|
var Quality string
|
||||||
if strings.Contains(Config.AlbumFolderFormat, "Quality") {
|
if strings.Contains(Config.AlbumFolderFormat, "Quality") {
|
||||||
if dl_atmos {
|
if dl_atmos {
|
||||||
Quality = fmt.Sprintf("%dkbps", Config.AtmosMax-2000)
|
Quality = fmt.Sprintf("%dKbps", Config.AtmosMax-2000)
|
||||||
} else if dl_aac && Config.AacType == "aac-lc" {
|
} else if dl_aac && Config.AacType == "aac-lc" {
|
||||||
Quality = "256kbps"
|
Quality = "256Kbps"
|
||||||
} else {
|
} else {
|
||||||
manifest1, err := ampapi.GetSongResp(storefront, meta.Data[0].Relationships.Tracks.Data[0].ID, album.Language, token)
|
manifest1, err := ampapi.GetSongResp(storefront, meta.Data[0].Relationships.Tracks.Data[0].ID, album.Language, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -913,7 +917,7 @@ func ripAlbum(albumId string, token string, storefront string, mediaUserToken st
|
|||||||
} else {
|
} else {
|
||||||
if manifest1.Data[0].Attributes.ExtendedAssetUrls.EnhancedHls == "" {
|
if manifest1.Data[0].Attributes.ExtendedAssetUrls.EnhancedHls == "" {
|
||||||
Codec = "AAC"
|
Codec = "AAC"
|
||||||
Quality = "256kbps"
|
Quality = "256Kbps"
|
||||||
//fmt.Println("Unavailable.\n")
|
//fmt.Println("Unavailable.\n")
|
||||||
} else {
|
} else {
|
||||||
needCheck := false
|
needCheck := false
|
||||||
@@ -1180,7 +1184,7 @@ func ripPlaylist(playlistId string, token string, storefront string, mediaUserTo
|
|||||||
var Quality string
|
var Quality string
|
||||||
if strings.Contains(Config.AlbumFolderFormat, "Quality") {
|
if strings.Contains(Config.AlbumFolderFormat, "Quality") {
|
||||||
if dl_atmos {
|
if dl_atmos {
|
||||||
Quality = fmt.Sprintf("%dkbps", Config.AtmosMax-2000)
|
Quality = fmt.Sprintf("%dKbps", Config.AtmosMax-2000)
|
||||||
} else if dl_aac && Config.AacType == "aac-lc" {
|
} else if dl_aac && Config.AacType == "aac-lc" {
|
||||||
Quality = "256Kbps"
|
Quality = "256Kbps"
|
||||||
} else {
|
} else {
|
||||||
@@ -1945,7 +1949,7 @@ func extractMedia(b string, more_mode bool) (string, string, error) {
|
|||||||
currentBitrate, _ = strconv.Atoi(current)
|
currentBitrate, _ = strconv.Atoi(current)
|
||||||
}
|
}
|
||||||
if bitrate > currentBitrate {
|
if bitrate > currentBitrate {
|
||||||
aacQuality = fmt.Sprintf("AAC | 2 Channel | %d kbps", bitrate)
|
aacQuality = fmt.Sprintf("AAC | 2 Channel | %d Kbps", bitrate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if variant.Codecs == "ec-3" && strings.Contains(variant.Audio, "atmos") { // Dolby Atmos
|
} else if variant.Codecs == "ec-3" && strings.Contains(variant.Audio, "atmos") { // Dolby Atmos
|
||||||
@@ -1964,7 +1968,7 @@ func extractMedia(b string, more_mode bool) (string, string, error) {
|
|||||||
currentBitrate, _ = strconv.Atoi(current)
|
currentBitrate, _ = strconv.Atoi(current)
|
||||||
}
|
}
|
||||||
if bitrate > currentBitrate {
|
if bitrate > currentBitrate {
|
||||||
atmosQuality = fmt.Sprintf("E-AC-3 | 16 Channel | %d kbps", bitrate)
|
atmosQuality = fmt.Sprintf("E-AC-3 | 16 Channel | %d Kbps", bitrate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if variant.Codecs == "alac" { // ALAC (Lossless or Hi-Res)
|
} else if variant.Codecs == "alac" { // ALAC (Lossless or Hi-Res)
|
||||||
@@ -1986,7 +1990,7 @@ func extractMedia(b string, more_mode bool) (string, string, error) {
|
|||||||
split := strings.Split(variant.Audio, "-")
|
split := strings.Split(variant.Audio, "-")
|
||||||
if len(split) > 0 {
|
if len(split) > 0 {
|
||||||
bitrate, _ := strconv.Atoi(split[len(split)-1])
|
bitrate, _ := strconv.Atoi(split[len(split)-1])
|
||||||
dolbyAudioQuality = fmt.Sprintf("AC-3 | 16 Channel | %d kbps", bitrate)
|
dolbyAudioQuality = fmt.Sprintf("AC-3 | 16 Channel | %d Kbps", bitrate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2007,7 +2011,7 @@ func extractMedia(b string, more_mode bool) (string, string, error) {
|
|||||||
if dl_atmos {
|
if dl_atmos {
|
||||||
if variant.Codecs == "ec-3" && strings.Contains(variant.Audio, "atmos") {
|
if variant.Codecs == "ec-3" && strings.Contains(variant.Audio, "atmos") {
|
||||||
if debug_mode && !more_mode {
|
if debug_mode && !more_mode {
|
||||||
fmt.Printf("Debug: Found Dolby Atmos variant - %s (Bitrate: %d kbps)\n",
|
fmt.Printf("Debug: Found Dolby Atmos variant - %s (Bitrate: %d Kbps)\n",
|
||||||
variant.Audio, variant.Bandwidth/1000)
|
variant.Audio, variant.Bandwidth/1000)
|
||||||
}
|
}
|
||||||
split := strings.Split(variant.Audio, "-")
|
split := strings.Split(variant.Audio, "-")
|
||||||
@@ -2025,12 +2029,12 @@ func extractMedia(b string, more_mode bool) (string, string, error) {
|
|||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
streamUrl = streamUrlTemp
|
streamUrl = streamUrlTemp
|
||||||
Quality = fmt.Sprintf("%s kbps", split[len(split)-1])
|
Quality = fmt.Sprintf("%s Kbps", split[len(split)-1])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else if variant.Codecs == "ac-3" { // Add Dolby Audio support
|
} else if variant.Codecs == "ac-3" { // Add Dolby Audio support
|
||||||
if debug_mode && !more_mode {
|
if debug_mode && !more_mode {
|
||||||
fmt.Printf("Debug: Found Dolby Audio variant - %s (Bitrate: %d kbps)\n",
|
fmt.Printf("Debug: Found Dolby Audio variant - %s (Bitrate: %d Kbps)\n",
|
||||||
variant.Audio, variant.Bandwidth/1000)
|
variant.Audio, variant.Bandwidth/1000)
|
||||||
}
|
}
|
||||||
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
||||||
@@ -2039,7 +2043,7 @@ func extractMedia(b string, more_mode bool) (string, string, error) {
|
|||||||
}
|
}
|
||||||
streamUrl = streamUrlTemp
|
streamUrl = streamUrlTemp
|
||||||
split := strings.Split(variant.Audio, "-")
|
split := strings.Split(variant.Audio, "-")
|
||||||
Quality = fmt.Sprintf("%s kbps", split[len(split)-1])
|
Quality = fmt.Sprintf("%s Kbps", split[len(split)-1])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else if dl_aac {
|
} else if dl_aac {
|
||||||
@@ -2059,7 +2063,7 @@ func extractMedia(b string, more_mode bool) (string, string, error) {
|
|||||||
}
|
}
|
||||||
streamUrl = streamUrlTemp
|
streamUrl = streamUrlTemp
|
||||||
split := strings.Split(variant.Audio, "-")
|
split := strings.Split(variant.Audio, "-")
|
||||||
Quality = fmt.Sprintf("%s kbps", split[2])
|
Quality = fmt.Sprintf("%s Kbps", split[2])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/grafov/m3u8"
|
"github.com/grafov/m3u8"
|
||||||
"github.com/schollz/progressbar/v3"
|
"github.com/schollz/progressbar/v3"
|
||||||
@@ -166,7 +167,7 @@ func GetWebplayback(adamId string, authtoken string, mutoken string, mvmode bool
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", "", nil
|
return "", "", errors.New("Unavailable")
|
||||||
}
|
}
|
||||||
|
|
||||||
type Songlist struct {
|
type Songlist struct {
|
||||||
@@ -355,35 +356,56 @@ func ExtMvData(keyAndUrls string, savePath string) error {
|
|||||||
fmt.Printf("创建文件失败:%v\n", err)
|
fmt.Printf("创建文件失败:%v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer tempFile.Close()
|
|
||||||
defer os.Remove(tempFile.Name())
|
defer os.Remove(tempFile.Name())
|
||||||
|
defer tempFile.Close()
|
||||||
// 依次下载每个链接并写入文件
|
// 依次下载每个链接并写入文件
|
||||||
bar := progressbar.DefaultBytes(
|
bar := progressbar.DefaultBytes(
|
||||||
-1,
|
-1,
|
||||||
"Downloading...",
|
"Downloading...",
|
||||||
)
|
)
|
||||||
barWriter := io.MultiWriter(tempFile, bar)
|
barWriter := io.MultiWriter(tempFile, bar)
|
||||||
for _, url := range urls {
|
pipeReaders := make([]*io.PipeReader, len(urls))
|
||||||
resp, err := http.Get(url)
|
var wg sync.WaitGroup
|
||||||
if err != nil {
|
//最多同时5个下载请求
|
||||||
fmt.Printf("下载链接 %s 失败:%v\n", url, err)
|
sem :=make(chan int, 10)
|
||||||
|
go func(pipeReaders []*io.PipeReader) {
|
||||||
|
for i, url := range urls {
|
||||||
|
pr, pw := io.Pipe()
|
||||||
|
pipeReaders[i] = pr
|
||||||
|
sem <- 1
|
||||||
|
wg.Add(1)
|
||||||
|
go func(i int, url string, pw *io.PipeWriter) {
|
||||||
|
//fmt.Printf("协程 %d 开始\n", i)
|
||||||
|
defer wg.Done()
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
// 出错时,通过 CloseWithError 通知后续读取端
|
||||||
|
pw.CloseWithError(err)
|
||||||
|
fmt.Printf("下载 %s 失败: %v\n", url, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
// 将 HTTP 响应体通过 pipe 写出(实现流式传输)
|
||||||
|
_, err = io.Copy(pw, resp.Body)
|
||||||
|
// 将可能的错误传递给 pipe
|
||||||
|
pw.CloseWithError(err)
|
||||||
|
}(i, url, pw)
|
||||||
|
}
|
||||||
|
}(pipeReaders)
|
||||||
|
// 按顺序读取每个 pipe 的数据并写入文件
|
||||||
|
for i := range len(urls) {
|
||||||
|
<-sem
|
||||||
|
//fmt.Printf("写入 %d 开始\n", i)
|
||||||
|
if _, err := io.Copy(barWriter, pipeReaders[i]); err != nil {
|
||||||
|
fmt.Printf("写入第 %d 部分失败: %v\n", i+1, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if resp.StatusCode != http.StatusOK {
|
pipeReaders[i].Close() // 及时关闭 read
|
||||||
fmt.Printf("链接 %s 响应失败:%v\n", url, resp.Status)
|
//fmt.Printf("写入 %d 成功\n", i)
|
||||||
return errors.New(resp.Status)
|
|
||||||
}
|
|
||||||
// 将响应体写入输出文件
|
|
||||||
_, 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 等待所有下载任务完成
|
||||||
|
wg.Wait()
|
||||||
tempFile.Close()
|
tempFile.Close()
|
||||||
fmt.Println("\nDownloaded.")
|
fmt.Println("\nDownloaded.")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user