diff --git a/internal/ffmpeg/api.go b/internal/ffmpeg/api.go new file mode 100644 index 00000000..d802f87c --- /dev/null +++ b/internal/ffmpeg/api.go @@ -0,0 +1,51 @@ +package ffmpeg + +import ( + "net/http" + "strings" + + "github.com/AlexxIT/go2rtc/internal/streams" +) + +func apiFFmpeg(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + http.Error(w, "", http.StatusMethodNotAllowed) + return + } + + query := r.URL.Query() + dst := query.Get("dst") + stream := streams.Get(dst) + if stream == nil { + http.Error(w, "", http.StatusNotFound) + return + } + + var src string + if s := query.Get("file"); s != "" { + if streams.Validate(s) == nil { + src = "ffmpeg:" + s + "#audio=auto#input=file" + } + } else if s = query.Get("live"); s != "" { + if streams.Validate(s) == nil { + src = "ffmpeg:" + s + "#audio=auto" + } + } else if s = query.Get("text"); s != "" { + if strings.IndexAny(s, `'"&%$`) < 0 { + src = "ffmpeg:tts?text=" + s + if s = query.Get("voice"); s != "" { + src += "&voice=" + s + } + src += "#audio=auto" + } + } + + if src == "" { + http.Error(w, "", http.StatusBadRequest) + return + } + + if err := stream.Play(src); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } +} diff --git a/internal/ffmpeg/ffmpeg.go b/internal/ffmpeg/ffmpeg.go index db5890d0..26f9880f 100644 --- a/internal/ffmpeg/ffmpeg.go +++ b/internal/ffmpeg/ffmpeg.go @@ -5,6 +5,7 @@ import ( "slices" "strings" + "github.com/AlexxIT/go2rtc/internal/api" "github.com/AlexxIT/go2rtc/internal/app" "github.com/AlexxIT/go2rtc/internal/ffmpeg/device" "github.com/AlexxIT/go2rtc/internal/ffmpeg/hardware" @@ -40,6 +41,8 @@ func Init() { streams.HandleFunc("ffmpeg", NewProducer) + api.HandleFunc("api/ffmpeg", apiFFmpeg) + device.Init(defaults["bin"]) hardware.Init(defaults["bin"]) } diff --git a/www/links.html b/www/links.html index 940de9fd..3b651762 100644 --- a/www/links.html +++ b/www/links.html @@ -85,16 +85,21 @@
example: ffmpeg:https://example.com/song.mp3#audio=pcma#input=file- +