fix apple master tag
This commit is contained in:
parent
5f528e76a9
commit
fa02c77ff8
131
main.go
131
main.go
@ -5,7 +5,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -23,6 +22,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
"github.com/abema/go-mp4"
|
"github.com/abema/go-mp4"
|
||||||
"github.com/beevik/etree"
|
"github.com/beevik/etree"
|
||||||
"github.com/grafov/m3u8"
|
"github.com/grafov/m3u8"
|
||||||
@ -36,6 +37,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
forbiddenNames = regexp.MustCompile(`[/\\<>:"|?*]`)
|
forbiddenNames = regexp.MustCompile(`[/\\<>:"|?*]`)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
MediaUserToken string `yaml:"media-user-token"`
|
MediaUserToken string `yaml:"media-user-token"`
|
||||||
SaveLrcFile bool `yaml:"save-lrc-file"`
|
SaveLrcFile bool `yaml:"save-lrc-file"`
|
||||||
@ -76,6 +78,7 @@ type SongInfo struct {
|
|||||||
alacParam *Alac
|
alacParam *Alac
|
||||||
samples []SampleInfo
|
samples []SampleInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadConfig() error {
|
func loadConfig() error {
|
||||||
// 读取config.yaml文件内容
|
// 读取config.yaml文件内容
|
||||||
data, err := ioutil.ReadFile("config.yaml")
|
data, err := ioutil.ReadFile("config.yaml")
|
||||||
@ -690,10 +693,10 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
AlbumName:=meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName
|
AlbumName := meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName
|
||||||
if strings.Contains(meta.Data[0].ID, "pl."){
|
if strings.Contains(meta.Data[0].ID, "pl.") {
|
||||||
if !config.UseSongInfoForPlaylist {
|
if !config.UseSongInfoForPlaylist {
|
||||||
AlbumName=meta.Data[0].Attributes.Name
|
AlbumName = meta.Data[0].Attributes.Name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = addMeta(mp4.BoxType{'\251', 'a', 'l', 'b'}, AlbumName)
|
err = addMeta(mp4.BoxType{'\251', 'a', 'l', 'b'}, AlbumName)
|
||||||
@ -805,7 +808,7 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(meta.Data[0].ID, "pl."){
|
if !strings.Contains(meta.Data[0].ID, "pl.") {
|
||||||
plID, err := strconv.ParseUint(meta.Data[0].ID, 10, 32)
|
plID, err := strconv.ParseUint(meta.Data[0].ID, 10, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -836,8 +839,8 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
binary.BigEndian.PutUint32(trkn, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber))
|
binary.BigEndian.PutUint32(trkn, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber))
|
||||||
binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal))
|
binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal))
|
||||||
binary.BigEndian.PutUint32(disk, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.DiscNumber))
|
binary.BigEndian.PutUint32(disk, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.DiscNumber))
|
||||||
binary.BigEndian.PutUint16(disk[4:], uint16(meta.Data[0].Relationships.Tracks.Data[trackTotal - 1].Attributes.DiscNumber))
|
binary.BigEndian.PutUint16(disk[4:], uint16(meta.Data[0].Relationships.Tracks.Data[trackTotal-1].Attributes.DiscNumber))
|
||||||
if strings.Contains(meta.Data[0].ID, "pl."){
|
if strings.Contains(meta.Data[0].ID, "pl.") {
|
||||||
if !config.UseSongInfoForPlaylist {
|
if !config.UseSongInfoForPlaylist {
|
||||||
binary.BigEndian.PutUint32(trkn, uint32(trackNum))
|
binary.BigEndian.PutUint32(trkn, uint32(trackNum))
|
||||||
binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal))
|
binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal))
|
||||||
@ -1117,8 +1120,8 @@ func getSongLyrics(songId string, storefront string, token string, userToken str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeCover(sanAlbumFolder,name string, url string) error {
|
func writeCover(sanAlbumFolder, name string, url string) error {
|
||||||
covPath := filepath.Join(sanAlbumFolder, name+"." + config.CoverFormat)
|
covPath := filepath.Join(sanAlbumFolder, name+"."+config.CoverFormat)
|
||||||
exists, err := fileExists(covPath)
|
exists, err := fileExists(covPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to check if cover exists.")
|
fmt.Println("Failed to check if cover exists.")
|
||||||
@ -1179,13 +1182,13 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var singerFoldername string
|
var singerFoldername string
|
||||||
if config.ArtistFolderFormat != ""{
|
if config.ArtistFolderFormat != "" {
|
||||||
if strings.Contains(albumId, "pl.") {
|
if strings.Contains(albumId, "pl.") {
|
||||||
singerFoldername = strings.NewReplacer(
|
singerFoldername = strings.NewReplacer(
|
||||||
"{ArtistName}", "Apple Music",
|
"{ArtistName}", "Apple Music",
|
||||||
"{ArtistId}", "",
|
"{ArtistId}", "",
|
||||||
).Replace(config.ArtistFolderFormat)
|
).Replace(config.ArtistFolderFormat)
|
||||||
}else{
|
} else {
|
||||||
singerFoldername = strings.NewReplacer(
|
singerFoldername = strings.NewReplacer(
|
||||||
"{ArtistName}", meta.Data[0].Attributes.ArtistName,
|
"{ArtistName}", meta.Data[0].Attributes.ArtistName,
|
||||||
"{ArtistId}", meta.Data[0].Relationships.Artists.Data[0].ID,
|
"{ArtistId}", meta.Data[0].Relationships.Artists.Data[0].ID,
|
||||||
@ -1206,29 +1209,29 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
fmt.Println("Unavailable in ALAC.")
|
fmt.Println("Unavailable in ALAC.")
|
||||||
}
|
}
|
||||||
var Quality string
|
var Quality string
|
||||||
EnhancedHls_m3u8,err:=checkM3u8(meta.Data[0].Relationships.Tracks.Data[0].ID,"album")
|
EnhancedHls_m3u8, err := checkM3u8(meta.Data[0].Relationships.Tracks.Data[0].ID, "album")
|
||||||
if strings.HasPrefix(EnhancedHls_m3u8, "http"){
|
if strings.HasPrefix(EnhancedHls_m3u8, "http") {
|
||||||
manifest1.Attributes.ExtendedAssetUrls.EnhancedHls=EnhancedHls_m3u8
|
manifest1.Attributes.ExtendedAssetUrls.EnhancedHls = EnhancedHls_m3u8
|
||||||
}
|
}
|
||||||
if strings.Contains(config.AlbumFolderFormat, "Quality"){
|
if strings.Contains(config.AlbumFolderFormat, "Quality") {
|
||||||
Quality,err = extractMediaQuality(manifest1.Attributes.ExtendedAssetUrls.EnhancedHls)
|
Quality, err = extractMediaQuality(manifest1.Attributes.ExtendedAssetUrls.EnhancedHls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to extract quality from manifest.\n", err)
|
fmt.Println("Failed to extract quality from manifest.\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stringsToJoin := []string{}
|
stringsToJoin := []string{}
|
||||||
if meta.Data[0].Attributes.IsAppleDigitalMaster{
|
if meta.Data[0].Attributes.IsAppleDigitalMaster || meta.Data[0].Attributes.IsMasteredForItunes {
|
||||||
if config.AppleMasterChoice != ""{
|
if config.AppleMasterChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if meta.Data[0].Attributes.ContentRating=="explicit"{
|
if meta.Data[0].Attributes.ContentRating == "explicit" {
|
||||||
if config.ExplicitChoice != ""{
|
if config.ExplicitChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if meta.Data[0].Attributes.ContentRating=="clean"{
|
if meta.Data[0].Attributes.ContentRating == "clean" {
|
||||||
if config.CleanChoice != ""{
|
if config.CleanChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1239,11 +1242,11 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
"{ArtistName}", "Apple Music",
|
"{ArtistName}", "Apple Music",
|
||||||
"{PlaylistName}", meta.Data[0].Attributes.Name,
|
"{PlaylistName}", meta.Data[0].Attributes.Name,
|
||||||
"{PlaylistId}", albumId,
|
"{PlaylistId}", albumId,
|
||||||
"{Quality}",Quality,
|
"{Quality}", Quality,
|
||||||
"{Codec}", "ALAC",
|
"{Codec}", "ALAC",
|
||||||
"{Tag}",Tag_string,
|
"{Tag}", Tag_string,
|
||||||
).Replace(config.PlaylistFolderFormat)
|
).Replace(config.PlaylistFolderFormat)
|
||||||
}else{
|
} else {
|
||||||
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],
|
||||||
@ -1255,7 +1258,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
"{AlbumId}", albumId,
|
"{AlbumId}", albumId,
|
||||||
"{Quality}", Quality,
|
"{Quality}", Quality,
|
||||||
"{Codec}", "ALAC",
|
"{Codec}", "ALAC",
|
||||||
"{Tag}",Tag_string,
|
"{Tag}", Tag_string,
|
||||||
).Replace(config.AlbumFolderFormat)
|
).Replace(config.AlbumFolderFormat)
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(albumFolder, ".") {
|
if strings.HasSuffix(albumFolder, ".") {
|
||||||
@ -1265,7 +1268,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
sanAlbumFolder := filepath.Join(singerFolder, forbiddenNames.ReplaceAllString(albumFolder, "_"))
|
sanAlbumFolder := filepath.Join(singerFolder, forbiddenNames.ReplaceAllString(albumFolder, "_"))
|
||||||
os.MkdirAll(sanAlbumFolder, os.ModePerm)
|
os.MkdirAll(sanAlbumFolder, os.ModePerm)
|
||||||
fmt.Println(albumFolder)
|
fmt.Println(albumFolder)
|
||||||
err = writeCover(sanAlbumFolder,"cover", meta.Data[0].Attributes.Artwork.URL)
|
err = writeCover(sanAlbumFolder, "cover", meta.Data[0].Attributes.Artwork.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to write cover.")
|
fmt.Println("Failed to write cover.")
|
||||||
}
|
}
|
||||||
@ -1283,31 +1286,31 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
fmt.Println("Unavailable in ALAC.")
|
fmt.Println("Unavailable in ALAC.")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
EnhancedHls_m3u8,err:=checkM3u8(track.ID,"song")
|
EnhancedHls_m3u8, err := checkM3u8(track.ID, "song")
|
||||||
if strings.HasPrefix(EnhancedHls_m3u8, "http"){
|
if strings.HasPrefix(EnhancedHls_m3u8, "http") {
|
||||||
manifest.Attributes.ExtendedAssetUrls.EnhancedHls=EnhancedHls_m3u8
|
manifest.Attributes.ExtendedAssetUrls.EnhancedHls = EnhancedHls_m3u8
|
||||||
}
|
}
|
||||||
var Quality string
|
var Quality string
|
||||||
if strings.Contains(config.SongFileFormat, "Quality"){
|
if strings.Contains(config.SongFileFormat, "Quality") {
|
||||||
Quality,err = extractMediaQuality(manifest.Attributes.ExtendedAssetUrls.EnhancedHls)
|
Quality, err = extractMediaQuality(manifest.Attributes.ExtendedAssetUrls.EnhancedHls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to extract quality from manifest.\n", err)
|
fmt.Println("Failed to extract quality from manifest.\n", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stringsToJoin := []string{}
|
stringsToJoin := []string{}
|
||||||
if track.Attributes.IsAppleDigitalMaster{
|
if track.Attributes.IsAppleDigitalMaster {
|
||||||
if config.AppleMasterChoice != ""{
|
if config.AppleMasterChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if track.Attributes.ContentRating=="explicit"{
|
if track.Attributes.ContentRating == "explicit" {
|
||||||
if config.ExplicitChoice != ""{
|
if config.ExplicitChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if track.Attributes.ContentRating=="clean"{
|
if track.Attributes.ContentRating == "clean" {
|
||||||
if config.CleanChoice != ""{
|
if config.CleanChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1320,7 +1323,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
"{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,
|
||||||
"{Tag}",Tag_string,
|
"{Tag}", Tag_string,
|
||||||
"{Codec}", "ALAC",
|
"{Codec}", "ALAC",
|
||||||
).Replace(config.SongFileFormat)
|
).Replace(config.SongFileFormat)
|
||||||
fmt.Println(songName)
|
fmt.Println(songName)
|
||||||
@ -1390,22 +1393,22 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
tags := []string{
|
tags := []string{
|
||||||
fmt.Sprintf("lyrics=%s", lrc),
|
fmt.Sprintf("lyrics=%s", lrc),
|
||||||
}
|
}
|
||||||
if track.Attributes.ContentRating=="explicit"{
|
if track.Attributes.ContentRating == "explicit" {
|
||||||
tags = append(tags, "rating=1")
|
tags = append(tags, "rating=1")
|
||||||
}else if track.Attributes.ContentRating=="clean"{
|
} else if track.Attributes.ContentRating == "clean" {
|
||||||
tags = append(tags, "rating=2")
|
tags = append(tags, "rating=2")
|
||||||
}else{
|
} else {
|
||||||
tags = append(tags, "rating=0")
|
tags = append(tags, "rating=0")
|
||||||
}
|
}
|
||||||
if config.EmbedCover {
|
if config.EmbedCover {
|
||||||
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
||||||
err = writeCover(sanAlbumFolder,track.ID, track.Attributes.Artwork.URL)
|
err = writeCover(sanAlbumFolder, track.ID, track.Attributes.Artwork.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to write cover.")
|
fmt.Println("Failed to write cover.")
|
||||||
}
|
}
|
||||||
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder,track.ID, config.CoverFormat))
|
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder, track.ID, config.CoverFormat))
|
||||||
}else{
|
} else {
|
||||||
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder,"cover", config.CoverFormat))
|
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder, "cover", config.CoverFormat))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tagsString := strings.Join(tags, ":")
|
tagsString := strings.Join(tags, ":")
|
||||||
@ -1415,8 +1418,8 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
||||||
if err := os.Remove(fmt.Sprintf("%s/%s.%s", sanAlbumFolder,track.ID, config.CoverFormat)); err != nil {
|
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)
|
fmt.Printf("Error deleting file: %s/%s.%s\n", sanAlbumFolder, track.ID, config.CoverFormat)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1517,12 +1520,12 @@ func conventTTMLToLRC(ttml string) (string, error) {
|
|||||||
return strings.Join(lrcLines, "\n"), nil
|
return strings.Join(lrcLines, "\n"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkM3u8(b string,f string) (string, error) {
|
func checkM3u8(b string, f string) (string, error) {
|
||||||
var EnhancedHls string
|
var EnhancedHls string
|
||||||
if config.Check != ""{
|
if config.Check != "" {
|
||||||
config.Check=strings.TrimSpace(config.Check)
|
config.Check = strings.TrimSpace(config.Check)
|
||||||
if strings.HasSuffix(config.Check, "txt") {
|
if strings.HasSuffix(config.Check, "txt") {
|
||||||
txtpath=config.Check
|
txtpath = config.Check
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(config.Check, "http") {
|
if strings.HasPrefix(config.Check, "http") {
|
||||||
req, err := http.NewRequest("GET", config.Check, nil)
|
req, err := http.NewRequest("GET", config.Check, nil)
|
||||||
@ -1544,8 +1547,8 @@ func checkM3u8(b string,f string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
if string(Checkbody) != "no_found"{
|
if string(Checkbody) != "no_found" {
|
||||||
EnhancedHls=string(Checkbody)
|
EnhancedHls = string(Checkbody)
|
||||||
fmt.Println("Found m3u8 from API")
|
fmt.Println("Found m3u8 from API")
|
||||||
} else {
|
} else {
|
||||||
if config.ForceApi {
|
if config.ForceApi {
|
||||||
@ -1555,14 +1558,14 @@ func checkM3u8(b string,f string) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if config.GetM3u8FromDevice{
|
if config.GetM3u8FromDevice {
|
||||||
adamID := b
|
adamID := b
|
||||||
conn, err := net.Dial("tcp", "127.0.0.1:20020")
|
conn, err := net.Dial("tcp", "127.0.0.1:20020")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error connecting to device:", err)
|
fmt.Println("Error connecting to device:", err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
if f =="song"{
|
if f == "song" {
|
||||||
fmt.Println("Connected to device")
|
fmt.Println("Connected to device")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1591,7 +1594,7 @@ func checkM3u8(b string,f string) (string, error) {
|
|||||||
|
|
||||||
response = bytes.TrimSpace(response)
|
response = bytes.TrimSpace(response)
|
||||||
if len(response) > 0 {
|
if len(response) > 0 {
|
||||||
if f =="song"{
|
if f == "song" {
|
||||||
fmt.Println("Received URL:", string(response))
|
fmt.Println("Received URL:", string(response))
|
||||||
}
|
}
|
||||||
EnhancedHls = string(response)
|
EnhancedHls = string(response)
|
||||||
@ -1611,7 +1614,7 @@ func checkM3u8(b string,f string) (string, error) {
|
|||||||
if strings.HasPrefix(line, b) {
|
if strings.HasPrefix(line, b) {
|
||||||
parts := strings.SplitN(line, ",", 2)
|
parts := strings.SplitN(line, ",", 2)
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
EnhancedHls=parts[1]
|
EnhancedHls = parts[1]
|
||||||
fmt.Println("Found m3u8 from txt")
|
fmt.Println("Found m3u8 from txt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1650,16 +1653,16 @@ func extractMediaQuality(b string) (string, error) {
|
|||||||
if variant.Codecs == "alac" {
|
if variant.Codecs == "alac" {
|
||||||
split := strings.Split(variant.Audio, "-")
|
split := strings.Split(variant.Audio, "-")
|
||||||
length := len(split)
|
length := len(split)
|
||||||
length_int,err := strconv.Atoi(split[length-2])
|
length_int, err := strconv.Atoi(split[length-2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if length_int <= config.AlacMax{
|
if length_int <= config.AlacMax {
|
||||||
HZ,err:=strconv.Atoi(split[length-2])
|
HZ, err := strconv.Atoi(split[length-2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
KHZ:=float64(HZ) / 1000.0
|
KHZ := float64(HZ) / 1000.0
|
||||||
Quality = fmt.Sprintf("%sB-%.1fkHz", split[length-1], KHZ)
|
Quality = fmt.Sprintf("%sB-%.1fkHz", split[length-1], KHZ)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -1699,11 +1702,11 @@ func extractMedia(b string) (string, []string, error) {
|
|||||||
if variant.Codecs == "alac" {
|
if variant.Codecs == "alac" {
|
||||||
split := strings.Split(variant.Audio, "-")
|
split := strings.Split(variant.Audio, "-")
|
||||||
length := len(split)
|
length := len(split)
|
||||||
length_int,err := strconv.Atoi(split[length-2])
|
length_int, err := strconv.Atoi(split[length-2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
if length_int <= config.AlacMax{
|
if length_int <= config.AlacMax {
|
||||||
fmt.Printf("%s-bit / %s Hz\n", split[length-1], split[length-2])
|
fmt.Printf("%s-bit / %s Hz\n", split[length-1], split[length-2])
|
||||||
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -4,10 +4,8 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/beevik/etree"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
@ -23,6 +21,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/beevik/etree"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
"github.com/abema/go-mp4"
|
"github.com/abema/go-mp4"
|
||||||
"github.com/grafov/m3u8"
|
"github.com/grafov/m3u8"
|
||||||
)
|
)
|
||||||
@ -35,6 +36,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
forbiddenNames = regexp.MustCompile(`[/\\<>:"|?*]`)
|
forbiddenNames = regexp.MustCompile(`[/\\<>:"|?*]`)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
MediaUserToken string `yaml:"media-user-token"`
|
MediaUserToken string `yaml:"media-user-token"`
|
||||||
SaveLrcFile bool `yaml:"save-lrc-file"`
|
SaveLrcFile bool `yaml:"save-lrc-file"`
|
||||||
@ -1063,8 +1065,8 @@ func getSongLyrics(songId string, storefront string, token string, userToken str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeCover(sanAlbumFolder,name string, url string) error {
|
func writeCover(sanAlbumFolder, name string, url string) error {
|
||||||
covPath := filepath.Join(sanAlbumFolder, name+"." + config.CoverFormat)
|
covPath := filepath.Join(sanAlbumFolder, name+"."+config.CoverFormat)
|
||||||
exists, err := fileExists(covPath)
|
exists, err := fileExists(covPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to check if cover exists.")
|
fmt.Println("Failed to check if cover exists.")
|
||||||
@ -1125,13 +1127,13 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var singerFoldername string
|
var singerFoldername string
|
||||||
if config.ArtistFolderFormat != ""{
|
if config.ArtistFolderFormat != "" {
|
||||||
if strings.Contains(albumId, "pl.") {
|
if strings.Contains(albumId, "pl.") {
|
||||||
singerFoldername = strings.NewReplacer(
|
singerFoldername = strings.NewReplacer(
|
||||||
"{ArtistName}", "Apple Music",
|
"{ArtistName}", "Apple Music",
|
||||||
"{ArtistId}", "",
|
"{ArtistId}", "",
|
||||||
).Replace(config.ArtistFolderFormat)
|
).Replace(config.ArtistFolderFormat)
|
||||||
}else{
|
} else {
|
||||||
singerFoldername = strings.NewReplacer(
|
singerFoldername = strings.NewReplacer(
|
||||||
"{ArtistName}", meta.Data[0].Attributes.ArtistName,
|
"{ArtistName}", meta.Data[0].Attributes.ArtistName,
|
||||||
"{ArtistId}", meta.Data[0].Relationships.Artists.Data[0].ID,
|
"{ArtistId}", meta.Data[0].Relationships.Artists.Data[0].ID,
|
||||||
@ -1145,46 +1147,45 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
}
|
}
|
||||||
singerFolder := filepath.Join(config.AtmosSaveFolder, forbiddenNames.ReplaceAllString(singerFoldername, "_"))
|
singerFolder := filepath.Join(config.AtmosSaveFolder, forbiddenNames.ReplaceAllString(singerFoldername, "_"))
|
||||||
stringsToJoin := []string{}
|
stringsToJoin := []string{}
|
||||||
if meta.Data[0].Attributes.IsAppleDigitalMaster{
|
if meta.Data[0].Attributes.IsAppleDigitalMaster || meta.Data[0].Attributes.IsMasteredForItunes {
|
||||||
if config.AppleMasterChoice != ""{
|
if config.AppleMasterChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if meta.Data[0].Attributes.ContentRating=="explicit"{
|
if meta.Data[0].Attributes.ContentRating == "explicit" {
|
||||||
if config.ExplicitChoice != ""{
|
if config.ExplicitChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if meta.Data[0].Attributes.ContentRating=="clean"{
|
if meta.Data[0].Attributes.ContentRating == "clean" {
|
||||||
if config.CleanChoice != ""{
|
if config.CleanChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Tag_string := strings.Join(stringsToJoin, " ")
|
Tag_string := strings.Join(stringsToJoin, " ")
|
||||||
var albumFolder string
|
var albumFolder string
|
||||||
Quality:=fmt.Sprintf("%dkbps", config.AtmosMax-2000)
|
Quality := fmt.Sprintf("%dkbps", config.AtmosMax-2000)
|
||||||
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}", meta.Data[0].Attributes.Name,
|
||||||
"{PlaylistId}", albumId,
|
"{PlaylistId}", albumId,
|
||||||
"{Quality}",Quality,
|
"{Quality}", Quality,
|
||||||
"{Codec}", "Atmos",
|
"{Codec}", "Atmos",
|
||||||
"{Tag}",Tag_string,
|
"{Tag}", Tag_string,
|
||||||
).Replace(config.PlaylistFolderFormat)
|
).Replace(config.PlaylistFolderFormat)
|
||||||
}else{
|
} else {
|
||||||
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}", meta.Data[0].Attributes.ArtistName,
|
||||||
"{AlbumName}", meta.Data[0].Attributes.Name,
|
"{AlbumName}", meta.Data[0].Attributes.Name,
|
||||||
"{UPC}", meta.Data[0].Attributes.Upc,
|
"{UPC}", meta.Data[0].Attributes.Upc,
|
||||||
"{RecordLabel}", meta.Data[0].Attributes.RecordLabel,
|
|
||||||
"{Copyright}", meta.Data[0].Attributes.Copyright,
|
"{Copyright}", meta.Data[0].Attributes.Copyright,
|
||||||
"{AlbumId}", albumId,
|
"{AlbumId}", albumId,
|
||||||
"{Quality}",Quality,
|
"{Quality}", Quality,
|
||||||
"{Codec}", "Atmos",
|
"{Codec}", "Atmos",
|
||||||
"{Tag}",Tag_string,
|
"{Tag}", Tag_string,
|
||||||
).Replace(config.AlbumFolderFormat)
|
).Replace(config.AlbumFolderFormat)
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(albumFolder, ".") {
|
if strings.HasSuffix(albumFolder, ".") {
|
||||||
@ -1194,7 +1195,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
sanAlbumFolder := filepath.Join(singerFolder, forbiddenNames.ReplaceAllString(albumFolder, "_"))
|
sanAlbumFolder := filepath.Join(singerFolder, forbiddenNames.ReplaceAllString(albumFolder, "_"))
|
||||||
os.MkdirAll(sanAlbumFolder, os.ModePerm)
|
os.MkdirAll(sanAlbumFolder, os.ModePerm)
|
||||||
fmt.Println(albumFolder)
|
fmt.Println(albumFolder)
|
||||||
err = writeCover(sanAlbumFolder,"cover", meta.Data[0].Attributes.Artwork.URL)
|
err = writeCover(sanAlbumFolder, "cover", meta.Data[0].Attributes.Artwork.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to write cover.")
|
fmt.Println("Failed to write cover.")
|
||||||
}
|
}
|
||||||
@ -1214,18 +1215,18 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
stringsToJoin := []string{}
|
stringsToJoin := []string{}
|
||||||
if track.Attributes.IsAppleDigitalMaster{
|
if track.Attributes.IsAppleDigitalMaster {
|
||||||
if config.AppleMasterChoice != ""{
|
if config.AppleMasterChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if track.Attributes.ContentRating=="explicit"{
|
if track.Attributes.ContentRating == "explicit" {
|
||||||
if config.ExplicitChoice != ""{
|
if config.ExplicitChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if track.Attributes.ContentRating=="clean"{
|
if track.Attributes.ContentRating == "clean" {
|
||||||
if config.CleanChoice != ""{
|
if config.CleanChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1236,9 +1237,9 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
"{SongName}", track.Attributes.Name,
|
"{SongName}", track.Attributes.Name,
|
||||||
"{DiscNumber}", string(track.Attributes.DiscNumber),
|
"{DiscNumber}", string(track.Attributes.DiscNumber),
|
||||||
"{TrackNumber}", fmt.Sprintf("%02d", track.Attributes.TrackNumber),
|
"{TrackNumber}", fmt.Sprintf("%02d", track.Attributes.TrackNumber),
|
||||||
"{Quality}",Quality,
|
"{Quality}", Quality,
|
||||||
"{Codec}", "Atmos",
|
"{Codec}", "Atmos",
|
||||||
"{Tag}",Tag_string,
|
"{Tag}", Tag_string,
|
||||||
).Replace(config.SongFileFormat)
|
).Replace(config.SongFileFormat)
|
||||||
fmt.Println(songName)
|
fmt.Println(songName)
|
||||||
filename := fmt.Sprintf("%s.ec3", forbiddenNames.ReplaceAllString(songName, "_"))
|
filename := fmt.Sprintf("%s.ec3", forbiddenNames.ReplaceAllString(songName, "_"))
|
||||||
@ -1327,13 +1328,13 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
}
|
}
|
||||||
if config.EmbedCover {
|
if config.EmbedCover {
|
||||||
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
||||||
err = writeCover(sanAlbumFolder,track.ID, track.Attributes.Artwork.URL)
|
err = writeCover(sanAlbumFolder, track.ID, track.Attributes.Artwork.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to write cover.")
|
fmt.Println("Failed to write cover.")
|
||||||
}
|
}
|
||||||
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder,track.ID, config.CoverFormat))
|
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder, track.ID, config.CoverFormat))
|
||||||
}else{
|
} else {
|
||||||
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder,"cover", config.CoverFormat))
|
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder, "cover", config.CoverFormat))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if strings.Contains(albumId, "pl.") && !config.UseSongInfoForPlaylist {
|
if strings.Contains(albumId, "pl.") && !config.UseSongInfoForPlaylist {
|
||||||
@ -1341,17 +1342,17 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
tags = append(tags, fmt.Sprintf("track=%s", trackNum))
|
tags = append(tags, fmt.Sprintf("track=%s", trackNum))
|
||||||
tags = append(tags, fmt.Sprintf("tracknum=%d/%d", trackNum, trackTotal))
|
tags = append(tags, fmt.Sprintf("tracknum=%d/%d", trackNum, trackTotal))
|
||||||
tags = append(tags, fmt.Sprintf("album=%s", meta.Data[0].Attributes.Name))
|
tags = append(tags, fmt.Sprintf("album=%s", meta.Data[0].Attributes.Name))
|
||||||
}else{
|
} 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("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("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("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))
|
tags = append(tags, fmt.Sprintf("album=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName))
|
||||||
}
|
}
|
||||||
if track.Attributes.ContentRating=="explicit"{
|
if track.Attributes.ContentRating == "explicit" {
|
||||||
tags = append(tags, "rating=1")
|
tags = append(tags, "rating=1")
|
||||||
}else if track.Attributes.ContentRating=="clean"{
|
} else if track.Attributes.ContentRating == "clean" {
|
||||||
tags = append(tags, "rating=2")
|
tags = append(tags, "rating=2")
|
||||||
}else{
|
} else {
|
||||||
tags = append(tags, "rating=0")
|
tags = append(tags, "rating=0")
|
||||||
}
|
}
|
||||||
tagsString := strings.Join(tags, ":")
|
tagsString := strings.Join(tags, ":")
|
||||||
@ -1367,8 +1368,8 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
||||||
if err := os.Remove(fmt.Sprintf("%s/%s.%s", sanAlbumFolder,track.ID, config.CoverFormat)); err != nil {
|
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)
|
fmt.Printf("Error deleting file: %s/%s.%s\n", sanAlbumFolder, track.ID, config.CoverFormat)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1491,11 +1492,11 @@ func extractMedia(b string) (string, []string, error) {
|
|||||||
if variant.Codecs == "ec-3" {
|
if variant.Codecs == "ec-3" {
|
||||||
split := strings.Split(variant.Audio, "-")
|
split := strings.Split(variant.Audio, "-")
|
||||||
length := len(split)
|
length := len(split)
|
||||||
length_int,err := strconv.Atoi(split[length-1])
|
length_int, err := strconv.Atoi(split[length-1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
if length_int <= config.AtmosMax{
|
if length_int <= config.AtmosMax {
|
||||||
fmt.Printf("%s\n", variant.Audio)
|
fmt.Printf("%s\n", variant.Audio)
|
||||||
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
109
main_select.go
109
main_select.go
@ -5,10 +5,8 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/beevik/etree"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
@ -24,6 +22,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/beevik/etree"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
"github.com/abema/go-mp4"
|
"github.com/abema/go-mp4"
|
||||||
"github.com/grafov/m3u8"
|
"github.com/grafov/m3u8"
|
||||||
)
|
)
|
||||||
@ -36,6 +37,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
forbiddenNames = regexp.MustCompile(`[/\\<>:"|?*]`)
|
forbiddenNames = regexp.MustCompile(`[/\\<>:"|?*]`)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
MediaUserToken string `yaml:"media-user-token"`
|
MediaUserToken string `yaml:"media-user-token"`
|
||||||
SaveLrcFile bool `yaml:"save-lrc-file"`
|
SaveLrcFile bool `yaml:"save-lrc-file"`
|
||||||
@ -685,10 +687,10 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
AlbumName:=meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName
|
AlbumName := meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName
|
||||||
if strings.Contains(meta.Data[0].ID, "pl."){
|
if strings.Contains(meta.Data[0].ID, "pl.") {
|
||||||
if !config.UseSongInfoForPlaylist {
|
if !config.UseSongInfoForPlaylist {
|
||||||
AlbumName=meta.Data[0].Attributes.Name
|
AlbumName = meta.Data[0].Attributes.Name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = addMeta(mp4.BoxType{'\251', 'a', 'l', 'b'}, AlbumName)
|
err = addMeta(mp4.BoxType{'\251', 'a', 'l', 'b'}, AlbumName)
|
||||||
@ -800,7 +802,7 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(meta.Data[0].ID, "pl."){
|
if !strings.Contains(meta.Data[0].ID, "pl.") {
|
||||||
plID, err := strconv.ParseUint(meta.Data[0].ID, 10, 32)
|
plID, err := strconv.ParseUint(meta.Data[0].ID, 10, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -830,8 +832,8 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
binary.BigEndian.PutUint32(trkn, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber))
|
binary.BigEndian.PutUint32(trkn, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber))
|
||||||
binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal))
|
binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal))
|
||||||
binary.BigEndian.PutUint32(disk, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.DiscNumber))
|
binary.BigEndian.PutUint32(disk, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.DiscNumber))
|
||||||
binary.BigEndian.PutUint16(disk[4:], uint16(meta.Data[0].Relationships.Tracks.Data[trackTotal - 1].Attributes.DiscNumber))
|
binary.BigEndian.PutUint16(disk[4:], uint16(meta.Data[0].Relationships.Tracks.Data[trackTotal-1].Attributes.DiscNumber))
|
||||||
if strings.Contains(meta.Data[0].ID, "pl."){
|
if strings.Contains(meta.Data[0].ID, "pl.") {
|
||||||
if !config.UseSongInfoForPlaylist {
|
if !config.UseSongInfoForPlaylist {
|
||||||
binary.BigEndian.PutUint32(trkn, uint32(trackNum))
|
binary.BigEndian.PutUint32(trkn, uint32(trackNum))
|
||||||
binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal))
|
binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal))
|
||||||
@ -1111,8 +1113,8 @@ func getSongLyrics(songId string, storefront string, token string, userToken str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeCover(sanAlbumFolder,name string, url string) error {
|
func writeCover(sanAlbumFolder, name string, url string) error {
|
||||||
covPath := filepath.Join(sanAlbumFolder, name+"." + config.CoverFormat)
|
covPath := filepath.Join(sanAlbumFolder, name+"."+config.CoverFormat)
|
||||||
exists, err := fileExists(covPath)
|
exists, err := fileExists(covPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to check if cover exists.")
|
fmt.Println("Failed to check if cover exists.")
|
||||||
@ -1183,13 +1185,13 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var singerFoldername string
|
var singerFoldername string
|
||||||
if config.ArtistFolderFormat != ""{
|
if config.ArtistFolderFormat != "" {
|
||||||
if strings.Contains(albumId, "pl.") {
|
if strings.Contains(albumId, "pl.") {
|
||||||
singerFoldername = strings.NewReplacer(
|
singerFoldername = strings.NewReplacer(
|
||||||
"{ArtistName}", "Apple Music",
|
"{ArtistName}", "Apple Music",
|
||||||
"{ArtistId}", "",
|
"{ArtistId}", "",
|
||||||
).Replace(config.ArtistFolderFormat)
|
).Replace(config.ArtistFolderFormat)
|
||||||
}else{
|
} else {
|
||||||
singerFoldername = strings.NewReplacer(
|
singerFoldername = strings.NewReplacer(
|
||||||
"{ArtistName}", meta.Data[0].Attributes.ArtistName,
|
"{ArtistName}", meta.Data[0].Attributes.ArtistName,
|
||||||
"{ArtistId}", meta.Data[0].Relationships.Artists.Data[0].ID,
|
"{ArtistId}", meta.Data[0].Relationships.Artists.Data[0].ID,
|
||||||
@ -1203,18 +1205,18 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
}
|
}
|
||||||
singerFolder := filepath.Join(config.AlacSaveFolder, forbiddenNames.ReplaceAllString(singerFoldername, "_"))
|
singerFolder := filepath.Join(config.AlacSaveFolder, forbiddenNames.ReplaceAllString(singerFoldername, "_"))
|
||||||
stringsToJoin := []string{}
|
stringsToJoin := []string{}
|
||||||
if meta.Data[0].Attributes.IsAppleDigitalMaster{
|
if meta.Data[0].Attributes.IsAppleDigitalMaster || meta.Data[0].Attributes.IsMasteredForItunes {
|
||||||
if config.AppleMasterChoice != ""{
|
if config.AppleMasterChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if meta.Data[0].Attributes.ContentRating=="explicit"{
|
if meta.Data[0].Attributes.ContentRating == "explicit" {
|
||||||
if config.ExplicitChoice != ""{
|
if config.ExplicitChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if meta.Data[0].Attributes.ContentRating=="clean"{
|
if meta.Data[0].Attributes.ContentRating == "clean" {
|
||||||
if config.CleanChoice != ""{
|
if config.CleanChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1227,8 +1229,8 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
fmt.Println("Unavailable in ALAC.")
|
fmt.Println("Unavailable in ALAC.")
|
||||||
}
|
}
|
||||||
var Quality string
|
var Quality string
|
||||||
if strings.Contains(config.AlbumFolderFormat, "Quality"){
|
if strings.Contains(config.AlbumFolderFormat, "Quality") {
|
||||||
Quality,err = extractMediaQuality(manifest1.Attributes.ExtendedAssetUrls.EnhancedHls)
|
Quality, err = extractMediaQuality(manifest1.Attributes.ExtendedAssetUrls.EnhancedHls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to extract quality from manifest.\n", err)
|
fmt.Println("Failed to extract quality from manifest.\n", err)
|
||||||
}
|
}
|
||||||
@ -1239,23 +1241,22 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
"{ArtistName}", "Apple Music",
|
"{ArtistName}", "Apple Music",
|
||||||
"{PlaylistName}", meta.Data[0].Attributes.Name,
|
"{PlaylistName}", meta.Data[0].Attributes.Name,
|
||||||
"{PlaylistId}", albumId,
|
"{PlaylistId}", albumId,
|
||||||
"{Quality}",Quality,
|
"{Quality}", Quality,
|
||||||
"{Codec}", "ALAC",
|
"{Codec}", "ALAC",
|
||||||
"{Tag}",Tag_string,
|
"{Tag}", Tag_string,
|
||||||
).Replace(config.PlaylistFolderFormat)
|
).Replace(config.PlaylistFolderFormat)
|
||||||
}else{
|
} else {
|
||||||
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}", meta.Data[0].Attributes.ArtistName,
|
||||||
"{AlbumName}", meta.Data[0].Attributes.Name,
|
"{AlbumName}", meta.Data[0].Attributes.Name,
|
||||||
"{UPC}", meta.Data[0].Attributes.Upc,
|
"{UPC}", meta.Data[0].Attributes.Upc,
|
||||||
"{RecordLabel}", meta.Data[0].Attributes.RecordLabel,
|
|
||||||
"{Copyright}", meta.Data[0].Attributes.Copyright,
|
"{Copyright}", meta.Data[0].Attributes.Copyright,
|
||||||
"{AlbumId}", albumId,
|
"{AlbumId}", albumId,
|
||||||
"{Quality}", Quality,
|
"{Quality}", Quality,
|
||||||
"{Codec}", "ALAC",
|
"{Codec}", "ALAC",
|
||||||
"{Tag}",Tag_string,
|
"{Tag}", Tag_string,
|
||||||
).Replace(config.AlbumFolderFormat)
|
).Replace(config.AlbumFolderFormat)
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(albumFolder, ".") {
|
if strings.HasSuffix(albumFolder, ".") {
|
||||||
@ -1265,7 +1266,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
sanAlbumFolder := filepath.Join(singerFolder, forbiddenNames.ReplaceAllString(albumFolder, "_"))
|
sanAlbumFolder := filepath.Join(singerFolder, forbiddenNames.ReplaceAllString(albumFolder, "_"))
|
||||||
os.MkdirAll(sanAlbumFolder, os.ModePerm)
|
os.MkdirAll(sanAlbumFolder, os.ModePerm)
|
||||||
fmt.Println(albumFolder)
|
fmt.Println(albumFolder)
|
||||||
err = writeCover(sanAlbumFolder,"cover", meta.Data[0].Attributes.Artwork.URL)
|
err = writeCover(sanAlbumFolder, "cover", meta.Data[0].Attributes.Artwork.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to write cover.")
|
fmt.Println("Failed to write cover.")
|
||||||
}
|
}
|
||||||
@ -1284,7 +1285,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
manually_txt := false
|
manually_txt := false
|
||||||
m3u8_txt := ""
|
m3u8_txt := ""
|
||||||
if strings.Contains(input, "txt") {
|
if strings.Contains(input, "txt") {
|
||||||
m3u8_txt= strings.TrimSpace(input)
|
m3u8_txt = strings.TrimSpace(input)
|
||||||
fmt.Print(m3u8_txt)
|
fmt.Print(m3u8_txt)
|
||||||
strArr := make([]string, len(arr))
|
strArr := make([]string, len(arr))
|
||||||
for i, num := range arr {
|
for i, num := range arr {
|
||||||
@ -1328,26 +1329,26 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var Quality string
|
var Quality string
|
||||||
if strings.Contains(config.SongFileFormat, "Quality"){
|
if strings.Contains(config.SongFileFormat, "Quality") {
|
||||||
Quality,err = extractMediaQuality(manifest.Attributes.ExtendedAssetUrls.EnhancedHls)
|
Quality, err = extractMediaQuality(manifest.Attributes.ExtendedAssetUrls.EnhancedHls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to extract quality from manifest.\n", err)
|
fmt.Println("Failed to extract quality from manifest.\n", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stringsToJoin := []string{}
|
stringsToJoin := []string{}
|
||||||
if track.Attributes.IsAppleDigitalMaster{
|
if track.Attributes.IsAppleDigitalMaster {
|
||||||
if config.AppleMasterChoice != ""{
|
if config.AppleMasterChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
stringsToJoin = append(stringsToJoin, config.AppleMasterChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if track.Attributes.ContentRating=="explicit"{
|
if track.Attributes.ContentRating == "explicit" {
|
||||||
if config.ExplicitChoice != ""{
|
if config.ExplicitChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
stringsToJoin = append(stringsToJoin, config.ExplicitChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if track.Attributes.ContentRating=="clean"{
|
if track.Attributes.ContentRating == "clean" {
|
||||||
if config.CleanChoice != ""{
|
if config.CleanChoice != "" {
|
||||||
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
stringsToJoin = append(stringsToJoin, config.CleanChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1358,9 +1359,9 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
"{SongName}", track.Attributes.Name,
|
"{SongName}", track.Attributes.Name,
|
||||||
"{DiscNumber}", string(track.Attributes.DiscNumber),
|
"{DiscNumber}", string(track.Attributes.DiscNumber),
|
||||||
"{TrackNumber}", fmt.Sprintf("%02d", track.Attributes.TrackNumber),
|
"{TrackNumber}", fmt.Sprintf("%02d", track.Attributes.TrackNumber),
|
||||||
"{Quality}",Quality,
|
"{Quality}", Quality,
|
||||||
"{Codec}", "ALAC",
|
"{Codec}", "ALAC",
|
||||||
"{Tag}",Tag_string,
|
"{Tag}", Tag_string,
|
||||||
).Replace(config.SongFileFormat)
|
).Replace(config.SongFileFormat)
|
||||||
fmt.Println(songName)
|
fmt.Println(songName)
|
||||||
filename := fmt.Sprintf("%s.m4a", forbiddenNames.ReplaceAllString(songName, "_"))
|
filename := fmt.Sprintf("%s.m4a", forbiddenNames.ReplaceAllString(songName, "_"))
|
||||||
@ -1408,7 +1409,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
if strings.HasPrefix(line, track.ID) {
|
if strings.HasPrefix(line, track.ID) {
|
||||||
parts := strings.SplitN(line, ",", 2)
|
parts := strings.SplitN(line, ",", 2)
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
manifest.Attributes.ExtendedAssetUrls.EnhancedHls=parts[1]
|
manifest.Attributes.ExtendedAssetUrls.EnhancedHls = parts[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1424,7 +1425,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
m3u8_url = strings.TrimSpace(m3u8_url)
|
m3u8_url = strings.TrimSpace(m3u8_url)
|
||||||
manifest.Attributes.ExtendedAssetUrls.EnhancedHls=m3u8_url
|
manifest.Attributes.ExtendedAssetUrls.EnhancedHls = m3u8_url
|
||||||
}
|
}
|
||||||
trackUrl, keys, err := extractMedia(manifest.Attributes.ExtendedAssetUrls.EnhancedHls)
|
trackUrl, keys, err := extractMedia(manifest.Attributes.ExtendedAssetUrls.EnhancedHls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1459,21 +1460,21 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
}
|
}
|
||||||
if config.EmbedCover {
|
if config.EmbedCover {
|
||||||
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
||||||
err = writeCover(sanAlbumFolder,track.ID, track.Attributes.Artwork.URL)
|
err = writeCover(sanAlbumFolder, track.ID, track.Attributes.Artwork.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to write cover.")
|
fmt.Println("Failed to write cover.")
|
||||||
}
|
}
|
||||||
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder,track.ID, config.CoverFormat))
|
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder, track.ID, config.CoverFormat))
|
||||||
}else{
|
} else {
|
||||||
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder,"cover", config.CoverFormat))
|
tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder, "cover", config.CoverFormat))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if track.Attributes.ContentRating=="explicit"{
|
if track.Attributes.ContentRating == "explicit" {
|
||||||
tags = append(tags, "rating=1")
|
tags = append(tags, "rating=1")
|
||||||
}else if track.Attributes.ContentRating=="clean"{
|
} else if track.Attributes.ContentRating == "clean" {
|
||||||
tags = append(tags, "rating=2")
|
tags = append(tags, "rating=2")
|
||||||
}else{
|
} else {
|
||||||
tags = append(tags, "rating=0")
|
tags = append(tags, "rating=0")
|
||||||
}
|
}
|
||||||
tagsString := strings.Join(tags, ":")
|
tagsString := strings.Join(tags, ":")
|
||||||
@ -1483,8 +1484,8 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist {
|
||||||
if err := os.Remove(fmt.Sprintf("%s/%s.%s", sanAlbumFolder,track.ID, config.CoverFormat)); err != nil {
|
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)
|
fmt.Printf("Error deleting file: %s/%s.%s\n", sanAlbumFolder, track.ID, config.CoverFormat)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1600,16 +1601,16 @@ func extractMediaQuality(b string) (string, error) {
|
|||||||
if variant.Codecs == "alac" {
|
if variant.Codecs == "alac" {
|
||||||
split := strings.Split(variant.Audio, "-")
|
split := strings.Split(variant.Audio, "-")
|
||||||
length := len(split)
|
length := len(split)
|
||||||
length_int,err := strconv.Atoi(split[length-2])
|
length_int, err := strconv.Atoi(split[length-2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if length_int <= config.AlacMax{
|
if length_int <= config.AlacMax {
|
||||||
HZ,err:=strconv.Atoi(split[length-2])
|
HZ, err := strconv.Atoi(split[length-2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
KHZ:=float64(HZ) / 1000.0
|
KHZ := float64(HZ) / 1000.0
|
||||||
Quality = fmt.Sprintf("%sB-%.1fkHz", split[length-1], KHZ)
|
Quality = fmt.Sprintf("%sB-%.1fkHz", split[length-1], KHZ)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -1649,11 +1650,11 @@ func extractMedia(b string) (string, []string, error) {
|
|||||||
if variant.Codecs == "alac" {
|
if variant.Codecs == "alac" {
|
||||||
split := strings.Split(variant.Audio, "-")
|
split := strings.Split(variant.Audio, "-")
|
||||||
length := len(split)
|
length := len(split)
|
||||||
length_int,err := strconv.Atoi(split[length-2])
|
length_int, err := strconv.Atoi(split[length-2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
if length_int <= config.AlacMax{
|
if length_int <= config.AlacMax {
|
||||||
fmt.Printf("%s-bit / %s Hz\n", split[length-1], split[length-2])
|
fmt.Printf("%s-bit / %s Hz\n", split[length-1], split[length-2])
|
||||||
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
streamUrlTemp, err := masterUrl.Parse(variant.URI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user