# R36S DLNA Browser

A lightweight DLNA media browser for the R36S handheld, built with Python, SDL2, and GStreamer.

Author: Matteo Benedetto

## Features

- Discover DLNA/UPnP media servers on local LAN via SSDP
- Browse media libraries hierarchically with D-pad navigation
- Play audio and video locally via integrated GStreamer playback inside the SDL window
- Optimised for 640×480 screen and low-power RK3326 hardware

## System Prerequisites

Install these system packages before running (Ubuntu/Debian-based):

```bash
sudo apt install libsdl2-2.0-0 libsdl2-ttf-2.0-0 python3 python3-pip python3-gi gir1.2-gstreamer-1.0 gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good
```

On Fedora the equivalent runtime packages are:

```bash
sudo dnf install SDL2_ttf python3-gobject gstreamer1 gstreamer1-plugins-base gstreamer1-plugins-good python3 python3-pip
```

The current playback path is SDL-only: GStreamer decodes into frames and the app
renders them inside the SDL renderer. This avoids any dependency on X11,
Wayland embedding, or a window manager and is aligned with DRM/KMS-only targets.

On ArkOS-derived firmware the SDL2 libraries are typically pre-installed.

A TrueType font is bundled inside the package at `src/r36s_dlna_browser/assets/`
so packaged builds do not depend on a system font path. System font fallbacks are
still kept for development machines.

## Quick Start

```bash
cd /path/to/R36SHack
python3 -m pip install -e ".[dev]"
python3 -m r36s_dlna_browser
```

## Miniforge / Conda Deploy

Use Miniforge or Miniconda when you want a reproducible Linux development or
packaging environment with GStreamer and SDL dependencies managed together.

```bash
cd /path/to/R36SHack
conda env create -f environment.yml
conda activate r36s-dlna-browser
python -m r36s_dlna_browser
```

To update an existing environment after dependency changes:

```bash
conda env update -f environment.yml --prune
conda activate r36s-dlna-browser
```

Or without installing:

```bash
cd /path/to/R36SHack
pip install -r requirements.txt
PYTHONPATH=src python3 -m r36s_dlna_browser
```

## Controls

| Key / Button | Action               |
|-------------|----------------------|
| Up / Down    | Navigate items       |
| Left / Right | Page up / down       |
| A (Return)   | Select / Enter       |
| B (Escape)   | Back                 |
| Start        | Quit                 |

During playback, the same controls are remapped to transport actions:

- `A`: pause / resume
- `B`: stop and return to browser
- `Left / Right`: seek `-10s / +10s`
- `Up / Down`: volume `+5 / -5`
- `H` / `Y`: cycle HUD mode (`auto / fixed / hidden`)

## On-Device (R36S / ArkOS)

1. Copy the project to a writable location such as `/home/ark/MatHacks/R36SHack`.
2. Ensure Wi-Fi is connected.
3. Install or reuse a conda env at `/home/ark/miniconda3/envs/r36s-dlna-browser`.
4. Run via PortMaster or a launch script:

```bash
cd /home/ark/MatHacks/R36SHack
export LD_LIBRARY_PATH=/home/ark/miniconda3/envs/r36s-dlna-browser/lib
export GST_PLUGIN_SCANNER=/home/ark/miniconda3/envs/r36s-dlna-browser/libexec/gstreamer-1.0/gst-plugin-scanner
python -m r36s_dlna_browser
```

An ArkOS launcher script for this layout is included at `deploy/arkos/MatHacks.sh`.

## Git / Release Workflow

For publication on a Gitea instance with `tea`, initialize git locally, create a
remote repository, then push the current branch.

```bash
git init
git add .
git commit -m "Initial import"
tea repos create --name R36SHack --description "SDL2/GStreamer DLNA browser for R36S" --owner enne2
git remote add origin ssh://git@git.enne2.net:222/enne2/R36SHack.git
git push -u origin main
```

Published repository:
https://git.enne2.net/enne2/R36SHack

## Project Structure

```
src/r36s_dlna_browser/
├── __main__.py          # Entrypoint
├── app.py               # Application lifecycle
├── assets/
│   └── NotoSans-Regular.ttf
├── dlna/
│   ├── discovery.py     # SSDP media-server discovery
│   ├── client.py        # ContentDirectory browsing via DmsDevice
│   ├── models.py        # Domain models for servers/items
│   └── browser_state.py # Navigation stack and cache
├── ui/
│   ├── sdl_app.py       # SDL2 window, event loop, rendering
│   ├── screens.py       # Screen definitions
│   └── theme.py         # Layout constants for 640×480
├── player/
│   ├── backend.py       # Player interface
│   └── gstreamer_backend.py # integrated GStreamer playback backend
└── platform/
    ├── controls.py      # Input mapping
    └── runtime.py       # Runtime detection and logging
```

## License

MIT

