|
|
|
@ -4,6 +4,7 @@ import ( |
|
|
|
|
"bytes" |
|
|
|
|
"encoding/binary" |
|
|
|
|
"encoding/json" |
|
|
|
|
"gopkg.in/yaml.v2" |
|
|
|
|
"errors" |
|
|
|
|
"fmt" |
|
|
|
|
"io" |
|
|
|
@ -34,6 +35,18 @@ const ( |
|
|
|
|
var ( |
|
|
|
|
forbiddenNames = regexp.MustCompile(`[/\\<>:"|?*]`) |
|
|
|
|
) |
|
|
|
|
type Config struct { |
|
|
|
|
MediaUserToken string `yaml:"media-user-token"` |
|
|
|
|
SaveLrcFile bool `yaml:"save-lrc-file"`
|
|
|
|
|
EmbedLrc bool `yaml:"embed-lrc"` |
|
|
|
|
EmbedCover bool `yaml:"embed-cover"` |
|
|
|
|
CoverSize string `yaml:"cover-size"` |
|
|
|
|
CoverFormat string `yaml:"cover-format"` |
|
|
|
|
AlacSaveFolder string `yaml:"alac-save-folder"` |
|
|
|
|
AtmosSaveFolder string `yaml:"atmos-save-folder"` |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var config Config |
|
|
|
|
var oktrackNum int = 0 |
|
|
|
|
var trackTotalnum int = 0 |
|
|
|
|
|
|
|
|
@ -48,6 +61,19 @@ type SongInfo struct { |
|
|
|
|
alacParam *Alac |
|
|
|
|
samples []SampleInfo |
|
|
|
|
} |
|
|
|
|
func loadConfig() error { |
|
|
|
|
// 读取config.yaml文件内容
|
|
|
|
|
data, err := ioutil.ReadFile("config.yaml") |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
// 将yaml解析到config变量中
|
|
|
|
|
err = yaml.Unmarshal(data, &config) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *SongInfo) Duration() (ret uint64) { |
|
|
|
|
for i := range s.samples { |
|
|
|
@ -1030,7 +1056,7 @@ func writeCover(sanAlbumFolder, url string) error { |
|
|
|
|
if exists { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
url = strings.Replace(url, "{w}x{h}", "5000x5000", 1) |
|
|
|
|
url = strings.Replace(url, "{w}x{h}", config.CoverSize, 1) |
|
|
|
|
req, err := http.NewRequest("GET", url, nil) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
@ -1081,7 +1107,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro |
|
|
|
|
singerFoldername = strings.ReplaceAll(singerFoldername, ".", "") |
|
|
|
|
} |
|
|
|
|
singerFoldername = strings.TrimSpace(singerFoldername) |
|
|
|
|
singerFolder := filepath.Join("AM-DL downloads", forbiddenNames.ReplaceAllString(singerFoldername, "_")) |
|
|
|
|
singerFolder := filepath.Join(config.AlacSaveFolder, forbiddenNames.ReplaceAllString(singerFoldername, "_")) |
|
|
|
|
albumFolder := fmt.Sprintf("%s", meta.Data[0].Attributes.Name) |
|
|
|
|
if strings.HasSuffix(albumFolder, ".") { |
|
|
|
|
albumFolder = strings.ReplaceAll(albumFolder, ".", "") |
|
|
|
@ -1113,7 +1139,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro |
|
|
|
|
lrcFilename := fmt.Sprintf("%02d. %s.lrc", trackNum, forbiddenNames.ReplaceAllString(track.Attributes.Name, "_")) |
|
|
|
|
trackPath := filepath.Join(sanAlbumFolder, filename) |
|
|
|
|
var lrc string = "" |
|
|
|
|
if userToken != "" { |
|
|
|
|
if userToken != "" && (config.EmbedLrc || config.SaveLrcFile) { |
|
|
|
|
ttml, err := getSongLyrics(track.ID, storefront, token, userToken) |
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Println("Failed to get lyrics") |
|
|
|
@ -1122,9 +1148,14 @@ func rip(albumId string, token string, storefront string, userToken string) erro |
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Printf("Failed to parse lyrics: %s \n", err) |
|
|
|
|
} else { |
|
|
|
|
err := writeLyrics(sanAlbumFolder, lrcFilename, lrc) |
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Printf("Failed to write lyrics") |
|
|
|
|
if config.SaveLrcFile { |
|
|
|
|
err := writeLyrics(sanAlbumFolder, lrcFilename, lrc) |
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Printf("Failed to write lyrics") |
|
|
|
|
} |
|
|
|
|
if !config.EmbedLrc { |
|
|
|
|
lrc = "" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1168,7 +1199,9 @@ func rip(albumId string, token string, storefront string, userToken string) erro |
|
|
|
|
} |
|
|
|
|
tags := []string{ |
|
|
|
|
fmt.Sprintf("lyrics=%s", lrc), |
|
|
|
|
fmt.Sprintf("cover=%s/cover.jpg", sanAlbumFolder), |
|
|
|
|
} |
|
|
|
|
if config.EmbedCover { |
|
|
|
|
tags = append(tags, fmt.Sprintf("cover=%s/cover.%s", sanAlbumFolder, config.CoverFormat)) |
|
|
|
|
} |
|
|
|
|
tagsString := strings.Join(tags, ":") |
|
|
|
|
cmd := exec.Command("MP4Box", "-itags", tagsString, trackPath) |
|
|
|
@ -1182,12 +1215,10 @@ func rip(albumId string, token string, storefront string, userToken string) erro |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func main() { |
|
|
|
|
var mediaUserToken string |
|
|
|
|
if _, err := os.Stat("media-user-token.txt"); err == nil { |
|
|
|
|
file, err := os.ReadFile("media-user-token.txt") |
|
|
|
|
if err == nil && file != nil { |
|
|
|
|
mediaUserToken = string(file) |
|
|
|
|
} |
|
|
|
|
err := loadConfig() |
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Printf("load config failed: %v", err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
token, err := getToken() |
|
|
|
|
if err != nil { |
|
|
|
|