diff options
| author | Xe Iaso <me@xeiaso.net> | 2024-09-02 09:33:04 -0400 |
|---|---|---|
| committer | Xe Iaso <me@xeiaso.net> | 2024-09-02 09:33:04 -0400 |
| commit | 4628a6e4ba4920925bef6b5dbb6dfd15c7b08a73 (patch) | |
| tree | 34aefa02776bec947c3cb6f38b7c1fd69f7a9d2f /internal/pvfm/recording | |
| parent | a2cf1050866bc902ad014ab21767531ff64a337a (diff) | |
| download | x-4628a6e4ba4920925bef6b5dbb6dfd15c7b08a73.tar.xz x-4628a6e4ba4920925bef6b5dbb6dfd15c7b08a73.zip | |
import cmd/aerial
Signed-off-by: Xe Iaso <me@xeiaso.net>
Diffstat (limited to 'internal/pvfm/recording')
| -rw-r--r-- | internal/pvfm/recording/doc.go | 4 | ||||
| -rw-r--r-- | internal/pvfm/recording/recording.go | 120 | ||||
| -rw-r--r-- | internal/pvfm/recording/recording_demo.go | 59 |
3 files changed, 183 insertions, 0 deletions
diff --git a/internal/pvfm/recording/doc.go b/internal/pvfm/recording/doc.go new file mode 100644 index 0000000..95bd800 --- /dev/null +++ b/internal/pvfm/recording/doc.go @@ -0,0 +1,4 @@ +/* +Package recording manages recording radio streams to files. +*/ +package recording diff --git a/internal/pvfm/recording/recording.go b/internal/pvfm/recording/recording.go new file mode 100644 index 0000000..d3378ce --- /dev/null +++ b/internal/pvfm/recording/recording.go @@ -0,0 +1,120 @@ +package recording + +import ( + "context" + "errors" + "log" + "os" + "os/exec" + "time" +) + +var ( + ErrMismatchWrite = errors.New("recording: did not write the same number of bytes that were read") +) + +// Recording ... +type Recording struct { + ctx context.Context + url string + fname string + cancel context.CancelFunc + started time.Time + restarts int + + Debug bool + Err error +} + +// New creates a new Recording of the given URL to the given filename for output. +func New(url, fname string) (*Recording, error) { + ctx, cancel := context.WithTimeout(context.Background(), 8*time.Hour) + + r := &Recording{ + ctx: ctx, + url: url, + fname: fname, + cancel: cancel, + started: time.Now(), + } + + return r, nil +} + +// Cancel stops the recording. +func (r *Recording) Cancel() { + r.cancel() +} + +// Done returns the done channel of the recording. +func (r *Recording) Done() <-chan struct{} { + return r.ctx.Done() +} + +// OutputFilename gets the output filename originally passed into New. +func (r *Recording) OutputFilename() string { + return r.fname +} + +// StartTime gets start time +func (r *Recording) StartTime() time.Time { + return r.started +} + +// Start blockingly starts the recording and returns the error if one is encountered while streaming. +// This should be stopped in another goroutine. +func (r *Recording) Start() error { + sr, err := exec.LookPath("streamripper") + if err != nil { + return err + } + + cmd := exec.CommandContext(r.ctx, sr, r.url, "-A", "-a", r.fname) + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + + log.Printf("%s: %v", cmd.Path, cmd.Args) + + err = cmd.Start() + if err != nil { + return err + } + + // Automatically kill recordings after four hours + go func() { + t := time.NewTicker(4 * time.Hour) + defer t.Stop() + + log.Println("got here") + + for { + select { + case <-r.ctx.Done(): + return + case <-t.C: + log.Printf("Automatically killing recording after 4 hours...") + r.Cancel() + } + } + }() + + go func() { + defer r.Cancel() + err := cmd.Wait() + if err != nil { + log.Println(err) + } + }() + + defer r.cancel() + + for { + time.Sleep(250 * time.Millisecond) + + select { + case <-r.ctx.Done(): + return nil + default: + } + } +} diff --git a/internal/pvfm/recording/recording_demo.go b/internal/pvfm/recording/recording_demo.go new file mode 100644 index 0000000..3264841 --- /dev/null +++ b/internal/pvfm/recording/recording_demo.go @@ -0,0 +1,59 @@ +// +build ignore + +package main + +import ( + "flag" + "log" + "os" + "os/signal" + + "github.com/PonyvilleFM/aura/recording" +) + +var ( + url = flag.String("url", "", "url to record") + fname = flag.String("fname", "", "filename to record to") + debug = flag.Bool("debug", false, "debug mode") + + askedToDie bool +) + +func main() { + flag.Parse() + + r, err := recording.New(*url, *fname) + if err != nil { + log.Printf("%s -> %s: %v", *url, *fname, err) + log.Fatal(err) + } + + r.Debug = *debug + + go func() { + log.Printf("Starting download of stream %s to %s", *url, *fname) + err := r.Start() + if err != nil { + log.Fatal(err) + } + }() + + go func() { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + + for _ = range c { + if askedToDie { + os.Exit(2) + } + + log.Println("Stopping recording... (^C again to kill now)") + r.Cancel() + + askedToDie = true + } + }() + + <-r.Done() + log.Printf("stream %s recorded to %s", *url, *fname) +} |
