Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,43 @@ The users data file should be located near to the settings. Basic auth, read mor

Note: You should enable authentication with -a (--httpauth) TorrServer startup option.

## Playback devices

TorrServer can send a selected video to a playback agent running on another computer, TV box, or media server. This is useful when the Web UI is opened on a phone but VLC should start on the device connected to the TV.

The feature is **disabled by default**. Until it is explicitly enabled, every browser opens VLC locally exactly as in previous TorrServer versions.

Configure it in **Settings → Application → Remote playback**. Three routing modes are available:

- **Each browser plays locally (legacy)** — preserves the previous behavior.
- **Always use one primary device** — every browser sends playback to one configured TV/media device.
- **Choose a device in each browser** — each browser remembers its own target. It may be marked **Control and playback** or **Control only**.

Each remote device also has an independent **Open VLC in fullscreen** option. It is off by default, so adding a device does not change normal VLC window behavior unless the user asks for it.

Device configuration is stored in the versioned `playback_devices.json` file next to the TorrServer settings. Agent URLs and bearer tokens stay on the server; the normal device list returned to browsers contains only device IDs and names. Enable TorrServer authentication when the Web UI is reachable by untrusted users.

A playback agent implements two endpoints:

```text
GET /health
POST /play
```

TorrServer sends the optional bearer token and the following JSON to `/play`:

```json
{
"path": "Movie.mkv",
"hash": "0123456789abcdef0123456789abcdef01234567",
"index": 1,
"stream_url": "http://torrserver:8090/stream/Movie.mkv?link=...&index=1&play=",
"fullscreen": false
}
```

Use **TorrServer URL for this device** when the agent reaches TorrServer through a different hostname or address than the browser. A reference [Linux/VLC playback agent](extras/vlc-agent/README.md) is included as an optional component.

## Retrackers

When adding a torrent, TorrServer can modify announce trackers according to **Settings → Additional → Retrackers**:
Expand Down
2 changes: 2 additions & 0 deletions extras/vlc-agent/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
__pycache__/
*.pyc
127 changes: 127 additions & 0 deletions extras/vlc-agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# TorrServer VLC agent for Linux

This optional agent lets TorrServer start VLC on a Linux computer connected to a TV while the Web UI is controlled from a phone or another computer.

The agent is intentionally small:

- Python standard library only;
- opens VLC in a normal window or fullscreen according to the selected device setting in TorrServer;
- replaces only the VLC process started by this agent;
- supports a bearer token;
- can restrict accepted TorrServer hostnames;
- validates the torrent hash, file index, filename, and stream URL before launching VLC;
- never executes a shell command.

## Requirements

- Linux with a graphical desktop;
- Python 3.10 or newer;
- VLC;
- systemd user services for the installer below.

## Install

Run this as the desktop user who should own the VLC window:

```bash
cd extras/vlc-agent
./install-user-service.sh --listen-lan --allowed-host 192.168.1.10
```

Replace `192.168.1.10` with the hostname or IP address used in TorrServer stream URLs. Repeat `--allowed-host` when the same TorrServer is reached by several names.

The installer:

- copies the agent to `~/.local/lib/torrserver-vlc-agent/`;
- installs a user service in `~/.config/systemd/user/`;
- creates `~/.config/torrserver-vlc-agent.env` with mode `0600`;
- generates a random bearer token;
- enables and starts the service.

Read the generated token from the environment file and register the device in **TorrServer → Settings → Application → Playback devices**:

```text
Name: Living room TV
Agent URL: http://PLAYER_IP:8092
Agent token: value from VLC_AGENT_TOKEN
TorrServer URL for this device: http://TORRSERVER_IP:8090
```

The last field is optional. Set it when the player reaches TorrServer through a different address than the browser, for example when the browser uses a public HTTPS name but the TV computer should stream over the LAN.

## Configuration

Edit:

```text
~/.config/torrserver-vlc-agent.env
```

Then restart:

```bash
systemctl --user restart torrserver-vlc-agent.service
```

Useful options:

```text
VLC_AGENT_HOST=0.0.0.0
VLC_AGENT_PORT=8092
VLC_AGENT_ALLOWED_HOSTS=192.168.1.10,movies.example.net
VLC_AGENT_PLAYER=/usr/bin/vlc
VLC_AGENT_PLAYER_ARGS="--no-one-instance --no-video-title-show --network-caching=3000 --http-reconnect"
```

TorrServer sends the device's **Open VLC in fullscreen** checkbox with every play request. The agent appends either `--fullscreen` or `--no-fullscreen` after the configured arguments, so the checkbox has an unambiguous result and remains off by default.

Additional VLC flags may be appended to `VLC_AGENT_PLAYER_ARGS`. Examples:

- `--qt-dark-palette` for VLC builds that support the dark Qt palette;
- `--aout=pulse --no-spdif --stereo-mode=1` when HDMI passthrough causes audio problems.

## Security

The default listener is `127.0.0.1`. Direct LAN access requires `VLC_AGENT_HOST=0.0.0.0` or `--listen-lan`.

A non-loopback listener refuses to start without a bearer token unless `--allow-unauthenticated-network` is explicitly used. That override is intended only for isolated test networks.

Also restrict TCP port `8092` with the host firewall so only the TorrServer machine can reach it. `VLC_AGENT_ALLOWED_HOSTS` limits the hostname accepted inside `stream_url`; it does not replace a firewall or bearer token.

## Desktop session troubleshooting

The service runs as a systemd **user** service so VLC can connect to that user's display and audio session. On desktops that do not import graphical variables into the user manager, run this once from a terminal inside the desktop session:

```bash
systemctl --user import-environment DISPLAY WAYLAND_DISPLAY DBUS_SESSION_BUS_ADDRESS PULSE_SERVER
systemctl --user restart torrserver-vlc-agent.service
```

Logs and status:

```bash
systemctl --user status torrserver-vlc-agent.service
journalctl --user -u torrserver-vlc-agent.service -f
```

Health check:

```bash
curl -H "Authorization: Bearer TOKEN_FROM_ENV_FILE" http://127.0.0.1:8092/health
```

## Run without installing

The agent can be started directly:

```bash
VLC_AGENT_TOKEN="TOKEN" \
VLC_AGENT_ALLOWED_HOSTS="192.168.1.10" \
python3 torrserver_vlc_agent.py --host 0.0.0.0
```

## Tests

```bash
python3 -m unittest -v test_agent.py
```
81 changes: 81 additions & 0 deletions extras/vlc-agent/install-user-service.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/bin/sh
set -eu

listen_host=127.0.0.1
allowed_hosts=

usage() {
cat <<'EOF'
Usage: ./install-user-service.sh [--listen-lan] [--allowed-host HOST]

--listen-lan listen on 0.0.0.0 instead of loopback
--allowed-host HOST allow stream URLs from this TorrServer host; repeatable
EOF
}

while [ "$#" -gt 0 ]; do
case "$1" in
--listen-lan)
listen_host=0.0.0.0
shift
;;
--allowed-host)
[ "$#" -ge 2 ] || { echo "--allowed-host requires a value" >&2; exit 2; }
if [ -n "$allowed_hosts" ]; then
allowed_hosts="$allowed_hosts,$2"
else
allowed_hosts=$2
fi
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 2
;;
esac
done

command -v python3 >/dev/null 2>&1 || { echo "python3 is required" >&2; exit 1; }
player=$(command -v vlc || true)
[ -n "$player" ] || { echo "VLC is required" >&2; exit 1; }
command -v systemctl >/dev/null 2>&1 || { echo "systemd is required" >&2; exit 1; }

source_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
agent_dir="$HOME/.local/lib/torrserver-vlc-agent"
unit_dir="$HOME/.config/systemd/user"
env_file="$HOME/.config/torrserver-vlc-agent.env"
unit_file="$unit_dir/torrserver-vlc-agent.service"

install -d -m 0755 "$agent_dir" "$unit_dir"
install -m 0755 "$source_dir/torrserver_vlc_agent.py" "$agent_dir/torrserver_vlc_agent.py"
install -m 0644 "$source_dir/torrserver-vlc-agent.service" "$unit_file"

if [ ! -e "$env_file" ]; then
token=$(python3 -c 'import secrets; print(secrets.token_urlsafe(32))')
umask 077
cat >"$env_file" <<EOF
VLC_AGENT_HOST=$listen_host
VLC_AGENT_PORT=8092
VLC_AGENT_TOKEN=$token
VLC_AGENT_ALLOWED_HOSTS=$allowed_hosts
VLC_AGENT_PLAYER=$player
VLC_AGENT_PLAYER_ARGS="--no-one-instance --no-video-title-show --network-caching=3000 --http-reconnect"
VLC_AGENT_STOP_TIMEOUT=3
EOF
chmod 0600 "$env_file"
else
echo "Keeping existing configuration: $env_file"
fi

systemctl --user daemon-reload
systemctl --user enable --now torrserver-vlc-agent.service

echo "Installed TorrServer VLC agent."
echo "Configuration: $env_file"
echo "Status: systemctl --user status torrserver-vlc-agent.service"
echo "Use the VLC_AGENT_TOKEN value from the configuration when registering this device in TorrServer."
Loading