Files
icecast-ripper/internal/streamchecker/streamchecker.go
Dmitry Andreev b5f23a50b7
Some checks failed
CodeQL / Analyze (go) (push) Has been cancelled
Docker / build (push) Has been cancelled
golangci-lint / lint (push) Has been cancelled
Integrate MP3 duration extraction and silence handling (#6)
* feat: integrate MP3 duration extraction and silence handling

- Added a new dependency on github.com/tcolgate/mp3 for MP3 frame decoding.
- Implemented actual MP3 duration retrieval in the scanRecordings function, falling back to an estimation if retrieval fails.
- Introduced a silent frame asset for generating silence in audio streams.
- Created a silence reader to provide a continuous stream of silent frames.
- Added necessary documentation and licensing for the new MP3 package.
- Updated .gitignore to exclude MP3 files except for the internal data directory.

* feat: update README and improve application configuration and logging

* refactor: remove unused GenerateFileHash function and improve resource cleanup in MP3 and recorder modules
2025-04-13 15:56:22 +03:00

84 lines
1.9 KiB
Go

package streamchecker
import (
"context"
"fmt"
"log/slog"
"net/http"
"time"
)
type Checker struct {
streamURL string
client *http.Client
userAgent string
}
// Option represents a functional option for configuring the Checker
type Option func(*Checker)
// WithUserAgent sets a custom User-Agent header
func WithUserAgent(userAgent string) Option {
return func(c *Checker) {
c.userAgent = userAgent
}
}
// New creates a new stream checker with sensible defaults
func New(streamURL string, opts ...Option) *Checker {
c := &Checker{
streamURL: streamURL,
client: &http.Client{
Timeout: 10 * time.Second,
},
}
// Apply any provided options
for _, opt := range opts {
opt(c)
}
return c
}
// IsLive checks if the stream is currently broadcasting
func (c *Checker) IsLive() (bool, error) {
return c.IsLiveWithContext(context.Background())
}
// IsLiveWithContext checks if the stream is live using the provided context
func (c *Checker) IsLiveWithContext(ctx context.Context) (bool, error) {
slog.Debug("Checking stream status", "url", c.streamURL)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.streamURL, nil)
if err != nil {
return false, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("User-Agent", c.userAgent)
resp, err := c.client.Do(req)
if err != nil {
slog.Debug("Connection to stream failed, considering not live", "error", err)
return false, nil // Connection failures mean the stream is not available
}
defer func() {
if err := resp.Body.Close(); err != nil {
slog.Error("Failed to close response body", "error", err)
}
}()
if resp.StatusCode == http.StatusOK {
slog.Info("Stream is live", "status", resp.StatusCode)
return true, nil
}
slog.Debug("Stream is not live", "status", resp.StatusCode)
return false, nil
}
// GetStreamURL returns the URL being monitored
func (c *Checker) GetStreamURL() string {
return c.streamURL
}