diff --git a/README.md b/README.md index aaed9410..4bc74af7 100644 --- a/README.md +++ b/README.md @@ -1352,6 +1352,7 @@ streams: **Distributions** - [Alpine Linux](https://pkgs.alpinelinux.org/packages?name=go2rtc) +- [Arch User Repository](https://linux-packages.com/aur/package/go2rtc) - [Gentoo](https://github.com/inode64/inode64-overlay/tree/main/media-video/go2rtc) - [NixOS](https://search.nixos.org/packages?query=go2rtc) - [Proxmox Helper Scripts](https://tteck.github.io/Proxmox/) diff --git a/internal/exec/exec.go b/internal/exec/exec.go index 36dacfaa..6bc5698a 100644 --- a/internal/exec/exec.go +++ b/internal/exec/exec.go @@ -7,6 +7,7 @@ import ( "fmt" "os" "os/exec" + "strings" "sync" "time" @@ -108,7 +109,7 @@ func handleRTSP(url, path string, cmd *exec.Cmd) (core.Producer, error) { waitersMu.Unlock() }() - log.Debug().Str("url", url).Msg("[exec] run") + log.Debug().Str("url", url).Str("cmd", fmt.Sprintf("%s", strings.Join(cmd.Args, " "))).Msg("[exec] run") ts := time.Now() diff --git a/pkg/ivideon/client.go b/pkg/ivideon/client.go index 0158f08d..c1b055b8 100644 --- a/pkg/ivideon/client.go +++ b/pkg/ivideon/client.go @@ -132,6 +132,9 @@ func (c *Client) Handle() error { case "stream-init": continue + case "metadata": + continue + case "fragment": _, data, err = c.conn.ReadMessage() if err != nil { @@ -183,6 +186,9 @@ func (c *Client) getTracks() error { } switch msg.Type { + case "metadata": + continue + case "stream-init": s := msg.CodecString i := strings.IndexByte(s, '.') diff --git a/www/index.html b/www/index.html index f4668a51..675e7079 100644 --- a/www/index.html +++ b/www/index.html @@ -100,28 +100,49 @@ function reload() { const url = new URL('api/streams', location.href); + const checkboxStates = {}; + tbody.querySelectorAll('input[type="checkbox"][name]').forEach(checkbox => { + checkboxStates[checkbox.name] = checkbox.checked; + }); fetch(url, {cache: 'no-cache'}).then(r => r.json()).then(data => { - tbody.innerHTML = ''; + const existingIds = Array.from(tbody.querySelectorAll('tr')).map(tr => tr.dataset['id']); + const fetchedIds = []; for (const [key, value] of Object.entries(data)) { const name = key.replace(/[<">]/g, ''); // sanitize + fetchedIds.push(name); + + let tr = tbody.querySelector(`tr[data-id="${name}"]`); const online = value && value.consumers ? value.consumers.length : 0; const src = encodeURIComponent(name); - const links = templates.map(link => { - return link.replace('{name}', src); - }).join(' '); + const links = templates.map(link => link.replace('{name}', src)).join(' '); - const tr = document.createElement('tr'); - tr.dataset['id'] = name; + if (!tr) { + tr = document.createElement('tr'); + tr.dataset['id'] = name; + tbody.appendChild(tr); + } + + const isChecked = checkboxStates[name] ? 'checked' : ''; tr.innerHTML = - `` + + `` + `${online} / info` + `${links}`; - tbody.appendChild(tr); } + + // Remove old rows + existingIds.forEach(id => { + if (!fetchedIds.includes(id)) { + const trToRemove = tbody.querySelector(`tr[data-id="${id}"]`); + tbody.removeChild(trToRemove); + } + }); }); } + // Auto-reload + setInterval(reload, 1000); + const url = new URL('api', location.href); fetch(url, {cache: 'no-cache'}).then(r => r.json()).then(data => { const info = document.querySelector('.info');