112 lines
2.6 KiB
Go
112 lines
2.6 KiB
Go
package services
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/dhowden/tag"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// AudioMetadata represents extracted audio metadata
|
|
type AudioMetadata struct {
|
|
Title string
|
|
Artist string
|
|
Album string
|
|
Genre string
|
|
Year int
|
|
Track int
|
|
Duration float64 // in seconds
|
|
Bitrate int
|
|
Format string
|
|
}
|
|
|
|
// MetadataService extracts metadata from audio files
|
|
type MetadataService struct {
|
|
logger *zap.Logger
|
|
}
|
|
|
|
// NewMetadataService creates a new metadata service
|
|
func NewMetadataService(logger *zap.Logger) *MetadataService {
|
|
return &MetadataService{
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// ExtractMetadata extracts metadata from an audio file
|
|
func (ms *MetadataService) ExtractMetadata(filePath string) (*AudioMetadata, error) {
|
|
// Open file
|
|
file, err := os.Open(filePath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open file for metadata extraction: %w", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
// Read metadata from file
|
|
metadata, err := tag.ReadFrom(file)
|
|
if err != nil {
|
|
// If metadata can't be read, return default metadata
|
|
ms.logger.Warn("Failed to extract metadata, using defaults",
|
|
zap.Error(err),
|
|
zap.String("file_path", filePath),
|
|
)
|
|
return ms.getDefaultMetadata(filePath), nil
|
|
}
|
|
|
|
// Extract metadata
|
|
trackNum, _ := metadata.Track()
|
|
result := &AudioMetadata{
|
|
Title: metadata.Title(),
|
|
Artist: metadata.Artist(),
|
|
Album: metadata.Album(),
|
|
Genre: metadata.Genre(),
|
|
Year: metadata.Year(),
|
|
Track: trackNum,
|
|
Format: filepath.Ext(filePath),
|
|
}
|
|
|
|
// Duration and bitrate would typically be extracted using ffprobe or similar
|
|
// For now, we'll leave these as 0
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// getDefaultMetadata returns default metadata based on filename
|
|
func (ms *MetadataService) getDefaultMetadata(filePath string) *AudioMetadata {
|
|
filename := filepath.Base(filePath)
|
|
ext := filepath.Ext(filename)
|
|
baseName := filename[:len(filename)-len(ext)]
|
|
|
|
// Try to parse "Artist - Title" pattern
|
|
var artist, title string
|
|
if len(baseName) > 3 && baseName[2:4] == " - " {
|
|
parts := baseName[:3] // This won't work, need proper parsing
|
|
artist = string(parts)
|
|
title = baseName[3:]
|
|
} else {
|
|
title = baseName
|
|
artist = "Unknown"
|
|
}
|
|
|
|
return &AudioMetadata{
|
|
Title: title,
|
|
Artist: artist,
|
|
Album: "",
|
|
Genre: "",
|
|
Year: 0,
|
|
Track: 0,
|
|
Format: ext,
|
|
}
|
|
}
|
|
|
|
// ValidateMetadata validates extracted metadata
|
|
func (ms *MetadataService) ValidateMetadata(metadata *AudioMetadata) error {
|
|
if metadata.Title == "" {
|
|
return fmt.Errorf("title is required")
|
|
}
|
|
if metadata.Artist == "" {
|
|
return fmt.Errorf("artist is required")
|
|
}
|
|
return nil
|
|
}
|