mirror of
https://git.sr.ht/~joren/streamrip-go
synced 2026-06-17 15:05:39 +02:00
unify folder naming with resolved audio profiles across providers
This commit is contained in:
@@ -48,6 +48,7 @@ type ripTrackOptions struct {
|
||||
albumFolder string
|
||||
albumEmbedCover string
|
||||
albumArtist string
|
||||
prefetched *provider.Downloadable
|
||||
index int
|
||||
total int
|
||||
albumDiscTotal int
|
||||
@@ -56,6 +57,15 @@ type ripTrackOptions struct {
|
||||
playlistPos int
|
||||
}
|
||||
|
||||
type folderAudioValues struct {
|
||||
container string
|
||||
codec string
|
||||
quality string
|
||||
bitDepth int
|
||||
samplingRate string
|
||||
bitrateKbps int
|
||||
}
|
||||
|
||||
type collectionAlbum struct {
|
||||
ID string
|
||||
Meta map[string]any
|
||||
@@ -535,15 +545,6 @@ func (m *Main) ripAlbum(ctx context.Context, p provider.Client, source, albumID
|
||||
year := naming.YearFromDate(releaseDate)
|
||||
bitDepth := jsonutil.IntFromAny(albumMeta["maximum_bit_depth"])
|
||||
sampling := jsonutil.StringFromAny(albumMeta["maximum_sampling_rate"])
|
||||
if bitDepth == 0 || sampling == "" {
|
||||
fallbackBitDepth, fallbackSampling := m.qualityProfileForSource(source)
|
||||
if bitDepth == 0 {
|
||||
bitDepth = fallbackBitDepth
|
||||
}
|
||||
if sampling == "" {
|
||||
sampling = fallbackSampling
|
||||
}
|
||||
}
|
||||
|
||||
tracksMap, ok := albumMeta["tracks"].(map[string]any)
|
||||
if !ok {
|
||||
@@ -571,7 +572,14 @@ func (m *Main) ripAlbum(ctx context.Context, p provider.Client, source, albumID
|
||||
}
|
||||
}
|
||||
|
||||
folder := m.albumFolderPath(source, albumID, albumTitle, albumArtist, year, bitDepth, sampling)
|
||||
var prefetched *provider.Downloadable
|
||||
if len(trackIDs) > 0 {
|
||||
if d, dErr := p.GetDownloadable(ctx, trackIDs[0], m.qualityForSource(source)); dErr == nil {
|
||||
prefetched = d
|
||||
}
|
||||
}
|
||||
audioVals := m.folderAudioValues(source, bitDepth, sampling, prefetched)
|
||||
folder := m.albumFolderPath(source, albumID, albumTitle, albumArtist, year, audioVals)
|
||||
artRes, _ := artwork.Prepare(ctx, m.DL, folder, albumMeta, m.Config.Session.Artwork, false)
|
||||
total := len(trackIDs)
|
||||
discTotal := jsonutil.IntFromAny(albumMeta["media_count"])
|
||||
@@ -584,6 +592,9 @@ func (m *Main) ripAlbum(ctx context.Context, p provider.Client, source, albumID
|
||||
if !m.Config.Session.Downloads.Concurrency || m.Config.Session.Downloads.MaxConnections == 1 {
|
||||
for i, trackID := range trackIDs {
|
||||
opts := ripTrackOptions{albumFolder: folder, albumEmbedCover: artRes.EmbedPath, albumArtist: albumArtist, index: i + 1, total: total, albumDiscTotal: discTotal}
|
||||
if i == 0 {
|
||||
opts.prefetched = prefetched
|
||||
}
|
||||
if err := m.ripTrack(ctx, p, source, trackID, "", opts); err != nil {
|
||||
failures++
|
||||
m.logf("track failed: id=%s reason=%v\n", trackID, err)
|
||||
@@ -609,6 +620,9 @@ func (m *Main) ripAlbum(ctx context.Context, p provider.Client, source, albumID
|
||||
defer wg.Done()
|
||||
defer func() { <-sem }()
|
||||
opts := ripTrackOptions{albumFolder: folder, albumEmbedCover: artRes.EmbedPath, albumArtist: albumArtist, index: idx, total: total, albumDiscTotal: discTotal}
|
||||
if idx == 1 {
|
||||
opts.prefetched = prefetched
|
||||
}
|
||||
if err := m.ripTrack(ctx, p, source, tid, "", opts); err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
@@ -834,13 +848,16 @@ func (m *Main) ripTrack(ctx context.Context, p provider.Client, source, id, fall
|
||||
applyPlaylistMetadataOverrides(meta, m.Config.Session.Metadata, opts.playlistName, opts.playlistPos)
|
||||
}
|
||||
|
||||
d, err := p.GetDownloadable(ctx, id, m.qualityForSource(source))
|
||||
if err != nil {
|
||||
_ = m.Store.MarkFailed(ctx, source, "track", id)
|
||||
return fmt.Errorf("id=%s title=%q get_downloadable: %w", id, title, err)
|
||||
d := opts.prefetched
|
||||
if d == nil {
|
||||
d, err = p.GetDownloadable(ctx, id, m.qualityForSource(source))
|
||||
if err != nil {
|
||||
_ = m.Store.MarkFailed(ctx, source, "track", id)
|
||||
return fmt.Errorf("id=%s title=%q get_downloadable: %w", id, title, err)
|
||||
}
|
||||
}
|
||||
|
||||
outPath := m.trackOutputPath(source, id, title, d.Extension, meta, opts.albumFolder, opts.albumDiscTotal)
|
||||
outPath := m.trackOutputPath(source, id, title, d.Extension, d, meta, opts.albumFolder, opts.albumDiscTotal)
|
||||
if opts.total > 0 && (!m.Config.Session.CLI.ProgressBars || !m.Config.Session.CLI.TextOutput || !m.DL.ProgressEnabled()) {
|
||||
m.logf("[%d/%d] %s\n", opts.index, opts.total, filepath.Base(outPath))
|
||||
}
|
||||
@@ -953,20 +970,95 @@ func (m *Main) qualityProfileForSource(source string) (int, string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Main) albumFolderPath(source, albumID, albumTitle, albumArtist, year string, bitDepth int, samplingRate string) string {
|
||||
func (m *Main) folderAudioValues(source string, metaBitDepth int, metaSampling string, d *provider.Downloadable) folderAudioValues {
|
||||
vals := folderAudioValues{
|
||||
container: "FLAC",
|
||||
bitDepth: metaBitDepth,
|
||||
quality: "Unknown",
|
||||
codec: "Unknown",
|
||||
}
|
||||
if s := strings.TrimSpace(metaSampling); s != "" {
|
||||
vals.samplingRate = s
|
||||
}
|
||||
|
||||
if d != nil {
|
||||
if c := strings.TrimSpace(d.Audio.Container); c != "" {
|
||||
vals.container = strings.ToUpper(c)
|
||||
} else if c := containerFromExtension(d.Extension); c != "" {
|
||||
vals.container = c
|
||||
}
|
||||
if d.Audio.BitDepth > 0 {
|
||||
vals.bitDepth = d.Audio.BitDepth
|
||||
}
|
||||
if s := strings.TrimSpace(d.Audio.SamplingRate); s != "" {
|
||||
vals.samplingRate = s
|
||||
}
|
||||
if c := strings.TrimSpace(d.Audio.Codec); c != "" {
|
||||
vals.codec = c
|
||||
}
|
||||
if q := strings.TrimSpace(d.Audio.Quality); q != "" {
|
||||
vals.quality = q
|
||||
}
|
||||
if d.Audio.BitrateKbps > 0 {
|
||||
vals.bitrateKbps = d.Audio.BitrateKbps
|
||||
}
|
||||
}
|
||||
|
||||
if vals.bitDepth == 0 || vals.samplingRate == "" {
|
||||
fallbackBitDepth, fallbackSampling := m.qualityProfileForSource(source)
|
||||
if vals.bitDepth == 0 {
|
||||
vals.bitDepth = fallbackBitDepth
|
||||
}
|
||||
if vals.samplingRate == "" {
|
||||
vals.samplingRate = fallbackSampling
|
||||
}
|
||||
}
|
||||
if vals.codec == "Unknown" {
|
||||
vals.codec = vals.container
|
||||
}
|
||||
return vals
|
||||
}
|
||||
|
||||
func containerFromExtension(ext string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(ext)) {
|
||||
case "flac":
|
||||
return "FLAC"
|
||||
case "mp3":
|
||||
return "MP3"
|
||||
case "m4a", "aac":
|
||||
return "M4A"
|
||||
case "mka":
|
||||
return "MKA"
|
||||
default:
|
||||
v := strings.ToUpper(strings.TrimSpace(ext))
|
||||
if v == "" {
|
||||
return ""
|
||||
}
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Main) albumFolderPath(source, albumID, albumTitle, albumArtist, year string, audio folderAudioValues) string {
|
||||
base := m.Config.Session.Downloads.Folder
|
||||
if m.Config.Session.Downloads.SourceSubdirectories {
|
||||
base = filepath.Join(base, jsonutil.TitleCase(source))
|
||||
}
|
||||
|
||||
bitrate := "Unknown"
|
||||
if audio.bitrateKbps > 0 {
|
||||
bitrate = strconv.Itoa(audio.bitrateKbps)
|
||||
}
|
||||
vals := map[string]string{
|
||||
"albumartist": albumArtist,
|
||||
"title": albumTitle,
|
||||
"year": year,
|
||||
"bit_depth": strconv.Itoa(bitDepth),
|
||||
"sampling_rate": samplingRate,
|
||||
"bit_depth": strconv.Itoa(audio.bitDepth),
|
||||
"sampling_rate": audio.samplingRate,
|
||||
"id": albumID,
|
||||
"container": "FLAC",
|
||||
"container": audio.container,
|
||||
"codec": audio.codec,
|
||||
"quality": audio.quality,
|
||||
"bitrate": bitrate,
|
||||
"albumcomposer": "Unknown",
|
||||
}
|
||||
folderName := naming.FormatTemplate(m.Config.Session.Filepaths.FolderFormat, vals)
|
||||
@@ -978,7 +1070,7 @@ func (m *Main) albumFolderPath(source, albumID, albumTitle, albumArtist, year st
|
||||
return filepath.Join(base, folderName)
|
||||
}
|
||||
|
||||
func (m *Main) trackOutputPath(source, id, title, ext string, trackMeta map[string]any, albumFolder string, albumDiscTotal int) string {
|
||||
func (m *Main) trackOutputPath(source, id, title, ext string, d *provider.Downloadable, trackMeta map[string]any, albumFolder string, albumDiscTotal int) string {
|
||||
base := m.Config.Session.Downloads.Folder
|
||||
if m.Config.Session.Downloads.SourceSubdirectories {
|
||||
base = filepath.Join(base, jsonutil.TitleCase(source))
|
||||
@@ -998,7 +1090,8 @@ func (m *Main) trackOutputPath(source, id, title, ext string, trackMeta map[stri
|
||||
if albumYear == "Unknown" {
|
||||
albumYear = naming.YearFromDate(jsonutil.StringFromAny(trackMeta["release_date"]))
|
||||
}
|
||||
albumFolder = m.albumFolderPath(source, albumID, albumTitle, albumArtist, albumYear, jsonutil.IntFromAny(trackMeta["maximum_bit_depth"]), jsonutil.StringFromAny(trackMeta["maximum_sampling_rate"]))
|
||||
audioVals := m.folderAudioValues(source, jsonutil.IntFromAny(trackMeta["maximum_bit_depth"]), jsonutil.StringFromAny(trackMeta["maximum_sampling_rate"]), d)
|
||||
albumFolder = m.albumFolderPath(source, albumID, albumTitle, albumArtist, albumYear, audioVals)
|
||||
}
|
||||
if albumFolder != "" {
|
||||
base = albumFolder
|
||||
|
||||
Reference in New Issue
Block a user