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/hardware.Dockerfile b/hardware.Dockerfile index b3e064c6..0aa85374 100644 --- a/hardware.Dockerfile +++ b/hardware.Dockerfile @@ -1,8 +1,9 @@ # syntax=docker/dockerfile:labs # 0. Prepare images -# only debian 12 (bookworm) has latest ffmpeg -ARG DEBIAN_VERSION="bookworm-slim" +# only debian 13 (trixie) has latest ffmpeg +# https://packages.debian.org/trixie/ffmpeg +ARG DEBIAN_VERSION="trixie-slim" ARG GO_VERSION="1.21-bookworm" ARG NGROK_VERSION="3" @@ -44,13 +45,16 @@ RUN rm -f /etc/apt/apt.conf.d/docker-clean \ # Install ffmpeg, bash (for run.sh), tini (for signal handling), # and other common tools for the echo source. # non-free for Intel QSV support (not used by go2rtc, just for tests) +# mesa-va-drivers for AMD APU # libasound2-plugins for ALSA support RUN --mount=type=cache,target=/var/cache/apt,sharing=locked --mount=type=cache,target=/var/lib/apt,sharing=locked \ - echo 'deb http://deb.debian.org/debian bookworm non-free' > /etc/apt/sources.list.d/debian-non-free.list && \ + echo 'deb http://deb.debian.org/debian trixie non-free' > /etc/apt/sources.list.d/debian-non-free.list && \ apt-get -y update && apt-get -y install tini ffmpeg \ python3 curl jq \ intel-media-va-driver-non-free \ - libasound2-plugins + mesa-va-drivers \ + libasound2-plugins && \ + apt-get clean && rm -rf /var/lib/apt/lists/* COPY --link --from=rootfs / / 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/core/track.go b/pkg/core/track.go index 0a3a701c..1faae309 100644 --- a/pkg/core/track.go +++ b/pkg/core/track.go @@ -73,9 +73,6 @@ func (t *Receiver) Replace(target *Receiver) { // move this receiver senders to new receiver t.mu.Lock() senders := t.senders - // fix https://github.com/AlexxIT/go2rtc/issues/828 - // TODO: fix the reason, not the consequence - t.senders = nil t.mu.Unlock() target.mu.Lock() 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/pkg/rtsp/client.go b/pkg/rtsp/client.go index 37d30950..ca32ce32 100644 --- a/pkg/rtsp/client.go +++ b/pkg/rtsp/client.go @@ -219,6 +219,9 @@ func (c *Conn) SetupMedia(media *core.Media) (byte, error) { rawURL += "/" } rawURL += media.ID + } else if strings.HasPrefix(rawURL, "rtsp://rtsp://") { + // fix https://github.com/AlexxIT/go2rtc/issues/830 + rawURL = rawURL[7:] } trackURL, err := urlParse(rawURL) if err != nil { diff --git a/www/add.html b/www/add.html index 2b1bb9d7..3058f8dc 100644 --- a/www/add.html +++ b/www/add.html @@ -5,11 +5,6 @@ diff --git a/www/index.html b/www/index.html index 4e4f9992..675e7079 100644 --- a/www/index.html +++ b/www/index.html @@ -8,39 +8,18 @@ go2rtc diff --git a/www/main.js b/www/main.js index 63dbde32..bb2bfec6 100644 --- a/www/main.js +++ b/www/main.js @@ -18,7 +18,6 @@ i { nav { display: block; - /*width: 660px;*/ margin: 0 auto 10px; } @@ -41,6 +40,97 @@ nav a:hover { nav li { display: inline; } + +body { + font-family: Arial, Helvetica, sans-serif; + background-color: white; +} +table { + background-color: white; + text-align: left; + border-collapse: collapse; +} +table thead { + background: #CFCFCF; + background: linear-gradient(to bottom, #dbdbdb 0%, #d3d3d3 66%, #CFCFCF 100%); + border-bottom: 3px solid black; +} +table thead th { + font-size: 15px; + font-weight: bold; + color: black; + text-align: center; +} +table td, table th { + border: 1px solid black; + padding: 5px 5px; +} + +/* Dark mode styles */ +body.dark-mode { + background-color: #121212; + color: #e0e0e0; +} + +body.dark-mode nav ul { + background: #333; +} + +body.dark-mode a { + background: rgba(45, 45, 45, .8); + border-right: 1px solid #2c2c2c; + color: #c7c7c7; +} + +body.dark-mode a:hover { + background: #555; +} + +body.dark-mode a:visited { + color: #999; +} + +body.dark-mode table { + background-color: #222; + color: #ddd; +} + +body.dark-mode table thead { + background: linear-gradient(to bottom, #444 0%, #3d3d3d 66%, #333 100%); + border-bottom: 3px solid #888; +} +body.dark-mode table thead th { + font-size: 15px; + font-weight: bold; + color: #ddd; + text-align: center; +} +body.dark-mode table td, body.dark-mode table th { + border: 1px solid #444; +} + +body.dark-mode button { + background: rgba(255, 255, 255, .1); + border: 1px solid #444; + color: #ccc; +} + +body.dark-mode input, +body.dark-mode select, +body.dark-mode textarea { + background-color: #333; + color: #e0e0e0; + border: 1px solid #444; +} + +body.dark-mode input::placeholder, +body.dark-mode textarea::placeholder { + color: #bbb; +} + +body.dark-mode hr { + border-top: 1px solid #444; +} ` + document.body.innerHTML; + +const sunIcon = '☀️'; +const moonIcon = '🌕'; + +document.addEventListener('DOMContentLoaded', () => { + const darkModeToggle = document.getElementById('darkModeToggle'); + const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)'); + + const isDarkModeEnabled = () => document.body.classList.contains('dark-mode'); + + // Update the toggle button based on the dark mode state + const updateToggleButton = () => { + if (isDarkModeEnabled()) { + darkModeToggle.innerHTML = sunIcon; + darkModeToggle.setAttribute('aria-label', 'Enable light mode'); + } else { + darkModeToggle.innerHTML = moonIcon; + darkModeToggle.setAttribute('aria-label', 'Enable dark mode'); + } + }; + + const updateDarkMode = () => { + if (localStorage.getItem('darkMode') === 'enabled' || prefersDarkScheme.matches && localStorage.getItem('darkMode') !== 'disabled') { + document.body.classList.add('dark-mode'); + } else { + document.body.classList.remove('dark-mode'); + } + updateEditorTheme(); + updateToggleButton(); + }; + + // Update the editor theme based on the dark mode state + const updateEditorTheme = () => { + if (typeof editor !== 'undefined') { + editor.setTheme(isDarkModeEnabled() ? "ace/theme/tomorrow_night_eighties" : "ace/theme/github"); } + }; + + // Initial update for dark mode and toggle button + updateDarkMode(); + + // Listen for changes in the system's color scheme preference + prefersDarkScheme.addEventListener('change', updateDarkMode); // Modern approach + + // Toggle dark mode and update local storage on button click + darkModeToggle.addEventListener('click', () => { + const enabled = document.body.classList.toggle('dark-mode'); + localStorage.setItem('darkMode', enabled ? 'enabled' : 'disabled'); + updateToggleButton(); // Update the button after toggling + updateEditorTheme(); + }); +});