diff --git a/main.go b/main.go index 9f9c1d4..c750756 100644 --- a/main.go +++ b/main.go @@ -442,7 +442,7 @@ func ripTrack(track *task.Track, token string, mediaUserToken string) { counter.Unavailable++ return } - fmt.Println("Unavailable, Try DL AAC-LC") + fmt.Println("Unavailable, trying to dl aac-lc") needDlAacLc = true } needCheck := false @@ -463,7 +463,7 @@ func ripTrack(track *task.Track, token string, mediaUserToken string) { var Quality string if strings.Contains(Config.SongFileFormat, "Quality") { if dl_atmos { - Quality = fmt.Sprintf("%dkbps", Config.AtmosMax-2000) + Quality = fmt.Sprintf("%dKbps", Config.AtmosMax-2000) } else if needDlAacLc { Quality = "256Kbps" } else { @@ -549,6 +549,10 @@ func ripTrack(track *task.Track, token string, mediaUserToken string) { _, err := runv3.Run(track.ID, trackPath, token, mediaUserToken, false) if err != nil { fmt.Println("Failed to dl aac-lc:", err) + if err.Error() == "Unavailable"{ + counter.Unavailable++ + return + } counter.Error++ return } @@ -903,9 +907,9 @@ func ripAlbum(albumId string, token string, storefront string, mediaUserToken st var Quality string if strings.Contains(Config.AlbumFolderFormat, "Quality") { 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" { - Quality = "256kbps" + Quality = "256Kbps" } else { manifest1, err := ampapi.GetSongResp(storefront, meta.Data[0].Relationships.Tracks.Data[0].ID, album.Language, token) if err != nil { @@ -913,7 +917,7 @@ func ripAlbum(albumId string, token string, storefront string, mediaUserToken st } else { if manifest1.Data[0].Attributes.ExtendedAssetUrls.EnhancedHls == "" { Codec = "AAC" - Quality = "256kbps" + Quality = "256Kbps" //fmt.Println("Unavailable.\n") } else { needCheck := false @@ -1180,7 +1184,7 @@ func ripPlaylist(playlistId string, token string, storefront string, mediaUserTo var Quality string if strings.Contains(Config.AlbumFolderFormat, "Quality") { 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" { Quality = "256Kbps" } else { @@ -1945,7 +1949,7 @@ func extractMedia(b string, more_mode bool) (string, string, error) { currentBitrate, _ = strconv.Atoi(current) } 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 @@ -1964,7 +1968,7 @@ func extractMedia(b string, more_mode bool) (string, string, error) { currentBitrate, _ = strconv.Atoi(current) } 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) @@ -1986,7 +1990,7 @@ func extractMedia(b string, more_mode bool) (string, string, error) { 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) + 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 variant.Codecs == "ec-3" && strings.Contains(variant.Audio, "atmos") { 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) } split := strings.Split(variant.Audio, "-") @@ -2025,12 +2029,12 @@ func extractMedia(b string, more_mode bool) (string, string, error) { return "", "", err } streamUrl = streamUrlTemp - Quality = fmt.Sprintf("%s kbps", split[len(split)-1]) + Quality = fmt.Sprintf("%s Kbps", split[len(split)-1]) break } } else if variant.Codecs == "ac-3" { // Add Dolby Audio support 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) } streamUrlTemp, err := masterUrl.Parse(variant.URI) @@ -2039,7 +2043,7 @@ func extractMedia(b string, more_mode bool) (string, string, error) { } streamUrl = streamUrlTemp split := strings.Split(variant.Audio, "-") - Quality = fmt.Sprintf("%s kbps", split[len(split)-1]) + Quality = fmt.Sprintf("%s Kbps", split[len(split)-1]) break } } else if dl_aac { @@ -2059,7 +2063,7 @@ func extractMedia(b string, more_mode bool) (string, string, error) { } streamUrl = streamUrlTemp split := strings.Split(variant.Audio, "-") - Quality = fmt.Sprintf("%s kbps", split[2]) + Quality = fmt.Sprintf("%s Kbps", split[2]) break } } diff --git a/utils/runv3/runv3.go b/utils/runv3/runv3.go index 699fe52..1bf3404 100644 --- a/utils/runv3/runv3.go +++ b/utils/runv3/runv3.go @@ -25,6 +25,7 @@ import ( "net/http" "os/exec" "strings" + "sync" "github.com/grafov/m3u8" "github.com/schollz/progressbar/v3" @@ -166,7 +167,7 @@ func GetWebplayback(adamId string, authtoken string, mutoken string, mvmode bool continue } } - return "", "", nil + return "", "", errors.New("Unavailable") } type Songlist struct { @@ -355,35 +356,56 @@ func ExtMvData(keyAndUrls string, savePath string) error { fmt.Printf("创建文件失败:%v\n", err) return err } - defer tempFile.Close() defer os.Remove(tempFile.Name()) - + defer tempFile.Close() // 依次下载每个链接并写入文件 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) + pipeReaders := make([]*io.PipeReader, len(urls)) + var wg sync.WaitGroup + //最多同时5个下载请求 + 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 } - if resp.StatusCode != http.StatusOK { - fmt.Printf("链接 %s 响应失败:%v\n", url, resp.Status) - 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) + pipeReaders[i].Close() // 及时关闭 read + //fmt.Printf("写入 %d 成功\n", i) } + + // 等待所有下载任务完成 + wg.Wait() tempFile.Close() fmt.Println("\nDownloaded.")