mirror of
https://github.com/AlexxIT/go2rtc.git
synced 2025-09-26 20:31:11 +08:00
Add stream redirect handler
This commit is contained in:
@@ -2,28 +2,28 @@ package echo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
"github.com/AlexxIT/go2rtc/internal/app"
|
"github.com/AlexxIT/go2rtc/internal/app"
|
||||||
"github.com/AlexxIT/go2rtc/internal/streams"
|
"github.com/AlexxIT/go2rtc/internal/streams"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
|
||||||
"github.com/AlexxIT/go2rtc/pkg/shell"
|
"github.com/AlexxIT/go2rtc/pkg/shell"
|
||||||
"os/exec"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Init() {
|
func Init() {
|
||||||
log := app.GetLogger("echo")
|
log := app.GetLogger("echo")
|
||||||
|
|
||||||
streams.HandleFunc("echo", func(url string) (core.Producer, error) {
|
streams.RedirectFunc("echo", func(url string) (string, error) {
|
||||||
args := shell.QuoteSplit(url[5:])
|
args := shell.QuoteSplit(url[5:])
|
||||||
|
|
||||||
b, err := exec.Command(args[0], args[1:]...).Output()
|
b, err := exec.Command(args[0], args[1:]...).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
b = bytes.TrimSpace(b)
|
b = bytes.TrimSpace(b)
|
||||||
|
|
||||||
log.Debug().Str("url", url).Msgf("[echo] %s", b)
|
log.Debug().Str("url", url).Msgf("[echo] %s", b)
|
||||||
|
|
||||||
return streams.GetProducer(string(b))
|
return string(b), nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package ffmpeg
|
package ffmpeg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -10,7 +9,6 @@ import (
|
|||||||
"github.com/AlexxIT/go2rtc/internal/ffmpeg/hardware"
|
"github.com/AlexxIT/go2rtc/internal/ffmpeg/hardware"
|
||||||
"github.com/AlexxIT/go2rtc/internal/rtsp"
|
"github.com/AlexxIT/go2rtc/internal/rtsp"
|
||||||
"github.com/AlexxIT/go2rtc/internal/streams"
|
"github.com/AlexxIT/go2rtc/internal/streams"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
|
||||||
"github.com/AlexxIT/go2rtc/pkg/ffmpeg"
|
"github.com/AlexxIT/go2rtc/pkg/ffmpeg"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,12 +25,9 @@ func Init() {
|
|||||||
defaults["global"] += " -v error"
|
defaults["global"] += " -v error"
|
||||||
}
|
}
|
||||||
|
|
||||||
streams.HandleFunc("ffmpeg", func(url string) (core.Producer, error) {
|
streams.RedirectFunc("ffmpeg", func(url string) (string, error) {
|
||||||
args := parseArgs(url[7:]) // remove `ffmpeg:`
|
args := parseArgs(url[7:])
|
||||||
if args == nil {
|
return "exec:" + args.String(), nil
|
||||||
return nil, errors.New("can't generate ffmpeg command")
|
|
||||||
}
|
|
||||||
return streams.GetProducer("exec:" + args.String())
|
|
||||||
})
|
})
|
||||||
|
|
||||||
device.Init(defaults["bin"])
|
device.Init(defaults["bin"])
|
||||||
|
@@ -37,12 +37,15 @@ func Init() {
|
|||||||
api.HandleFunc("/streams", apiOK)
|
api.HandleFunc("/streams", apiOK)
|
||||||
api.HandleFunc("/stream/", apiStream)
|
api.HandleFunc("/stream/", apiStream)
|
||||||
|
|
||||||
streams.HandleFunc("hass", func(url string) (core.Producer, error) {
|
streams.RedirectFunc("hass", func(url string) (string, error) {
|
||||||
// check entity by name
|
if location := entities[url[5:]]; location != "" {
|
||||||
if url2 := entities[url[5:]]; url2 != "" {
|
return location, nil
|
||||||
return streams.GetProducer(url2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
})
|
||||||
|
|
||||||
|
streams.HandleFunc("hass", func(url string) (core.Producer, error) {
|
||||||
// support hass://supervisor?entity_id=camera.driveway_doorbell
|
// support hass://supervisor?entity_id=camera.driveway_doorbell
|
||||||
client, err := hass.NewClient(url)
|
client, err := hass.NewClient(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -1,41 +1,75 @@
|
|||||||
package streams
|
package streams
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"errors"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Handler func(url string) (core.Producer, error)
|
type Handler func(url string) (core.Producer, error)
|
||||||
|
|
||||||
var handlers = map[string]Handler{}
|
var handlers = map[string]Handler{}
|
||||||
var handlersMu sync.Mutex
|
|
||||||
|
|
||||||
func HandleFunc(scheme string, handler Handler) {
|
func HandleFunc(scheme string, handler Handler) {
|
||||||
handlersMu.Lock()
|
|
||||||
handlers[scheme] = handler
|
handlers[scheme] = handler
|
||||||
handlersMu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func getHandler(url string) Handler {
|
|
||||||
i := strings.IndexByte(url, ':')
|
|
||||||
if i <= 0 { // TODO: i < 4 ?
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
handlersMu.Lock()
|
|
||||||
defer handlersMu.Unlock()
|
|
||||||
return handlers[url[:i]]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func HasProducer(url string) bool {
|
func HasProducer(url string) bool {
|
||||||
return getHandler(url) != nil
|
if i := strings.IndexByte(url, ':'); i > 0 {
|
||||||
|
scheme := url[:i]
|
||||||
|
|
||||||
|
if _, ok := handlers[scheme]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := redirects[scheme]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetProducer(url string) (core.Producer, error) {
|
func GetProducer(url string) (core.Producer, error) {
|
||||||
handler := getHandler(url)
|
if i := strings.IndexByte(url, ':'); i > 0 {
|
||||||
if handler == nil {
|
scheme := url[:i]
|
||||||
return nil, fmt.Errorf("unsupported scheme: %s", url)
|
|
||||||
|
if redirect, ok := redirects[scheme]; ok {
|
||||||
|
location, err := redirect(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if location != "" {
|
||||||
|
return GetProducer(location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if handler, ok := handlers[scheme]; ok {
|
||||||
|
return handler(url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return handler(url)
|
|
||||||
|
return nil, errors.New("streams: unsupported scheme: " + url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect can return: location URL or error or empty URL and error
|
||||||
|
type Redirect func(url string) (string, error)
|
||||||
|
|
||||||
|
var redirects = map[string]Redirect{}
|
||||||
|
|
||||||
|
func RedirectFunc(scheme string, redirect Redirect) {
|
||||||
|
redirects[scheme] = redirect
|
||||||
|
}
|
||||||
|
|
||||||
|
func Location(url string) (string, error) {
|
||||||
|
if i := strings.IndexByte(url, ':'); i > 0 {
|
||||||
|
scheme := url[:i]
|
||||||
|
|
||||||
|
if redirect, ok := redirects[scheme]; ok {
|
||||||
|
return redirect(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user