add limit folder length and select all album command
This commit is contained in:
parent
d9fa2202b4
commit
e77cd8291d
12
README.md
12
README.md
@ -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}"
|
||||||
|
37
main.go
37
main.go
@ -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…
x
Reference in New Issue
Block a user