mirror of
https://git.sr.ht/~joren/streamrip-go
synced 2026-08-24 18:48:21 +02:00
Compare commits
2
Commits
e336bb96f1
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb7854bac3
|
||
|
|
5f61b1a3cf
|
+41
-8
@@ -648,10 +648,7 @@ func (m *Main) ripAlbum(ctx context.Context, p provider.Client, source, albumID
|
||||
}
|
||||
|
||||
albumTitle := titleFromMetadata(albumMeta, albumID)
|
||||
albumArtist := jsonutil.NestedString(albumMeta, "artist", "name")
|
||||
if albumArtist == "" {
|
||||
albumArtist = "Unknown"
|
||||
}
|
||||
albumArtist := extractAlbumArtist(albumMeta)
|
||||
releaseDate := jsonutil.StringFromAny(albumMeta["release_date_original"])
|
||||
if releaseDate == "" {
|
||||
releaseDate = jsonutil.StringFromAny(albumMeta["release_date"])
|
||||
@@ -1224,10 +1221,7 @@ func (m *Main) trackOutputPath(source, id, title, ext string, d *provider.Downlo
|
||||
if albumID == "" {
|
||||
albumID = id
|
||||
}
|
||||
albumArtist := jsonutil.NestedString(trackMeta, "album", "artist", "name")
|
||||
if albumArtist == "" {
|
||||
albumArtist = jsonutil.NestedString(trackMeta, "performer", "name")
|
||||
}
|
||||
albumArtist := extractAlbumArtist(trackMetaAlbum(trackMeta))
|
||||
albumYear := naming.YearFromDate(jsonutil.StringFromAny(trackMeta["release_date_original"]))
|
||||
if albumYear == "Unknown" {
|
||||
albumYear = naming.YearFromDate(jsonutil.StringFromAny(trackMeta["release_date"]))
|
||||
@@ -1613,3 +1607,42 @@ func isFFmpegMissingError(err error) bool {
|
||||
}
|
||||
return strings.Contains(strings.ToLower(err.Error()), "ffmpeg not found")
|
||||
}
|
||||
|
||||
func extractAlbumArtist(albumMeta map[string]any) string {
|
||||
if artistsRaw, ok := albumMeta["artists"].([]any); ok {
|
||||
names := make([]string, 0, len(artistsRaw))
|
||||
for _, a := range artistsRaw {
|
||||
artist, ok := a.(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if name := jsonutil.StringFromAny(artist["name"]); name != "" {
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
if len(names) > 0 {
|
||||
return displayArtistNames(names)
|
||||
}
|
||||
}
|
||||
if names := stringSliceFromAny(albumMeta["artist_names"]); len(names) > 0 {
|
||||
return displayArtistNames(names)
|
||||
}
|
||||
artist := jsonutil.NestedString(albumMeta, "artist", "name")
|
||||
if artist != "" {
|
||||
return artist
|
||||
}
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
func displayArtistNames(names []string) string {
|
||||
switch len(names) {
|
||||
case 0:
|
||||
return ""
|
||||
case 1:
|
||||
return names[0]
|
||||
case 2:
|
||||
return names[0] + " & " + names[1]
|
||||
default:
|
||||
return strings.Join(names[:len(names)-1], ", ") + " & " + names[len(names)-1]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,40 +364,60 @@ func qobuzDownloadExtension(resp map[string]any, quality int, streamURL string)
|
||||
}
|
||||
|
||||
func qobuzAudioProfile(resp map[string]any, requestedQuality int, ext string) provider.AudioProfile {
|
||||
exactBitDepth, _ := intValue(firstNonNil(resp["bit_depth"], resp["bits_depth"], resp["maximum_bit_depth"]))
|
||||
exactSampling, _ := floatValue(firstNonNil(resp["sampling_rate"], resp["sample_rate"], resp["maximum_sampling_rate"]))
|
||||
if formatID, ok := intValue(resp["format_id"]); ok {
|
||||
switch formatID {
|
||||
case 5:
|
||||
if exactBitDepth == 0 {
|
||||
exactBitDepth = 16
|
||||
}
|
||||
if exactSampling == 0 {
|
||||
exactSampling = 44.1
|
||||
}
|
||||
return provider.AudioProfile{
|
||||
Container: "MP3",
|
||||
Codec: "MP3",
|
||||
Quality: "HIGH",
|
||||
BitDepth: 16,
|
||||
SamplingRate: "44.1",
|
||||
BitDepth: exactBitDepth,
|
||||
SamplingRate: formatSamplingRate(exactSampling),
|
||||
BitrateKbps: 320,
|
||||
}
|
||||
case 6:
|
||||
if exactBitDepth == 0 {
|
||||
exactBitDepth = 16
|
||||
}
|
||||
if exactSampling == 0 {
|
||||
exactSampling = 44.1
|
||||
}
|
||||
return provider.AudioProfile{
|
||||
Container: "FLAC",
|
||||
Codec: "FLAC",
|
||||
Quality: "LOSSLESS",
|
||||
BitDepth: 16,
|
||||
SamplingRate: "44.1",
|
||||
BitDepth: exactBitDepth,
|
||||
SamplingRate: formatSamplingRate(exactSampling),
|
||||
}
|
||||
case 7:
|
||||
if exactBitDepth == 0 {
|
||||
exactBitDepth = 24
|
||||
}
|
||||
return provider.AudioProfile{
|
||||
Container: "FLAC",
|
||||
Codec: "FLAC",
|
||||
Quality: "HI_RES",
|
||||
BitDepth: 24,
|
||||
SamplingRate: "96",
|
||||
BitDepth: exactBitDepth,
|
||||
SamplingRate: formatSamplingRate(exactSampling),
|
||||
}
|
||||
case 27:
|
||||
if exactBitDepth == 0 {
|
||||
exactBitDepth = 24
|
||||
}
|
||||
return provider.AudioProfile{
|
||||
Container: "FLAC",
|
||||
Codec: "FLAC",
|
||||
Quality: "HI_RES",
|
||||
BitDepth: 24,
|
||||
SamplingRate: "192",
|
||||
BitDepth: exactBitDepth,
|
||||
SamplingRate: formatSamplingRate(exactSampling),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -438,6 +458,22 @@ func qobuzAudioProfile(resp map[string]any, requestedQuality int, ext string) pr
|
||||
}
|
||||
}
|
||||
|
||||
func firstNonNil(vals ...any) any {
|
||||
for _, v := range vals {
|
||||
if v != nil {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func formatSamplingRate(v float64) string {
|
||||
if v <= 0 {
|
||||
return ""
|
||||
}
|
||||
return strconv.FormatFloat(v, 'f', -1, 64)
|
||||
}
|
||||
|
||||
func (c *Client) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -371,6 +371,24 @@ func TestGetDownloadableUsesReturnedURLExtension(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestQobuzAudioProfileUsesExactReturnedQuality(t *testing.T) {
|
||||
profile := qobuzAudioProfile(map[string]any{
|
||||
"format_id": float64(7),
|
||||
"bit_depth": float64(24),
|
||||
"sampling_rate": float64(44.1),
|
||||
}, 4, "flac")
|
||||
if profile.BitDepth != 24 || profile.SamplingRate != "44.1" || profile.Quality != "HI_RES" {
|
||||
t.Fatalf("unexpected profile: %+v", profile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQobuzAudioProfileAvoidsGuessingHiResSampleRate(t *testing.T) {
|
||||
profile := qobuzAudioProfile(map[string]any{"format_id": float64(7)}, 4, "flac")
|
||||
if profile.BitDepth != 24 || profile.SamplingRate != "" || profile.Quality != "HI_RES" {
|
||||
t.Fatalf("unexpected profile: %+v", profile)
|
||||
}
|
||||
}
|
||||
|
||||
func qobuzSecretSig(requestTS, secret string) string {
|
||||
raw := "trackgetFileUrlformat_id27intentstreamtrack_id19512574" + requestTS + secret
|
||||
hash := md5.Sum([]byte(raw))
|
||||
|
||||
Reference in New Issue
Block a user