Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enhance audio file processing with terminal width support #400

Merged
merged 1 commit into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ require (
github.com/tphakala/go-tflite v0.0.0-20241022031318-2dad4328ec9e
golang.org/x/crypto v0.32.0
golang.org/x/net v0.34.0
golang.org/x/term v0.28.0
golang.org/x/text v0.21.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.5.6
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
Expand Down
79 changes: 71 additions & 8 deletions internal/analysis/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"path/filepath"
"time"

"golang.org/x/term"

"github.com/tphakala/birdnet-go/internal/birdnet"
"github.com/tphakala/birdnet-go/internal/conf"
"github.com/tphakala/birdnet-go/internal/datastore"
Expand Down Expand Up @@ -85,6 +87,46 @@ func validateAudioFile(filePath string) error {
return nil
}

// truncateString truncates a string to fit within maxLen, adding "..." if truncated
func truncateString(s string, maxLen int) string {
if len(s) <= maxLen {
return s
}
if maxLen <= 3 {
return s[:maxLen]
}
return s[:maxLen-3] + "..."
}

// formatProgressLine formats the progress line to fit within the terminal width
func formatProgressLine(filename string, duration time.Duration, chunkCount, totalChunks int, avgRate float64, timeRemaining string, termWidth int) string {
// Base format without filename (to calculate remaining space)
baseFormat := fmt.Sprintf(" [%s] | \033[33m🔍 Analyzing chunk %d/%d\033[0m | \033[36m%.1f chunks/sec\033[0m %s",
duration.Round(time.Second),
chunkCount,
totalChunks,
avgRate,
timeRemaining)

// Calculate available space for filename
// Account for emoji (📄) and color codes
const colorCodesLen = 45 // Approximate length of all color codes
availableSpace := termWidth - len(baseFormat) - colorCodesLen

// Ensure minimum width
if availableSpace < 10 {
availableSpace = 10
}

// Truncate filename if needed
truncatedFilename := truncateString(filename, availableSpace)

// Return the complete formatted line
return fmt.Sprintf("\r\033[K\033[37m📄 %s%s",
truncatedFilename,
baseFormat)
}

// processAudioFile processes the audio file and returns the notes.
func processAudioFile(settings *conf.Settings, audioInfo *myaudio.AudioInfo) ([]datastore.Note, error) {
// Calculate total chunks
Expand All @@ -104,7 +146,7 @@ func processAudioFile(settings *conf.Settings, audioInfo *myaudio.AudioInfo) ([]
duration := time.Duration(float64(audioInfo.TotalSamples) / float64(audioInfo.SampleRate) * float64(time.Second))

// Get filename and truncate if necessary
filename := truncateFilename(settings.Input.Path)
filename := filepath.Base(settings.Input.Path)

startTime := time.Now()
chunkCount := 1
Expand Down Expand Up @@ -203,13 +245,22 @@ func processAudioFile(settings *conf.Settings, audioInfo *myaudio.AudioInfo) ([]
lastChunkCount = chunkCount
lastProgressUpdate = currentTime

fmt.Printf("\r\033[K\033[37m📄 %s [%s]\033[0m | \033[33m🔍 Analyzing chunk %d/%d\033[0m | \033[36m%.1f chunks/sec\033[0m %s",
// Get terminal width
width, _, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil {
width = 80 // Default to 80 columns if we can't get terminal width
}

// Format and print the progress line
fmt.Print(formatProgressLine(
filename,
duration.Round(time.Second),
duration,
chunkCount,
totalChunks,
avgRate,
birdnet.EstimateTimeRemaining(startTime, chunkCount, totalChunks))
birdnet.EstimateTimeRemaining(startTime, chunkCount, totalChunks),
width,
))
}
}
}()
Expand Down Expand Up @@ -303,11 +354,23 @@ func processAudioFile(settings *conf.Settings, audioInfo *myaudio.AudioInfo) ([]
totalTime := time.Since(startTime)
avgChunksPerSec := float64(totalChunks) / totalTime.Seconds()

fmt.Printf("\r\033[K\033[37m📄 %s [%s]\033[0m | \033[32m✅ Analysis completed in %s\033[0m | \033[36m%.1f chunks/sec avg\033[0m\n",
// Get terminal width for final status line
width, _, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil {
width = 80 // Default to 80 columns if we can't get terminal width
}

// Format and print the final status line
fmt.Print(formatProgressLine(
filename,
duration.Round(time.Second),
birdnet.FormatDuration(totalTime),
avgChunksPerSec)
duration,
totalChunks,
totalChunks,
avgChunksPerSec,
fmt.Sprintf("in %s", birdnet.FormatDuration(totalTime)),
width,
))
fmt.Println() // Add newline after completion

return allNotes, nil
}
Expand Down
Loading