Compare commits

...

2 Commits

Author SHA1 Message Date
64ba7f9006 Merge pull request 'Fix CORS' (#3) from prochains-changements into main
All checks were successful
Build and Push Docker Images / Build Backend Image (push) Successful in 12m50s
Build and Push Docker Images / Build Frontend Image (push) Successful in 7m10s
Reviewed-on: #3
2025-12-23 14:34:05 +01:00
cc2f1d0051 Fix CORS 2025-12-23 14:33:25 +01:00
6 changed files with 59 additions and 25 deletions

View File

@@ -5,7 +5,9 @@ POSTGRES_PASSWORD=audio_password
POSTGRES_DB=audio_classifier
# Backend API
CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
# Use "*" to allow all origins (recommended for development/local deployment)
# Or specify comma-separated URLs for production: http://yourdomain.com,https://yourdomain.com
CORS_ORIGINS=*
API_HOST=0.0.0.0
API_PORT=8000
@@ -16,4 +18,5 @@ ESSENTIA_MODELS_PATH=/app/models
AUDIO_LIBRARY_PATH=/path/to/your/audio/library
# Frontend
NEXT_PUBLIC_API_URL=http://localhost:8000
# API URL accessed by the browser (use port 8001 since backend is mapped to 8001)
NEXT_PUBLIC_API_URL=http://localhost:8001

View File

@@ -10,7 +10,8 @@ class Settings(BaseSettings):
DATABASE_URL: str = "postgresql://audio_user:audio_password@localhost:5432/audio_classifier"
# API Configuration
CORS_ORIGINS: str = "http://localhost:3000,http://127.0.0.1:3000"
# Comma-separated list of allowed origins, or use "*" to allow all
CORS_ORIGINS: str = "*"
API_HOST: str = "0.0.0.0"
API_PORT: int = 8000
@@ -33,7 +34,13 @@ class Settings(BaseSettings):
@property
def cors_origins_list(self) -> List[str]:
"""Parse CORS origins string to list."""
"""Parse CORS origins string to list.
If CORS_ORIGINS is "*", allow all origins.
Otherwise, parse comma-separated list.
"""
if self.CORS_ORIGINS.strip() == "*":
return ["*"]
return [origin.strip() for origin in self.CORS_ORIGINS.split(",")]

View File

@@ -31,7 +31,7 @@ services:
condition: service_healthy
environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-audio_user}:${POSTGRES_PASSWORD:-audio_password}@postgres:5432/${POSTGRES_DB:-audio_classifier}
CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000}
CORS_ORIGINS: ${CORS_ORIGINS:-*}
ANALYSIS_USE_CLAP: ${ANALYSIS_USE_CLAP:-false}
ANALYSIS_NUM_WORKERS: ${ANALYSIS_NUM_WORKERS:-4}
ESSENTIA_MODELS_PATH: /app/models

View File

@@ -26,7 +26,7 @@ services:
condition: service_healthy
environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-audio_user}:${POSTGRES_PASSWORD:-audio_password}@postgres:5432/${POSTGRES_DB:-audio_classifier}
CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000}
CORS_ORIGINS: ${CORS_ORIGINS:-*}
ANALYSIS_USE_CLAP: ${ANALYSIS_USE_CLAP:-false}
ANALYSIS_NUM_WORKERS: ${ANALYSIS_NUM_WORKERS:-4}
ESSENTIA_MODELS_PATH: /app/models

View File

@@ -52,6 +52,7 @@ export default function Home() {
const [filters, setFilters] = useState<FilterParams>({})
const [page, setPage] = useState(0)
const [currentTrack, setCurrentTrack] = useState<Track | null>(null)
const [isPlaying, setIsPlaying] = useState(false)
const [searchQuery, setSearchQuery] = useState("")
const [isScanning, setIsScanning] = useState(false)
const [scanStatus, setScanStatus] = useState<string>("")
@@ -233,10 +234,19 @@ export default function Home() {
<div className="flex items-center gap-4">
{/* Play button */}
<button
onClick={() => setCurrentTrack(track)}
onClick={() => {
if (currentTrack?.id === track.id) {
// Toggle play/pause for current track
setIsPlaying(!isPlaying)
} else {
// Switch to new track and start playing
setCurrentTrack(track)
setIsPlaying(true)
}
}}
className="flex-shrink-0 w-12 h-12 flex items-center justify-center bg-orange-500 hover:bg-orange-600 rounded-full transition-colors shadow-sm"
>
{currentTrack?.id === track.id ? (
{currentTrack?.id === track.id && isPlaying ? (
<svg className="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/>
</svg>
@@ -347,7 +357,11 @@ export default function Home() {
{/* Fixed Audio Player at bottom */}
<div className="fixed bottom-0 left-0 right-0 z-50">
<AudioPlayer track={currentTrack} />
<AudioPlayer
track={currentTrack}
isPlaying={isPlaying}
onPlayingChange={setIsPlaying}
/>
</div>
</div>
)

View File

@@ -5,10 +5,11 @@ import type { Track } from "@/lib/types"
interface AudioPlayerProps {
track: Track | null
isPlaying: boolean
onPlayingChange: (playing: boolean) => void
}
export default function AudioPlayer({ track }: AudioPlayerProps) {
const [isPlaying, setIsPlaying] = useState(false)
export default function AudioPlayer({ track, isPlaying, onPlayingChange }: AudioPlayerProps) {
const [currentTime, setCurrentTime] = useState(0)
const [duration, setDuration] = useState(0)
const [volume, setVolume] = useState(1)
@@ -22,7 +23,7 @@ export default function AudioPlayer({ track }: AudioPlayerProps) {
// Load audio and waveform when track changes
useEffect(() => {
if (!track) {
setIsPlaying(false)
onPlayingChange(false)
setCurrentTime(0)
setWaveformPeaks([])
return
@@ -33,14 +34,14 @@ export default function AudioPlayer({ track }: AudioPlayerProps) {
if (audioRef.current) {
audioRef.current.load()
// Autoplay when track loads
audioRef.current.play().then(() => {
setIsPlaying(true)
}).catch((error: unknown) => {
// Autoplay when track loads if isPlaying is true
if (isPlaying) {
audioRef.current.play().catch((error: unknown) => {
console.error("Autoplay failed:", error)
setIsPlaying(false)
onPlayingChange(false)
})
}
}
}, [track?.id])
// Update current time as audio plays
@@ -54,7 +55,7 @@ export default function AudioPlayer({ track }: AudioPlayerProps) {
setDuration(audio.duration)
}
}
const handleEnded = () => setIsPlaying(false)
const handleEnded = () => onPlayingChange(false)
audio.addEventListener("timeupdate", updateTime)
audio.addEventListener("loadedmetadata", updateDuration)
@@ -91,15 +92,24 @@ export default function AudioPlayer({ track }: AudioPlayerProps) {
}
}
const togglePlay = () => {
if (!audioRef.current || !track) return
// Sync playing state with audio element
useEffect(() => {
const audio = audioRef.current
if (!audio) return
if (isPlaying) {
audioRef.current.pause()
audio.play().catch((error: unknown) => {
console.error("Play failed:", error)
onPlayingChange(false)
})
} else {
audioRef.current.play()
audio.pause()
}
setIsPlaying(!isPlaying)
}, [isPlaying, onPlayingChange])
const togglePlay = () => {
if (!audioRef.current || !track) return
onPlayingChange(!isPlaying)
}
const handleVolumeChange = (e: React.ChangeEvent<HTMLInputElement>) => {