add atmos and select to main.go
--atmos,--select
This commit is contained in:
parent
af1a310cb6
commit
c1c62ab94c
539
main.go
539
main.go
@ -37,6 +37,8 @@ const (
|
||||
var (
|
||||
forbiddenNames = regexp.MustCompile(`[/\\<>:"|?*]`)
|
||||
)
|
||||
var dl_atmos = false
|
||||
var dl_select = false
|
||||
|
||||
type Config struct {
|
||||
MediaUserToken string `yaml:"media-user-token"`
|
||||
@ -63,6 +65,7 @@ type Config struct {
|
||||
GetM3u8Port string `yaml:"get-m3u8-port"`
|
||||
GetM3u8FromDevice bool `yaml:"get-m3u8-from-device"`
|
||||
AlacMax int `yaml:"alac-max"`
|
||||
AtmosMax int `yaml:"atmos-max"`
|
||||
UseSongInfoForPlaylist bool `yaml:"use-songinfo-for-playlist"`
|
||||
DlAlbumcoverForPlaylist bool `yaml:"dl-albumcover-for-playlist"`
|
||||
}
|
||||
@ -109,6 +112,15 @@ func (*Alac) GetType() mp4.BoxType {
|
||||
return BoxTypeAlac()
|
||||
}
|
||||
|
||||
func isInArray(arr []int, target int) bool {
|
||||
for _, num := range arr {
|
||||
if num == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func fileExists(path string) (bool, error) {
|
||||
f, err := os.Stat(path)
|
||||
if err == nil {
|
||||
@ -1009,6 +1021,14 @@ func decryptSong(info *SongInfo, keys []string, manifest *AutoGenerated, filenam
|
||||
return err
|
||||
}
|
||||
defer create.Close()
|
||||
if dl_atmos {
|
||||
_, err = create.Write(decrypted)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return writeM4a(mp4.NewWriter(create), info, manifest, decrypted, trackNum, trackTotal)
|
||||
}
|
||||
@ -1304,6 +1324,12 @@ func writeLyrics(sanAlbumFolder, filename string, lrc string) error {
|
||||
}
|
||||
|
||||
func rip(albumId string, token string, storefront string, userToken string) error {
|
||||
var Codec string
|
||||
if dl_atmos {
|
||||
Codec = "Atmos"
|
||||
} else {
|
||||
Codec = "ALAC"
|
||||
}
|
||||
meta, err := getMeta(albumId, token, storefront)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get album metadata.\n")
|
||||
@ -1336,20 +1362,24 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
||||
singerFolder := filepath.Join(config.AlacSaveFolder, forbiddenNames.ReplaceAllString(singerFoldername, "_"))
|
||||
var Quality string
|
||||
if strings.Contains(config.AlbumFolderFormat, "Quality") {
|
||||
manifest1, err := getInfoFromAdam(meta.Data[0].Relationships.Tracks.Data[0].ID, token, storefront)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get manifest.\n", err)
|
||||
if dl_atmos {
|
||||
Quality = fmt.Sprintf("%dkbps", config.AtmosMax-2000)
|
||||
} else {
|
||||
if manifest1.Attributes.ExtendedAssetUrls.EnhancedHls == "" {
|
||||
fmt.Println("Unavailable in ALAC.\n")
|
||||
manifest1, err := getInfoFromAdam(meta.Data[0].Relationships.Tracks.Data[0].ID, token, storefront)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get manifest.\n", err)
|
||||
} else {
|
||||
EnhancedHls_m3u8, err := checkM3u8(meta.Data[0].Relationships.Tracks.Data[0].ID, "album")
|
||||
if strings.HasPrefix(EnhancedHls_m3u8, "http") {
|
||||
manifest1.Attributes.ExtendedAssetUrls.EnhancedHls = EnhancedHls_m3u8
|
||||
}
|
||||
Quality, err = extractMediaQuality(manifest1.Attributes.ExtendedAssetUrls.EnhancedHls)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to extract quality from manifest.\n", err)
|
||||
if manifest1.Attributes.ExtendedAssetUrls.EnhancedHls == "" {
|
||||
fmt.Println("Unavailable.\n")
|
||||
} else {
|
||||
EnhancedHls_m3u8, err := checkM3u8(meta.Data[0].Relationships.Tracks.Data[0].ID, "album")
|
||||
if strings.HasPrefix(EnhancedHls_m3u8, "http") {
|
||||
manifest1.Attributes.ExtendedAssetUrls.EnhancedHls = EnhancedHls_m3u8
|
||||
}
|
||||
Quality, err = extractMediaQuality(manifest1.Attributes.ExtendedAssetUrls.EnhancedHls)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to extract quality from manifest.\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1378,7 +1408,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
||||
"{PlaylistName}", meta.Data[0].Attributes.Name,
|
||||
"{PlaylistId}", albumId,
|
||||
"{Quality}", Quality,
|
||||
"{Codec}", "ALAC",
|
||||
"{Codec}", Codec,
|
||||
"{Tag}", Tag_string,
|
||||
).Replace(config.PlaylistFolderFormat)
|
||||
} else {
|
||||
@ -1392,7 +1422,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
||||
"{Copyright}", meta.Data[0].Attributes.Copyright,
|
||||
"{AlbumId}", albumId,
|
||||
"{Quality}", Quality,
|
||||
"{Codec}", "ALAC",
|
||||
"{Codec}", Codec,
|
||||
"{Tag}", Tag_string,
|
||||
).Replace(config.AlbumFolderFormat)
|
||||
}
|
||||
@ -1448,157 +1478,260 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
||||
}
|
||||
}
|
||||
trackTotal := len(meta.Data[0].Relationships.Tracks.Data)
|
||||
for trackNum, track := range meta.Data[0].Relationships.Tracks.Data {
|
||||
trackNum++
|
||||
trackTotalnum += 1
|
||||
fmt.Printf("Track %d of %d:\n", trackNum, trackTotal)
|
||||
manifest, err := getInfoFromAdam(track.ID, token, storefront)
|
||||
arr := make([]int, trackTotal)
|
||||
for i := 0; i < trackTotal; i++ {
|
||||
arr[i] = i + 1
|
||||
}
|
||||
selected := []int{}
|
||||
|
||||
if !dl_select {
|
||||
selected = arr
|
||||
} else {
|
||||
|
||||
fmt.Print("select: ")
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
input, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get manifest.\n", err)
|
||||
continue
|
||||
fmt.Println(err)
|
||||
}
|
||||
if manifest.Attributes.ExtendedAssetUrls.EnhancedHls == "" {
|
||||
fmt.Println("Unavailable in ALAC.")
|
||||
continue
|
||||
}
|
||||
EnhancedHls_m3u8, err := checkM3u8(track.ID, "song")
|
||||
if strings.HasPrefix(EnhancedHls_m3u8, "http") {
|
||||
manifest.Attributes.ExtendedAssetUrls.EnhancedHls = EnhancedHls_m3u8
|
||||
}
|
||||
var Quality string
|
||||
if strings.Contains(config.SongFileFormat, "Quality") {
|
||||
Quality, err = extractMediaQuality(manifest.Attributes.ExtendedAssetUrls.EnhancedHls)
|
||||
input = strings.TrimSpace(input)
|
||||
inputs := strings.Fields(input)
|
||||
|
||||
for _, str := range inputs {
|
||||
num, err := strconv.Atoi(str)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to extract quality from manifest.\n", err)
|
||||
fmt.Printf("wrong '%s', skip...\n", str)
|
||||
continue
|
||||
}
|
||||
}
|
||||
stringsToJoin := []string{}
|
||||
if track.Attributes.IsAppleDigitalMaster {
|
||||
if config.AppleMasterChoice != "" {
|
||||
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
||||
}
|
||||
}
|
||||
if track.Attributes.ContentRating == "explicit" {
|
||||
if config.ExplicitChoice != "" {
|
||||
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
||||
}
|
||||
}
|
||||
if track.Attributes.ContentRating == "clean" {
|
||||
if config.CleanChoice != "" {
|
||||
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
||||
}
|
||||
}
|
||||
Tag_string := strings.Join(stringsToJoin, " ")
|
||||
|
||||
songName := strings.NewReplacer(
|
||||
"{SongId}", track.ID,
|
||||
"{SongNumer}", fmt.Sprintf("%02d", trackNum),
|
||||
"{SongName}", track.Attributes.Name,
|
||||
"{DiscNumber}", fmt.Sprintf("%0d", track.Attributes.DiscNumber),
|
||||
"{TrackNumber}", fmt.Sprintf("%0d", track.Attributes.TrackNumber),
|
||||
"{Quality}", Quality,
|
||||
"{Tag}", Tag_string,
|
||||
"{Codec}", "ALAC",
|
||||
).Replace(config.SongFileFormat)
|
||||
fmt.Println(songName)
|
||||
filename := fmt.Sprintf("%s.m4a", forbiddenNames.ReplaceAllString(songName, "_"))
|
||||
lrcFilename := fmt.Sprintf("%s.lrc", forbiddenNames.ReplaceAllString(songName, "_"))
|
||||
trackPath := filepath.Join(sanAlbumFolder, filename)
|
||||
var lrc string = ""
|
||||
if userToken != "your-media-user-token" && (config.EmbedLrc || config.SaveLrcFile) {
|
||||
ttml, err := getSongLyrics(track.ID, storefront, token, userToken)
|
||||
found := false
|
||||
for i := 0; i < len(arr); i++ {
|
||||
if arr[i] == num {
|
||||
selected = append(selected, num)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
fmt.Printf("Option '%d' not found or already selected, skipping...\n", num)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Selected options:", selected)
|
||||
}
|
||||
for trackNum, track := range meta.Data[0].Relationships.Tracks.Data {
|
||||
trackNum++
|
||||
if isInArray(selected, trackNum) {
|
||||
trackTotalnum += 1
|
||||
fmt.Printf("Track %d of %d:\n", trackNum, trackTotal)
|
||||
manifest, err := getInfoFromAdam(track.ID, token, storefront)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get lyrics")
|
||||
} else {
|
||||
lrc, err = conventTTMLToLRC(ttml)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse lyrics: %s \n", err)
|
||||
fmt.Println("Failed to get manifest.\n", err)
|
||||
continue
|
||||
}
|
||||
if manifest.Attributes.ExtendedAssetUrls.EnhancedHls == "" {
|
||||
fmt.Println("Unavailable.")
|
||||
continue
|
||||
}
|
||||
EnhancedHls_m3u8, err := checkM3u8(track.ID, "song")
|
||||
if strings.HasPrefix(EnhancedHls_m3u8, "http") {
|
||||
manifest.Attributes.ExtendedAssetUrls.EnhancedHls = EnhancedHls_m3u8
|
||||
}
|
||||
var Quality string
|
||||
if strings.Contains(config.SongFileFormat, "Quality") {
|
||||
if dl_atmos {
|
||||
Quality = fmt.Sprintf("%dkbps", config.AtmosMax-2000)
|
||||
} else {
|
||||
if config.SaveLrcFile {
|
||||
err := writeLyrics(sanAlbumFolder, lrcFilename, lrc)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to write lyrics")
|
||||
}
|
||||
if !config.EmbedLrc {
|
||||
lrc = ""
|
||||
Quality, err = extractMediaQuality(manifest.Attributes.ExtendedAssetUrls.EnhancedHls)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to extract quality from manifest.\n", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
stringsToJoin := []string{}
|
||||
if track.Attributes.IsAppleDigitalMaster {
|
||||
if config.AppleMasterChoice != "" {
|
||||
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
||||
}
|
||||
}
|
||||
if track.Attributes.ContentRating == "explicit" {
|
||||
if config.ExplicitChoice != "" {
|
||||
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
||||
}
|
||||
}
|
||||
if track.Attributes.ContentRating == "clean" {
|
||||
if config.CleanChoice != "" {
|
||||
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
||||
}
|
||||
}
|
||||
Tag_string := strings.Join(stringsToJoin, " ")
|
||||
|
||||
songName := strings.NewReplacer(
|
||||
"{SongId}", track.ID,
|
||||
"{SongNumer}", fmt.Sprintf("%02d", trackNum),
|
||||
"{SongName}", track.Attributes.Name,
|
||||
"{DiscNumber}", fmt.Sprintf("%0d", track.Attributes.DiscNumber),
|
||||
"{TrackNumber}", fmt.Sprintf("%0d", track.Attributes.TrackNumber),
|
||||
"{Quality}", Quality,
|
||||
"{Tag}", Tag_string,
|
||||
"{Codec}", Codec,
|
||||
).Replace(config.SongFileFormat)
|
||||
fmt.Println(songName)
|
||||
filename := fmt.Sprintf("%s.m4a", forbiddenNames.ReplaceAllString(songName, "_"))
|
||||
if dl_atmos {
|
||||
filename = fmt.Sprintf("%s.ec3", forbiddenNames.ReplaceAllString(songName, "_"))
|
||||
}
|
||||
m4afilename := fmt.Sprintf("%s.m4a", forbiddenNames.ReplaceAllString(songName, "_"))
|
||||
lrcFilename := fmt.Sprintf("%s.lrc", forbiddenNames.ReplaceAllString(songName, "_"))
|
||||
trackPath := filepath.Join(sanAlbumFolder, filename)
|
||||
m4atrackPath := filepath.Join(sanAlbumFolder, m4afilename)
|
||||
var lrc string = ""
|
||||
if userToken != "your-media-user-token" && (config.EmbedLrc || config.SaveLrcFile) {
|
||||
ttml, err := getSongLyrics(track.ID, storefront, token, userToken)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get lyrics")
|
||||
} else {
|
||||
lrc, err = conventTTMLToLRC(ttml)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse lyrics: %s \n", err)
|
||||
} else {
|
||||
if config.SaveLrcFile {
|
||||
err := writeLyrics(sanAlbumFolder, lrcFilename, lrc)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to write lyrics")
|
||||
}
|
||||
if !config.EmbedLrc {
|
||||
lrc = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exists, err := fileExists(trackPath)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to check if track exists.")
|
||||
}
|
||||
if exists {
|
||||
fmt.Println("Track already exists locally.")
|
||||
oktrackNum += 1
|
||||
continue
|
||||
}
|
||||
|
||||
trackUrl, keys, err := extractMedia(manifest.Attributes.ExtendedAssetUrls.EnhancedHls)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to extract info from manifest.\n", err)
|
||||
continue
|
||||
}
|
||||
info, err := extractSong(trackUrl)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to extract track.", err)
|
||||
continue
|
||||
}
|
||||
samplesOk := true
|
||||
for samplesOk {
|
||||
for _, i := range info.samples {
|
||||
if int(i.descIndex) >= len(keys) {
|
||||
fmt.Println("Decryption size mismatch.")
|
||||
samplesOk = false
|
||||
}
|
||||
exists, err := fileExists(trackPath)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to check if track exists.")
|
||||
}
|
||||
break
|
||||
}
|
||||
if !samplesOk {
|
||||
continue
|
||||
}
|
||||
err = decryptSong(info, keys, meta, trackPath, trackNum, trackTotal)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to decrypt track.\n", err)
|
||||
continue
|
||||
}
|
||||
tags := []string{
|
||||
fmt.Sprintf("lyrics=%s", lrc),
|
||||
}
|
||||
if track.Attributes.ContentRating == "explicit" {
|
||||
tags = append(tags, "rating=1")
|
||||
} else if track.Attributes.ContentRating == "clean" {
|
||||
tags = append(tags, "rating=2")
|
||||
} else {
|
||||
tags = append(tags, "rating=0")
|
||||
}
|
||||
if config.EmbedCover {
|
||||
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
||||
err = writeCover(sanAlbumFolder, track.ID, track.Attributes.Artwork.URL)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to write cover.")
|
||||
}
|
||||
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder, track.ID, config.CoverFormat))
|
||||
} else {
|
||||
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder, "cover", config.CoverFormat))
|
||||
}
|
||||
}
|
||||
tagsString := strings.Join(tags, ":")
|
||||
cmd := exec.Command("MP4Box", "-itags", tagsString, trackPath)
|
||||
if err := cmd.Run(); err != nil {
|
||||
fmt.Printf("Embed failed: %v\n", err)
|
||||
continue
|
||||
}
|
||||
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
||||
if err := os.Remove(fmt.Sprintf("%s/%s.%s", sanAlbumFolder, track.ID, config.CoverFormat)); err != nil {
|
||||
fmt.Printf("Error deleting file: %s/%s.%s\n", sanAlbumFolder, track.ID, config.CoverFormat)
|
||||
if exists {
|
||||
fmt.Println("Track already exists locally.")
|
||||
oktrackNum += 1
|
||||
continue
|
||||
}
|
||||
m4aexists, err := fileExists(m4atrackPath)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to check if track exists.")
|
||||
}
|
||||
if m4aexists {
|
||||
fmt.Println("Track already exists locally.")
|
||||
oktrackNum += 1
|
||||
continue
|
||||
}
|
||||
|
||||
trackUrl, keys, err := extractMedia(manifest.Attributes.ExtendedAssetUrls.EnhancedHls)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to extract info from manifest.\n", err)
|
||||
continue
|
||||
}
|
||||
info, err := extractSong(trackUrl)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to extract track.", err)
|
||||
continue
|
||||
}
|
||||
samplesOk := true
|
||||
for samplesOk {
|
||||
for _, i := range info.samples {
|
||||
if int(i.descIndex) >= len(keys) {
|
||||
fmt.Println("Decryption size mismatch.")
|
||||
samplesOk = false
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
if !samplesOk {
|
||||
continue
|
||||
}
|
||||
err = decryptSong(info, keys, meta, trackPath, trackNum, trackTotal)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to decrypt track.\n", err)
|
||||
continue
|
||||
}
|
||||
tags := []string{
|
||||
fmt.Sprintf("lyrics=%s", lrc),
|
||||
}
|
||||
|
||||
index := trackNum - 1
|
||||
if dl_atmos {
|
||||
tags = []string{
|
||||
"tool=",
|
||||
fmt.Sprintf("lyrics=%s", lrc),
|
||||
fmt.Sprintf("title=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.Name),
|
||||
fmt.Sprintf("artist=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName),
|
||||
fmt.Sprintf("genre=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.GenreNames[0]),
|
||||
fmt.Sprintf("created=%s", meta.Data[0].Attributes.ReleaseDate),
|
||||
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("writer=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.ComposerName),
|
||||
fmt.Sprintf("performer=%s", meta.Data[0].Attributes.ArtistName),
|
||||
fmt.Sprintf("copyright=%s", meta.Data[0].Attributes.Copyright),
|
||||
fmt.Sprintf("ISRC=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.Isrc),
|
||||
fmt.Sprintf("UPC=%s", meta.Data[0].Attributes.Upc),
|
||||
}
|
||||
if strings.Contains(albumId, "pl.") && !config.UseSongInfoForPlaylist {
|
||||
tags = append(tags, "disk=1/1")
|
||||
tags = append(tags, fmt.Sprintf("track=%s", trackNum))
|
||||
tags = append(tags, fmt.Sprintf("tracknum=%d/%d", trackNum, trackTotal))
|
||||
tags = append(tags, fmt.Sprintf("album=%s", meta.Data[0].Attributes.Name))
|
||||
} else {
|
||||
tags = append(tags, fmt.Sprintf("disk=%d/%d", meta.Data[0].Relationships.Tracks.Data[index].Attributes.DiscNumber, meta.Data[0].Relationships.Tracks.Data[trackTotal-1].Attributes.DiscNumber))
|
||||
tags = append(tags, fmt.Sprintf("track=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber))
|
||||
tags = append(tags, fmt.Sprintf("tracknum=%d/%d", meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber, trackTotal))
|
||||
tags = append(tags, fmt.Sprintf("album=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName))
|
||||
}
|
||||
}
|
||||
if track.Attributes.ContentRating == "explicit" {
|
||||
tags = append(tags, "rating=1")
|
||||
} else if track.Attributes.ContentRating == "clean" {
|
||||
tags = append(tags, "rating=2")
|
||||
} else {
|
||||
tags = append(tags, "rating=0")
|
||||
}
|
||||
if config.EmbedCover {
|
||||
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
||||
err = writeCover(sanAlbumFolder, track.ID, track.Attributes.Artwork.URL)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to write cover.")
|
||||
}
|
||||
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder, track.ID, config.CoverFormat))
|
||||
} else {
|
||||
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder, "cover", config.CoverFormat))
|
||||
}
|
||||
}
|
||||
tagsString := strings.Join(tags, ":")
|
||||
cmd := exec.Command("MP4Box", "-itags", tagsString, trackPath)
|
||||
if dl_atmos {
|
||||
cmd = exec.Command("MP4Box", "-add", trackPath, "-name", fmt.Sprintf("1=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.Name), "-itags", tagsString, "-brand", "mp42", "-ab", "dby1", m4atrackPath)
|
||||
}
|
||||
if err := cmd.Run(); err != nil {
|
||||
fmt.Printf("Embed failed: %v\n", err)
|
||||
continue
|
||||
}
|
||||
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
||||
if err := os.Remove(fmt.Sprintf("%s/%s.%s", sanAlbumFolder, track.ID, config.CoverFormat)); err != nil {
|
||||
fmt.Printf("Error deleting file: %s/%s.%s\n", sanAlbumFolder, track.ID, config.CoverFormat)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if dl_atmos {
|
||||
fmt.Printf("Deleting original EC3 file: %s\n", filepath.Base(trackPath))
|
||||
if err := os.Remove(trackPath); err != nil {
|
||||
fmt.Printf("Error deleting file: %v\n", err)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("Successfully processed and deleted %s\n", filepath.Base(trackPath))
|
||||
}
|
||||
oktrackNum += 1
|
||||
}
|
||||
oktrackNum += 1
|
||||
}
|
||||
return err
|
||||
}
|
||||
@ -1614,6 +1747,17 @@ func main() {
|
||||
fmt.Println("Failed to get token.")
|
||||
return
|
||||
}
|
||||
var dlArgs []string
|
||||
for _, arg := range os.Args {
|
||||
if strings.Contains(arg, "--atmos") {
|
||||
dl_atmos = true
|
||||
} else if strings.Contains(arg, "--select") {
|
||||
dl_select = true
|
||||
} else {
|
||||
dlArgs = append(dlArgs, arg)
|
||||
}
|
||||
}
|
||||
os.Args = dlArgs
|
||||
if strings.Contains(os.Args[1], "/artist/") {
|
||||
newArgs, err := checkArtist(os.Args[1], token)
|
||||
if err != nil {
|
||||
@ -1882,26 +2026,46 @@ func extractMedia(b string) (string, []string, error) {
|
||||
return master.Variants[i].AverageBandwidth > master.Variants[j].AverageBandwidth
|
||||
})
|
||||
for _, variant := range master.Variants {
|
||||
if variant.Codecs == "alac" {
|
||||
split := strings.Split(variant.Audio, "-")
|
||||
length := len(split)
|
||||
length_int, err := strconv.Atoi(split[length-2])
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if length_int <= config.AlacMax {
|
||||
fmt.Printf("%s-bit / %s Hz\n", split[length-1], split[length-2])
|
||||
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
||||
if dl_atmos {
|
||||
if variant.Codecs == "ec-3" {
|
||||
split := strings.Split(variant.Audio, "-")
|
||||
length := len(split)
|
||||
length_int, err := strconv.Atoi(split[length-1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return "", nil, err
|
||||
}
|
||||
if length_int <= config.AtmosMax {
|
||||
fmt.Printf("%s\n", variant.Audio)
|
||||
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
streamUrl = streamUrlTemp
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if variant.Codecs == "alac" {
|
||||
split := strings.Split(variant.Audio, "-")
|
||||
length := len(split)
|
||||
length_int, err := strconv.Atoi(split[length-2])
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if length_int <= config.AlacMax {
|
||||
fmt.Printf("%s-bit / %s Hz\n", split[length-1], split[length-2])
|
||||
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
streamUrl = streamUrlTemp
|
||||
break
|
||||
}
|
||||
streamUrl = streamUrlTemp
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if streamUrl == nil {
|
||||
return "", nil, errors.New("no alac codec found")
|
||||
return "", nil, errors.New("no codec found")
|
||||
}
|
||||
var keys []string
|
||||
keys = append(keys, prefetchKey)
|
||||
@ -1909,8 +2073,14 @@ func extractMedia(b string) (string, []string, error) {
|
||||
regex := regexp.MustCompile(`"(skd?://[^"]*)"`)
|
||||
matches := regex.FindAllStringSubmatch(masterString, -1)
|
||||
for _, match := range matches {
|
||||
if strings.HasSuffix(match[1], "c23") || strings.HasSuffix(match[1], "c6") {
|
||||
keys = append(keys, match[1])
|
||||
if dl_atmos {
|
||||
if strings.HasSuffix(match[1], "c24") || strings.HasSuffix(match[1], "c6") {
|
||||
keys = append(keys, match[1])
|
||||
}
|
||||
} else {
|
||||
if strings.HasSuffix(match[1], "c23") || strings.HasSuffix(match[1], "c6") {
|
||||
keys = append(keys, match[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
return streamUrl.String(), keys, nil
|
||||
@ -1992,23 +2162,30 @@ func extractSong(url string) (*SongInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
enca, err := mp4.ExtractBoxWithPayload(f, stbl[0], []mp4.BoxType{
|
||||
mp4.BoxTypeStsd(),
|
||||
mp4.BoxTypeEnca(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var extracted *SongInfo
|
||||
if !dl_atmos {
|
||||
enca, err := mp4.ExtractBoxWithPayload(f, stbl[0], []mp4.BoxType{
|
||||
mp4.BoxTypeStsd(),
|
||||
mp4.BoxTypeEnca(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
aalac, err := mp4.ExtractBoxWithPayload(f, &enca[0].Info,
|
||||
[]mp4.BoxType{BoxTypeAlac()})
|
||||
if err != nil || len(aalac) != 1 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
extracted := &SongInfo{
|
||||
r: f,
|
||||
alacParam: aalac[0].Payload.(*Alac),
|
||||
aalac, err := mp4.ExtractBoxWithPayload(f, &enca[0].Info,
|
||||
[]mp4.BoxType{BoxTypeAlac()})
|
||||
if err != nil || len(aalac) != 1 {
|
||||
return nil, err
|
||||
}
|
||||
extracted = &SongInfo{
|
||||
r: f,
|
||||
alacParam: aalac[0].Payload.(*Alac),
|
||||
}
|
||||
} else {
|
||||
extracted = &SongInfo{
|
||||
r: f,
|
||||
// alacParam: aalac[0].Payload.(*Alac),
|
||||
}
|
||||
}
|
||||
|
||||
moofs, err := mp4.ExtractBox(f, nil, []mp4.BoxType{
|
||||
|
Loading…
x
Reference in New Issue
Block a user