add limit folder length and select all album command

pull/26/head
zhaarey 2 months ago
parent d9fa2202b4
commit e77cd8291d
  1. 12
      README.md
  2. 1
      config.yaml
  3. 37
      main.go

@ -6,12 +6,12 @@
3. 运行结束后显示总体完成情况 3. 运行结束后显示总体完成情况
4. 自动内嵌封面和LRC歌词(需要media-user-token,获取方式看最后的说明) 4. 自动内嵌封面和LRC歌词(需要media-user-token,获取方式看最后的说明)
5. 自动构建 可以到 [Actions](https://github.com/zhaarey/apple-music-alac-atmos-downloader/actions) 页面下载最新自动构建版本 可以直接`main.exe url` 5. 自动构建 可以到 [Actions](https://github.com/zhaarey/apple-music-alac-atmos-downloader/actions) 页面下载最新自动构建版本 可以直接`main.exe url`
6. main 支持使用 go run main.go "txt文件地址" txt文件名需要指定格式 例如 cn_1707581102_THE BOOK 3.txt 建议使用这个[Reqable 脚本代码](https://telegra.ph/Reqable-For-Apple-Music-05-01) 自动生成 6. main 支持check 可以填入文本地址 或API数据库.
7. main 支持check 可以填入文本地址 或API数据库. 7. 新增get-m3u8-from-device 改为true 且设置端口`adb forward tcp:20020 tcp:20020`即从模拟器获取m3u8
8. 新增get-m3u8-from-device 改为true 且设置端口`adb forward tcp:20020 tcp:20020`即从模拟器获取m3u8 8. 文件夹和文件支持模板
9. 文件夹和文件支持模板 9. 支持下载歌手 `go run main.go https://music.apple.com/us/artist/taylor-swift/159260351` `--all-album` 自动选择歌手的所有专辑
10. 支持下载歌手 `go run main.go https://music.apple.com/us/artist/taylor-swift/159260351` 10. 新增[wrapper](https://github.com/zhaarey/wrapper/releases)模式 目前只能linux运行,解密速度超快,基本秒解
11. 新增[wrapper](https://github.com/zhaarey/wrapper/releases)模式 目前只能linux运行,解密速度超快,基本秒解 11. `limit-max`支持限制长度 默认200
本项目仅支持ALAC和Atmos 本项目仅支持ALAC和Atmos
- `alac (audio-alac-stereo)` - `alac (audio-alac-stereo)`

@ -16,6 +16,7 @@ get-m3u8-port: "127.0.0.1:20020"
get-m3u8-from-device: false get-m3u8-from-device: false
alac-max: 192000 #192000 96000 48000 44100 alac-max: 192000 #192000 96000 48000 44100
atmos-max: 2768 #2768 2448 atmos-max: 2768 #2768 2448
limit-max: 200
#{AlbumId} {AlbumName} {ArtistName} {ReleaseDate} {ReleaseYear} {UPC} {Copyright} {Quality} {Codec} {Tag} {RecordLabel} #{AlbumId} {AlbumName} {ArtistName} {ReleaseDate} {ReleaseYear} {UPC} {Copyright} {Quality} {Codec} {Tag} {RecordLabel}
#example: {ReleaseYear} - {ArtistName} - {AlbumName}({AlbumId})({UPC})({Copyright}){Codec} #example: {ReleaseYear} - {ArtistName} - {AlbumName}({AlbumId})({UPC})({Copyright}){Codec}
album-folder-format: "{AlbumName}" album-folder-format: "{AlbumName}"

@ -39,6 +39,7 @@ var (
) )
var dl_atmos = false var dl_atmos = false
var dl_select = false var dl_select = false
var artist_select = false
type Config struct { type Config struct {
MediaUserToken string `yaml:"media-user-token"` MediaUserToken string `yaml:"media-user-token"`
@ -66,6 +67,7 @@ type Config struct {
GetM3u8FromDevice bool `yaml:"get-m3u8-from-device"` GetM3u8FromDevice bool `yaml:"get-m3u8-from-device"`
AlacMax int `yaml:"alac-max"` AlacMax int `yaml:"alac-max"`
AtmosMax int `yaml:"atmos-max"` AtmosMax int `yaml:"atmos-max"`
LimitMax int `yaml:"limit-max"`
UseSongInfoForPlaylist bool `yaml:"use-songinfo-for-playlist"` UseSongInfoForPlaylist bool `yaml:"use-songinfo-for-playlist"`
DlAlbumcoverForPlaylist bool `yaml:"dl-albumcover-for-playlist"` DlAlbumcoverForPlaylist bool `yaml:"dl-albumcover-for-playlist"`
} }
@ -101,6 +103,13 @@ func loadConfig() error {
return nil return nil
} }
func LimitString(s string) string {
if len([]rune(s)) > config.LimitMax {
return string([]rune(s)[:config.LimitMax])
}
return s
}
func (s *SongInfo) Duration() (ret uint64) { func (s *SongInfo) Duration() (ret uint64) {
for i := range s.samples { for i := range s.samples {
ret += uint64(s.samples[i].duration) ret += uint64(s.samples[i].duration)
@ -726,12 +735,12 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
return err return err
} }
err = addMeta(mp4.BoxType{'\251', 'A', 'R', 'T'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName) err = addMeta(mp4.BoxType{'\251', 'A', 'R', 'T'}, meta.Data[0].Attributes.ArtistName)
if err != nil { if err != nil {
return err return err
} }
err = addMeta(mp4.BoxType{'s', 'o', 'a', 'r'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName) err = addMeta(mp4.BoxType{'s', 'o', 'a', 'r'}, meta.Data[0].Attributes.ArtistName)
if err != nil { if err != nil {
return err return err
} }
@ -796,12 +805,12 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
if len(meta.Data) > 0 { if len(meta.Data) > 0 {
album := meta.Data[0] album := meta.Data[0]
err = addMeta(mp4.BoxType{'a', 'A', 'R', 'T'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName) err = addMeta(mp4.BoxType{'a', 'A', 'R', 'T'}, meta.Data[0].Attributes.ArtistName)
if err != nil { if err != nil {
return err return err
} }
err = addMeta(mp4.BoxType{'s', 'o', 'a', 'a'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName) err = addMeta(mp4.BoxType{'s', 'o', 'a', 'a'}, meta.Data[0].Attributes.ArtistName)
if err != nil { if err != nil {
return err return err
} }
@ -1105,6 +1114,10 @@ func checkArtist(artistUrl string, token string) ([]string, error) {
for i, option := range options { for i, option := range options {
fmt.Printf("%02d: %s\n", i+1, option) fmt.Printf("%02d: %s\n", i+1, option)
} }
if artist_select {
fmt.Println("You have selected all options:")
return urls, nil
}
reader := bufio.NewReader(os.Stdin) reader := bufio.NewReader(os.Stdin)
fmt.Println("Please select from the following options (multiple options separated by commas, ranges supported, or type 'all' to select all)") fmt.Println("Please select from the following options (multiple options separated by commas, ranges supported, or type 'all' to select all)")
fmt.Print("Enter your choice: ") fmt.Print("Enter your choice: ")
@ -1344,12 +1357,12 @@ func rip(albumId string, token string, storefront string, userToken string) erro
).Replace(config.ArtistFolderFormat) ).Replace(config.ArtistFolderFormat)
} else if len(meta.Data[0].Relationships.Artists.Data) > 0 { } else if len(meta.Data[0].Relationships.Artists.Data) > 0 {
singerFoldername = strings.NewReplacer( singerFoldername = strings.NewReplacer(
"{ArtistName}", meta.Data[0].Attributes.ArtistName, "{ArtistName}", LimitString(meta.Data[0].Attributes.ArtistName),
"{ArtistId}", meta.Data[0].Relationships.Artists.Data[0].ID, "{ArtistId}", meta.Data[0].Relationships.Artists.Data[0].ID,
).Replace(config.ArtistFolderFormat) ).Replace(config.ArtistFolderFormat)
} else { } else {
singerFoldername = strings.NewReplacer( singerFoldername = strings.NewReplacer(
"{ArtistName}", meta.Data[0].Attributes.ArtistName, "{ArtistName}", LimitString(meta.Data[0].Attributes.ArtistName),
"{ArtistId}", "", "{ArtistId}", "",
).Replace(config.ArtistFolderFormat) ).Replace(config.ArtistFolderFormat)
} }
@ -1408,7 +1421,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
if strings.Contains(albumId, "pl.") { if strings.Contains(albumId, "pl.") {
albumFolder = strings.NewReplacer( albumFolder = strings.NewReplacer(
"{ArtistName}", "Apple Music", "{ArtistName}", "Apple Music",
"{PlaylistName}", meta.Data[0].Attributes.Name, "{PlaylistName}", LimitString(meta.Data[0].Attributes.Name),
"{PlaylistId}", albumId, "{PlaylistId}", albumId,
"{Quality}", Quality, "{Quality}", Quality,
"{Codec}", Codec, "{Codec}", Codec,
@ -1418,8 +1431,8 @@ func rip(albumId string, token string, storefront string, userToken string) erro
albumFolder = strings.NewReplacer( albumFolder = strings.NewReplacer(
"{ReleaseDate}", meta.Data[0].Attributes.ReleaseDate, "{ReleaseDate}", meta.Data[0].Attributes.ReleaseDate,
"{ReleaseYear}", meta.Data[0].Attributes.ReleaseDate[:4], "{ReleaseYear}", meta.Data[0].Attributes.ReleaseDate[:4],
"{ArtistName}", meta.Data[0].Attributes.ArtistName, "{ArtistName}", LimitString(meta.Data[0].Attributes.ArtistName),
"{AlbumName}", meta.Data[0].Attributes.Name, "{AlbumName}", LimitString(meta.Data[0].Attributes.Name),
"{UPC}", meta.Data[0].Attributes.Upc, "{UPC}", meta.Data[0].Attributes.Upc,
"{RecordLabel}", meta.Data[0].Attributes.RecordLabel, "{RecordLabel}", meta.Data[0].Attributes.RecordLabel,
"{Copyright}", meta.Data[0].Attributes.Copyright, "{Copyright}", meta.Data[0].Attributes.Copyright,
@ -1574,7 +1587,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
songName := strings.NewReplacer( songName := strings.NewReplacer(
"{SongId}", track.ID, "{SongId}", track.ID,
"{SongNumer}", fmt.Sprintf("%02d", trackNum), "{SongNumer}", fmt.Sprintf("%02d", trackNum),
"{SongName}", track.Attributes.Name, "{SongName}", LimitString(track.Attributes.Name),
"{DiscNumber}", fmt.Sprintf("%0d", track.Attributes.DiscNumber), "{DiscNumber}", fmt.Sprintf("%0d", track.Attributes.DiscNumber),
"{TrackNumber}", fmt.Sprintf("%0d", track.Attributes.TrackNumber), "{TrackNumber}", fmt.Sprintf("%0d", track.Attributes.TrackNumber),
"{Quality}", Quality, "{Quality}", Quality,
@ -1675,7 +1688,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
fmt.Sprintf("album_artist=%s", meta.Data[0].Attributes.ArtistName), fmt.Sprintf("album_artist=%s", meta.Data[0].Attributes.ArtistName),
fmt.Sprintf("composer=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.ComposerName), fmt.Sprintf("composer=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.ComposerName),
fmt.Sprintf("writer=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.ComposerName), fmt.Sprintf("writer=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.ComposerName),
fmt.Sprintf("performer=%s", meta.Data[0].Attributes.ArtistName), fmt.Sprintf("performer=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName),
fmt.Sprintf("copyright=%s", meta.Data[0].Attributes.Copyright), fmt.Sprintf("copyright=%s", meta.Data[0].Attributes.Copyright),
fmt.Sprintf("ISRC=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.Isrc), fmt.Sprintf("ISRC=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.Isrc),
fmt.Sprintf("UPC=%s", meta.Data[0].Attributes.Upc), fmt.Sprintf("UPC=%s", meta.Data[0].Attributes.Upc),
@ -1756,6 +1769,8 @@ func main() {
dl_atmos = true dl_atmos = true
} else if strings.Contains(arg, "--select") { } else if strings.Contains(arg, "--select") {
dl_select = true dl_select = true
} else if strings.Contains(arg, "--all-album") {
artist_select = true
} else { } else {
dlArgs = append(dlArgs, arg) dlArgs = append(dlArgs, arg)
} }

Loading…
Cancel
Save