mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-08-02 09:08:35 +02:00
refactor(go): consolidate duplicated track maps, selectors, and small helpers
This commit is contained in:
@@ -333,7 +333,7 @@ func resolveCollectionShareURL(ext *loadedExtension, itemType string, track *Ext
|
||||
if url := urlFromExternalLinks(track.ExternalLinks, "album"); url != "" {
|
||||
return url
|
||||
}
|
||||
if url := templateShareURL(ext, "album", firstNonEmptyString(track.AlbumID, collectionID(*track, "album"), track.AlbumURL)); url != "" {
|
||||
if url := templateShareURL(ext, "album", firstNonEmptyTrimmed(track.AlbumID, collectionID(*track, "album"), track.AlbumURL)); url != "" {
|
||||
return url
|
||||
}
|
||||
return ""
|
||||
@@ -350,7 +350,7 @@ func resolveCollectionShareURL(ext *loadedExtension, itemType string, track *Ext
|
||||
if url := urlFromExternalLinks(track.ExternalLinks, "artist"); url != "" {
|
||||
return url
|
||||
}
|
||||
if url := templateShareURL(ext, "artist", firstNonEmptyString(track.ArtistID, collectionID(*track, "artist"))); url != "" {
|
||||
if url := templateShareURL(ext, "artist", firstNonEmptyTrimmed(track.ArtistID, collectionID(*track, "artist"))); url != "" {
|
||||
return url
|
||||
}
|
||||
return ""
|
||||
@@ -430,13 +430,3 @@ func stripProviderPrefix(id string) string {
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
func firstNonEmptyString(values ...string) string {
|
||||
for _, value := range values {
|
||||
trimmed := strings.TrimSpace(value)
|
||||
if trimmed != "" {
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -783,29 +783,7 @@ func CustomSearchWithExtensionJSONWithRequestID(extensionID, query string, optio
|
||||
|
||||
result := make([]map[string]any, len(tracks))
|
||||
for i, track := range tracks {
|
||||
result[i] = map[string]any{
|
||||
"id": track.ID,
|
||||
"name": track.Name,
|
||||
"artists": track.Artists,
|
||||
"album_name": track.AlbumName,
|
||||
"album_artist": track.AlbumArtist,
|
||||
"duration_ms": track.DurationMS,
|
||||
"images": track.ResolvedCoverURL(),
|
||||
"preview_url": track.PreviewURL,
|
||||
"release_date": track.ReleaseDate,
|
||||
"track_number": track.TrackNumber,
|
||||
"total_tracks": track.TotalTracks,
|
||||
"disc_number": track.DiscNumber,
|
||||
"total_discs": track.TotalDiscs,
|
||||
"isrc": track.ISRC,
|
||||
"provider_id": track.ProviderID,
|
||||
"item_type": track.ItemType,
|
||||
"album_type": track.AlbumType,
|
||||
"composer": track.Composer,
|
||||
"audio_quality": track.AudioQuality,
|
||||
"audio_modes": track.AudioModes,
|
||||
"explicit": track.Explicit,
|
||||
}
|
||||
result[i] = normalizeExtensionTrackMetadataMap(track, "", 0)
|
||||
}
|
||||
|
||||
return marshalJSONString(result)
|
||||
@@ -835,51 +813,13 @@ func HandleURLWithExtensionJSON(url string) (string, error) {
|
||||
}
|
||||
|
||||
if result.Track != nil {
|
||||
response["track"] = map[string]any{
|
||||
"id": result.Track.ID,
|
||||
"name": result.Track.Name,
|
||||
"artists": result.Track.Artists,
|
||||
"album_name": result.Track.AlbumName,
|
||||
"album_artist": result.Track.AlbumArtist,
|
||||
"duration_ms": result.Track.DurationMS,
|
||||
"images": result.Track.ResolvedCoverURL(),
|
||||
"preview_url": result.Track.PreviewURL,
|
||||
"release_date": result.Track.ReleaseDate,
|
||||
"track_number": result.Track.TrackNumber,
|
||||
"total_tracks": result.Track.TotalTracks,
|
||||
"disc_number": result.Track.DiscNumber,
|
||||
"total_discs": result.Track.TotalDiscs,
|
||||
"isrc": result.Track.ISRC,
|
||||
"provider_id": result.Track.ProviderID,
|
||||
"composer": result.Track.Composer,
|
||||
"explicit": result.Track.Explicit,
|
||||
}
|
||||
response["track"] = normalizeExtensionTrackMetadataMap(*result.Track, "", 0)
|
||||
}
|
||||
|
||||
if len(result.Tracks) > 0 {
|
||||
tracks := make([]map[string]any, len(result.Tracks))
|
||||
for i, track := range result.Tracks {
|
||||
tracks[i] = map[string]any{
|
||||
"id": track.ID,
|
||||
"name": track.Name,
|
||||
"artists": track.Artists,
|
||||
"album_name": track.AlbumName,
|
||||
"album_artist": track.AlbumArtist,
|
||||
"duration_ms": track.DurationMS,
|
||||
"images": track.ResolvedCoverURL(),
|
||||
"preview_url": track.PreviewURL,
|
||||
"release_date": track.ReleaseDate,
|
||||
"track_number": track.TrackNumber,
|
||||
"total_tracks": track.TotalTracks,
|
||||
"disc_number": track.DiscNumber,
|
||||
"total_discs": track.TotalDiscs,
|
||||
"isrc": track.ISRC,
|
||||
"provider_id": track.ProviderID,
|
||||
"item_type": track.ItemType,
|
||||
"album_type": track.AlbumType,
|
||||
"composer": track.Composer,
|
||||
"explicit": track.Explicit,
|
||||
}
|
||||
tracks[i] = normalizeExtensionTrackMetadataMap(track, "", 0)
|
||||
}
|
||||
response["tracks"] = tracks
|
||||
}
|
||||
@@ -958,26 +898,7 @@ func HandleURLWithExtensionJSON(url string) (string, error) {
|
||||
if len(result.Artist.TopTracks) > 0 {
|
||||
topTracks := make([]map[string]any, len(result.Artist.TopTracks))
|
||||
for i, track := range result.Artist.TopTracks {
|
||||
topTracks[i] = map[string]any{
|
||||
"id": track.ID,
|
||||
"name": track.Name,
|
||||
"artists": track.Artists,
|
||||
"album_name": track.AlbumName,
|
||||
"album_artist": track.AlbumArtist,
|
||||
"duration_ms": track.DurationMS,
|
||||
"images": track.ResolvedCoverURL(),
|
||||
"preview_url": track.PreviewURL,
|
||||
"release_date": track.ReleaseDate,
|
||||
"track_number": track.TrackNumber,
|
||||
"total_tracks": track.TotalTracks,
|
||||
"disc_number": track.DiscNumber,
|
||||
"total_discs": track.TotalDiscs,
|
||||
"isrc": track.ISRC,
|
||||
"provider_id": track.ProviderID,
|
||||
"spotify_id": track.SpotifyID,
|
||||
"composer": track.Composer,
|
||||
"explicit": track.Explicit,
|
||||
}
|
||||
topTracks[i] = normalizeExtensionTrackMetadataMap(track, "", 0)
|
||||
}
|
||||
artistResponse["top_tracks"] = topTracks
|
||||
}
|
||||
|
||||
@@ -879,7 +879,7 @@ func DownloadWithExtensionFallback(req DownloadRequest) (*DownloadResponse, erro
|
||||
return &DownloadResponse{
|
||||
Success: false,
|
||||
Error: "Download failed: " + lastErr.Error(),
|
||||
ErrorType: firstNonEmptyString(lastErrType, "extension_error"),
|
||||
ErrorType: firstNonEmptyTrimmed(lastErrType, "extension_error"),
|
||||
RetryAfterSeconds: lastRetryAfterSeconds,
|
||||
Service: req.Source,
|
||||
}, nil
|
||||
@@ -1013,7 +1013,7 @@ func DownloadWithExtensionFallback(req DownloadRequest) (*DownloadResponse, erro
|
||||
}
|
||||
|
||||
if lastErr != nil {
|
||||
errorType := firstNonEmptyString(lastErrType, classifyDownloadErrorType(lastErr.Error()))
|
||||
errorType := firstNonEmptyTrimmed(lastErrType, classifyDownloadErrorType(lastErr.Error()))
|
||||
if errorType == "unknown" {
|
||||
errorType = "not_found"
|
||||
}
|
||||
|
||||
@@ -151,11 +151,15 @@ func invokeExtensionMethod(vm *goja.Runtime, method string, args ...any) (goja.V
|
||||
return goja.Null(), nil
|
||||
}
|
||||
|
||||
return callable(extensionObject, gojaArgumentValues(vm, args)...)
|
||||
}
|
||||
|
||||
func gojaArgumentValues(vm *goja.Runtime, args []any) []goja.Value {
|
||||
values := make([]goja.Value, len(args))
|
||||
for i, arg := range args {
|
||||
values[i] = gojaArgumentValue(vm, arg)
|
||||
}
|
||||
return callable(extensionObject, values...)
|
||||
return values
|
||||
}
|
||||
|
||||
func gojaArgumentValue(vm *goja.Runtime, value any) goja.Value {
|
||||
@@ -214,11 +218,7 @@ func invokeExtensionOrGlobal(vm *goja.Runtime, method string, args ...any) (goja
|
||||
if !ok {
|
||||
return goja.Null(), nil
|
||||
}
|
||||
values := make([]goja.Value, len(args))
|
||||
for i, arg := range args {
|
||||
values[i] = gojaArgumentValue(vm, arg)
|
||||
}
|
||||
return callable(vm.GlobalObject(), values...)
|
||||
return callable(vm.GlobalObject(), gojaArgumentValues(vm, args)...)
|
||||
}
|
||||
|
||||
func extensionTrackInput(track *ExtTrackMetadata) map[string]any {
|
||||
|
||||
@@ -77,7 +77,7 @@ func (e *repoExtension) getMinAppVersion() string {
|
||||
}
|
||||
|
||||
func (e *repoExtension) getRawSHA256() string {
|
||||
return firstNonEmpty(e.SHA256, e.ChecksumSHA256, e.ChecksumAlt)
|
||||
return firstNonEmptyTrimmed(e.SHA256, e.ChecksumSHA256, e.ChecksumAlt)
|
||||
}
|
||||
|
||||
func (e *repoExtension) getSHA256() string {
|
||||
@@ -443,15 +443,6 @@ func (s *extensionRepo) downloadExtension(extensionID string, destPath string) e
|
||||
|
||||
const maxExtensionPackageBytes int64 = 64 * 1024 * 1024
|
||||
|
||||
func firstNonEmpty(values ...string) string {
|
||||
for _, value := range values {
|
||||
if strings.TrimSpace(value) != "" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func normalizeSHA256(value string) string {
|
||||
normalized := strings.ToLower(strings.TrimSpace(value))
|
||||
normalized = strings.TrimPrefix(normalized, "sha256:")
|
||||
|
||||
@@ -508,10 +508,6 @@ func (c *LyricsClient) FetchLyricsWithMetadata(artist, track string) (*LyricsRes
|
||||
return c.parseLRCLibResponse(&lrcResp), nil
|
||||
}
|
||||
|
||||
func (c *LyricsClient) FetchLyricsFromLRCLibSearch(query string, durationSec float64) (*LyricsResponse, error) {
|
||||
return c.fetchLyricsFromLRCLibSearch(query, "", "", durationSec)
|
||||
}
|
||||
|
||||
func (c *LyricsClient) fetchLyricsFromLRCLibSearch(query, trackName, artistName string, durationSec float64) (*LyricsResponse, error) {
|
||||
params := url.Values{}
|
||||
params.Set("q", query)
|
||||
|
||||
@@ -99,36 +99,15 @@ func appleMusicSearchResultMatches(result appleMusicSearchResult, trackName, art
|
||||
}
|
||||
|
||||
func selectBestAppleMusicSearchResult(results []appleMusicSearchResult, trackName, artistName string, durationSec float64) *appleMusicSearchResult {
|
||||
if len(results) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
bestIndex := -1
|
||||
bestScore := -1
|
||||
for i := range results {
|
||||
best := selectBestLyricsCandidate(len(results), trackName, artistName, durationSec, func(i int) (string, string, float64, bool) {
|
||||
result := &results[i]
|
||||
if !appleMusicSearchResultMatches(*result, trackName, artistName, durationSec) {
|
||||
continue
|
||||
}
|
||||
|
||||
score := scoreLyricsSearchCandidate(
|
||||
result.SongName,
|
||||
result.ArtistName,
|
||||
float64(result.Duration)/1000.0,
|
||||
trackName,
|
||||
artistName,
|
||||
durationSec,
|
||||
)
|
||||
if score > bestScore {
|
||||
bestScore = score
|
||||
bestIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
if bestIndex < 0 {
|
||||
ok := appleMusicSearchResultMatches(*result, trackName, artistName, durationSec)
|
||||
return result.SongName, result.ArtistName, float64(result.Duration) / 1000.0, ok
|
||||
})
|
||||
if best < 0 {
|
||||
return nil
|
||||
}
|
||||
return &results[bestIndex]
|
||||
return &results[best]
|
||||
}
|
||||
|
||||
func (c *AppleMusicClient) getAppleMusicToken() (string, error) {
|
||||
|
||||
@@ -114,9 +114,7 @@ func (c *NeteaseClient) SearchSong(trackName, artistName string) (int64, error)
|
||||
}
|
||||
|
||||
func selectBestNeteaseSearchResult(results []neteaseSearchSong, trackName, artistName string) *neteaseSearchSong {
|
||||
bestIndex := -1
|
||||
bestScore := -1
|
||||
for i := range results {
|
||||
best := selectBestLyricsCandidate(len(results), trackName, artistName, 0, func(i int) (string, string, float64, bool) {
|
||||
result := &results[i]
|
||||
artists := make([]string, 0, len(result.Artists))
|
||||
for _, artist := range result.Artists {
|
||||
@@ -125,20 +123,14 @@ func selectBestNeteaseSearchResult(results []neteaseSearchSong, trackName, artis
|
||||
}
|
||||
}
|
||||
candidateArtist := strings.Join(artists, ", ")
|
||||
if !lyricsSearchTitlesMatch(result.Name, trackName, false) ||
|
||||
!lyricsSearchArtistsMatch(candidateArtist, artistName) {
|
||||
continue
|
||||
}
|
||||
score := scoreLyricsSearchCandidate(result.Name, candidateArtist, 0, trackName, artistName, 0)
|
||||
if score > bestScore {
|
||||
bestIndex = i
|
||||
bestScore = score
|
||||
}
|
||||
}
|
||||
if bestIndex < 0 {
|
||||
ok := lyricsSearchTitlesMatch(result.Name, trackName, false) &&
|
||||
lyricsSearchArtistsMatch(candidateArtist, artistName)
|
||||
return result.Name, candidateArtist, 0, ok
|
||||
})
|
||||
if best < 0 {
|
||||
return nil
|
||||
}
|
||||
return &results[bestIndex]
|
||||
return &results[best]
|
||||
}
|
||||
|
||||
func (c *NeteaseClient) FetchLyricsByID(songID int64, includeTranslation, includeRomanization bool) (string, error) {
|
||||
|
||||
@@ -265,31 +265,39 @@ func (c *SpotifyLyricsClient) SearchSong(trackName, artistName string, durationS
|
||||
return strings.TrimSpace(best.TrackID), nil
|
||||
}
|
||||
|
||||
func selectBestSpotifyLyricsSearchResult(results []spotifyLyricsSearchResult, trackName, artistName string, durationSec float64) *spotifyLyricsSearchResult {
|
||||
if len(results) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// selectBestLyricsCandidate returns the index of the highest-scoring candidate
|
||||
// whose provider-specific gate passes; candidate returns
|
||||
// (name, artist, durationSec, gatePassed). Returns -1 when nothing matches.
|
||||
func selectBestLyricsCandidate(n int, trackName, artistName string, durationSec float64, candidate func(i int) (string, string, float64, bool)) int {
|
||||
bestIndex := -1
|
||||
bestScore := -1
|
||||
for i := range results {
|
||||
result := &results[i]
|
||||
candidateDuration := parseClockDuration(result.Duration)
|
||||
if !lyricsSearchTitlesMatch(result.Name, trackName, false) ||
|
||||
!lyricsSearchArtistsMatch(result.ArtistName, artistName) ||
|
||||
!lyricsSearchDurationMatches(candidateDuration, durationSec) {
|
||||
for i := 0; i < n; i++ {
|
||||
name, artist, duration, ok := candidate(i)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
score := scoreLyricsSearchCandidate(result.Name, result.ArtistName, candidateDuration, trackName, artistName, durationSec)
|
||||
score := scoreLyricsSearchCandidate(name, artist, duration, trackName, artistName, durationSec)
|
||||
if score > bestScore {
|
||||
bestIndex = i
|
||||
bestScore = score
|
||||
}
|
||||
}
|
||||
if bestIndex < 0 {
|
||||
return bestIndex
|
||||
}
|
||||
|
||||
func selectBestSpotifyLyricsSearchResult(results []spotifyLyricsSearchResult, trackName, artistName string, durationSec float64) *spotifyLyricsSearchResult {
|
||||
best := selectBestLyricsCandidate(len(results), trackName, artistName, durationSec, func(i int) (string, string, float64, bool) {
|
||||
result := &results[i]
|
||||
duration := parseClockDuration(result.Duration)
|
||||
ok := lyricsSearchTitlesMatch(result.Name, trackName, false) &&
|
||||
lyricsSearchArtistsMatch(result.ArtistName, artistName) &&
|
||||
lyricsSearchDurationMatches(duration, durationSec)
|
||||
return result.Name, result.ArtistName, duration, ok
|
||||
})
|
||||
if best < 0 {
|
||||
return nil
|
||||
}
|
||||
return &results[bestIndex]
|
||||
return &results[best]
|
||||
}
|
||||
|
||||
func (c *SpotifyLyricsClient) FetchLyricsByID(trackID string) (*LyricsResponse, error) {
|
||||
@@ -383,32 +391,20 @@ func (c *YouTubeLyricsClient) SearchSong(trackName, artistName string, durationS
|
||||
}
|
||||
|
||||
func selectBestYouTubeLyricsSearchResult(results []youtubeLyricsSearchResult, trackName, artistName string, durationSec float64) *youtubeLyricsSearchResult {
|
||||
if len(results) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
bestIndex := -1
|
||||
bestScore := -1
|
||||
for i := range results {
|
||||
best := selectBestLyricsCandidate(len(results), trackName, artistName, durationSec, func(i int) (string, string, float64, bool) {
|
||||
result := &results[i]
|
||||
candidateDuration := parseClockDuration(result.Duration)
|
||||
duration := parseClockDuration(result.Duration)
|
||||
artistMatches := lyricsSearchArtistsMatch(result.Author, artistName) ||
|
||||
lyricsSearchArtistAppearsInTitle(result.Title, artistName)
|
||||
if !lyricsSearchTitlesMatch(result.Title, trackName, true) ||
|
||||
!artistMatches ||
|
||||
!lyricsSearchDurationMatches(candidateDuration, durationSec) {
|
||||
continue
|
||||
}
|
||||
score := scoreLyricsSearchCandidate(result.Title, result.Author, candidateDuration, trackName, artistName, durationSec)
|
||||
if score > bestScore {
|
||||
bestIndex = i
|
||||
bestScore = score
|
||||
}
|
||||
}
|
||||
if bestIndex < 0 {
|
||||
ok := lyricsSearchTitlesMatch(result.Title, trackName, true) &&
|
||||
artistMatches &&
|
||||
lyricsSearchDurationMatches(duration, durationSec)
|
||||
return result.Title, result.Author, duration, ok
|
||||
})
|
||||
if best < 0 {
|
||||
return nil
|
||||
}
|
||||
return &results[bestIndex]
|
||||
return &results[best]
|
||||
}
|
||||
|
||||
func (c *YouTubeLyricsClient) FetchLyrics(trackName, artistName string, durationSec float64) (*LyricsResponse, error) {
|
||||
@@ -451,29 +447,17 @@ func (c *KugouLyricsClient) SearchSong(trackName, artistName string, durationSec
|
||||
}
|
||||
|
||||
func selectBestKugouLyricsSearchResult(results []kugouLyricsSearchResult, trackName, artistName string, durationSec float64) *kugouLyricsSearchResult {
|
||||
if len(results) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
bestIndex := -1
|
||||
bestScore := -1
|
||||
for i := range results {
|
||||
best := selectBestLyricsCandidate(len(results), trackName, artistName, durationSec, func(i int) (string, string, float64, bool) {
|
||||
result := &results[i]
|
||||
if !lyricsSearchTitlesMatch(result.Title, trackName, false) ||
|
||||
!lyricsSearchArtistsMatch(result.Artist, artistName) ||
|
||||
!lyricsSearchDurationMatches(result.Duration, durationSec) {
|
||||
continue
|
||||
}
|
||||
score := scoreLyricsSearchCandidate(result.Title, result.Artist, result.Duration, trackName, artistName, durationSec)
|
||||
if score > bestScore {
|
||||
bestIndex = i
|
||||
bestScore = score
|
||||
}
|
||||
}
|
||||
if bestIndex < 0 {
|
||||
ok := lyricsSearchTitlesMatch(result.Title, trackName, false) &&
|
||||
lyricsSearchArtistsMatch(result.Artist, artistName) &&
|
||||
lyricsSearchDurationMatches(result.Duration, durationSec)
|
||||
return result.Title, result.Artist, result.Duration, ok
|
||||
})
|
||||
if best < 0 {
|
||||
return nil
|
||||
}
|
||||
return &results[bestIndex]
|
||||
return &results[best]
|
||||
}
|
||||
|
||||
func (c *KugouLyricsClient) FetchLyrics(trackName, artistName string, durationSec float64) (*LyricsResponse, error) {
|
||||
|
||||
@@ -123,9 +123,9 @@ func TestLyricsCacheParsingAndLRCLibClient(t *testing.T) {
|
||||
if err != nil || got.SyncType != "LINE_SYNCED" || len(got.Lines) != 1 {
|
||||
t.Fatalf("FetchLyricsWithMetadata = %#v/%v", got, err)
|
||||
}
|
||||
search, err := client.FetchLyricsFromLRCLibSearch("Artist Song", 180)
|
||||
search, err := client.fetchLyricsFromLRCLibSearch("Artist Song", "", "", 180)
|
||||
if err != nil || len(search.Lines) == 0 {
|
||||
t.Fatalf("FetchLyricsFromLRCLibSearch = %#v/%v", search, err)
|
||||
t.Fatalf("fetchLyricsFromLRCLibSearch = %#v/%v", search, err)
|
||||
}
|
||||
if best := client.findBestLRCLibSearchMatch(
|
||||
[]LRCLibResponse{
|
||||
|
||||
+17
-41
@@ -1661,30 +1661,27 @@ type AudioQuality struct {
|
||||
Codec string `json:"codec,omitempty"`
|
||||
}
|
||||
|
||||
func flacAudioQualityFromStreamInfo(streamInfo []byte) AudioQuality {
|
||||
bitDepth, sampleRate, totalSamples := parseFLACStreamInfoQuality(streamInfo)
|
||||
duration := 0
|
||||
if sampleRate > 0 && totalSamples > 0 {
|
||||
duration = int(totalSamples / int64(sampleRate))
|
||||
}
|
||||
return AudioQuality{
|
||||
BitDepth: bitDepth,
|
||||
SampleRate: sampleRate,
|
||||
TotalSamples: totalSamples,
|
||||
Duration: duration,
|
||||
Codec: "flac",
|
||||
}
|
||||
}
|
||||
|
||||
func audioQualityFromParsedFlac(f *flac.File) (AudioQuality, error) {
|
||||
for _, meta := range f.Meta {
|
||||
if meta.Type != flac.StreamInfo || len(meta.Data) < 18 {
|
||||
continue
|
||||
}
|
||||
streamInfo := meta.Data
|
||||
sampleRate := (int(streamInfo[10]) << 12) | (int(streamInfo[11]) << 4) | (int(streamInfo[12]) >> 4)
|
||||
bitsPerSample := ((int(streamInfo[12]) & 0x01) << 4) | (int(streamInfo[13]) >> 4) + 1
|
||||
totalSamples := int64(streamInfo[13]&0x0F)<<32 |
|
||||
int64(streamInfo[14])<<24 |
|
||||
int64(streamInfo[15])<<16 |
|
||||
int64(streamInfo[16])<<8 |
|
||||
int64(streamInfo[17])
|
||||
duration := 0
|
||||
if sampleRate > 0 && totalSamples > 0 {
|
||||
duration = int(totalSamples / int64(sampleRate))
|
||||
}
|
||||
return AudioQuality{
|
||||
BitDepth: bitsPerSample,
|
||||
SampleRate: sampleRate,
|
||||
TotalSamples: totalSamples,
|
||||
Duration: duration,
|
||||
Codec: "flac",
|
||||
}, nil
|
||||
return flacAudioQualityFromStreamInfo(meta.Data), nil
|
||||
}
|
||||
return AudioQuality{}, fmt.Errorf("FLAC STREAMINFO block not found")
|
||||
}
|
||||
@@ -1717,28 +1714,7 @@ func GetAudioQuality(filePath string) (AudioQuality, error) {
|
||||
return AudioQuality{}, fmt.Errorf("failed to read STREAMINFO: %w", err)
|
||||
}
|
||||
|
||||
sampleRate := (int(streamInfo[10]) << 12) | (int(streamInfo[11]) << 4) | (int(streamInfo[12]) >> 4)
|
||||
|
||||
bitsPerSample := ((int(streamInfo[12]) & 0x01) << 4) | (int(streamInfo[13]) >> 4) + 1
|
||||
|
||||
totalSamples := int64(streamInfo[13]&0x0F)<<32 |
|
||||
int64(streamInfo[14])<<24 |
|
||||
int64(streamInfo[15])<<16 |
|
||||
int64(streamInfo[16])<<8 |
|
||||
int64(streamInfo[17])
|
||||
|
||||
duration := 0
|
||||
if sampleRate > 0 && totalSamples > 0 {
|
||||
duration = int(totalSamples / int64(sampleRate))
|
||||
}
|
||||
|
||||
return AudioQuality{
|
||||
BitDepth: bitsPerSample,
|
||||
SampleRate: sampleRate,
|
||||
TotalSamples: totalSamples,
|
||||
Duration: duration,
|
||||
Codec: "flac",
|
||||
}, nil
|
||||
return flacAudioQualityFromStreamInfo(streamInfo), nil
|
||||
}
|
||||
|
||||
file.Seek(0, 0)
|
||||
|
||||
Reference in New Issue
Block a user