This is the multi-page printable view of this section. Click here to print.
Media
- 1: Distribution
- 1.1: Torrent
- 1.1.1: rTorrent
- 1.1.2: Transmission
- 2: Indexers
- 2.1: Bitmagnet
- 3: Players
- 3.1: Audioserve
- 3.2: Calibre-Web
- 3.3: Jellyfin
- 3.4: LibreELEC
- 3.4.1: Add-ons
- 3.4.2: AutoSSH
- 3.4.3: Building
- 3.4.4: Fancontrol
- 3.4.5: Hotspot
- 3.4.6: MergerFS on LibreELEC
- 3.4.7: Remotes
- 3.5: Plex
1 - Distribution
1.1 - Torrent
I’ve taken a look at a few of the clients you’d run on a server. The notable ones are:
- Aria2
- Deluge
- qBittorrent
- rTorrent
- Transmission
1.1.1 - rTorrent
RTorrent is a contender for the best, light-weight, torrent client. It’s terminal based, though there are web interfaces for it. In my testing it was second-best in terms of resource use.
The developer has recently picked it up again and is pulling in community contributions. My recent (Jan 2026) builds of it had segfault issues, but those may be cleaned up by now.
You can build and install on the same box, but if you’re running a seed box you may prefer to package it for deployment, so I’ve included both so you can:
or
Build and Install
LibTorrent
RTorrent depends on LibTorrent, also from this developer.
# on Debian 13 (Trixie)
sudo apt install git
git clone https://github.com/rakshasa/libtorrent
cd libtorrent
sudo apt install build-essential autoconf libcurlpp-dev libtool
autoreconf -ivf
./configure
make
sudo make install
RTorrent
# Assuming you've already installed and built libtorrent on this box. Adjust branch after checking
git clone https://github.com/rakshasa/rtorrent --branch v0.16.6 --depth 1 rtorrent-0.16.6
sudo apt install libncurses-dev
autoreconf -ivf
./configure
make
sudo make install
Build and Package
Packaging things into a .deb is a bit of an adventure. But give it a try. Once you get it going you can probably use some sort of system to keep it up do date. Maybe do a repo and go full-debian on.
Assuming you’ve built and copied the packages:
sudo apt install ./libtorrent36_0.16.6-1_amd64.deb ./rtorrent_0.16.6-1_amd64.deb
# Connect to the console with
sudo -u rtorrent tmux a
# Disconnect from tmux to leave it running with
Ctrl-b d
You probably want to link it to other tools, like sonarr. They don’t talk SCGI, so you’ll need a proxy. Lightty is an easy way to do that.
sudo apt install lighttpd
sudo vi /etc/lighttpd/conf-available/10-rtorrent.conf
server.modules += ( "mod_scgi" )
scgi.server = (
"/RPC2" =>
( "127.0.0.1" =>
(
"socket" => "/home/user/rtorrent/rpc.socket",
"check-local" => "disable",
"disable-time" => 0, # don't disable SCGI if connection fails
)
# YOU MUST ADD SOME KIND OF AUTH
)
)
or possibly
"host" => "127.0.0.1",
"port" => 8080,
sudo lighty-enable-mod rtorrent
sudo systemctl restart lighttpd
You can test with a curl or xmlrpc (though you may need to add the latter)
curl -H "Content-Type: text/xml" --data "<?xml version='1.0'?><methodCall><methodName>system.listMethods</methodName></methodCall>" http://127.0.0.1/RPC2
xmlrpc tpub/RPC2 system.listMethods
1.1.2 - Transmission
Transmission is a very clean and easy to use client. It runs efficiently and includes a web interface. The only downside is under heavy load it suffers performance issues. Say over a hundred torrents and a thousand connections.
But for casual use, it’s my preferred client.
Installation
sudo apt install transmission-daemon
Notes on Use
One note about installing transmission; make sure to stop the service before editing the config file. It will replace your settings with it’s running settings when it exits, otherwise.
sudo apt install transmission-daemon
sudo service transmission-daemon stop
sudo vim /etc/transmission-daemon/settings.json
"dht-enabled": false,
"rpc-whitelist": "127.0.0.1,192.168.*.*",
"peer-limit-global": 960,
"peer-limit-per-torrent": 288,
"preallocation": 2,
"rename-partial-files": false,
"watch-dir": "xxxxx",
"watch-dir-enabled": true
# Legacy setting not needed anymore
"max-peers-global": 960,
Most systems will require adjustment of the iptables firewall, should you be using such, for both the web admin port and the torrent traffic port. If you’re using something other than the standard port, adjust to suit. If you’re using random ports, you may want to open a range.
# The web admin port is tcp 9091 and peer traffic is 51413 tcp/udp by default
sudo iptables -A INPUT -p tcp -s 192.168.1.1/24 --dport 9091 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 51413 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p udp --dport 51413 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
Should you have a router and NAT tranmission will use upnp to forward the appropriate ports. You can also check out upnpc for manipulating that device manually or via script.
If you’re using a VPN you may want to restrict traffic to that connection. You can configure transmission for that. Disable the transmission server so that you can start it as part of the VPN service.
sudo systemctl disable --now transmission-daemon
Here’s an example using PIA. Note: This may be somewhat dated at this point.
# These are not your normal credentials. Even though you may be using wireguard, set them up under the openvpn service.
# Get these and the client ID from their website support section
USER=xxxx
PASS=xxxxx
CLIENT_ID=xxxxx
IP=$(ip -o -4 addr list tun0 | awk '{print $4}')
PORT=$(curl -d "user=$USER&pass=$PASS&client_id=$CLIENT_ID&local_ip=$IP" https://www.privateinternetaccess.com/vpninfo/port_forward_assignment | grep -o '[0-9]\+')
echo $IP $PORT
# Just in case it's already running
sudo service transmission-daemon stop
sudo sed -i "s/bind-address-ipv4.*/bind-address-ipv4\": \"$IP\",/" /etc/transmission-daemon/settings.json
sudo sed -i "s/peer-port\".*/peer-port\": $PORT, /" /etc/transmission-daemon/settings.json
sudo iptables -A INPUT -i tun0 -p tcp -m tcp --dport $PORT -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -i tun0 -p udp -m udp --dport $PORT -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo service transmission-daemon start
2 - Indexers
2.1 - Bitmagnet
Bitmagnet is a tool that crawls the Distributed Hash Table (DHT) and attempts in index all known torrents. It’s normally distributed via docker, but you can also deploy without it by installing:
- VPN
- Postgres
- Bitmagnet
VPN
You may want to use a VPN so you don’t get flagged. Even though you’re not downloading files with this tool, it’s a bittorrent tool and that could get you swept up in something.
Postgres
# Insall postgres
sudo apt install -y postgresql postgresql-contrib
# Create the database
createdb bitmagnet
# Run the psql command as the system user 'postgres' who has superuser rights on the DB
# and set the postgres user password
sudo -i -u postgres psql
ALTER USER postgres WITH PASSWORD 'SOMETHINGRANDOM';
exit
Note - you may need to add a line to the postgres client auth config file. If you can’t connect with psql --host localhost --user postgres --password you may need to add a line like local all all scram-sha-256 to the /etc/postgresql/17/main/pg_hba.conf file.
Bitmagnet
You can install with go as the setup page suggests but they also make a .deb you can more easily install.
wget https://github.com/bitmagnet-io/bitmagnet/releases/download/v0.10.0/bitmagnet_0.10.0_linux_amd64.deb
sudo apt install ./bitmagnet_0.10.0_linux_amd64.deb
Then you can create a service file like this.
sudo vi /etc/systemd/system/bitmagnet-web.service
[Unit]
Description=bitmagnet Web GUI
After=network-online.target
After=pia-vpn.service
Requires=pia-vpn.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/bitmagnet
ExecStart=/usr/bin/bitmagnet worker run --all
Environment=POSTGRES_HOST=localhost
Environment=POSTGRES_PASSWORD=postgres
Environment=TMDB_API_KEY=theTmdbKey
Restart=on-failure
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now bitmagnet-web.service
To ensure you bind to the VPN address, you may consider a complicated ExexStart as below.
[Unit]
Description=bitmagnet Web GUI
After=network-online.target
# Use whatever service your VPN runs as, though this is a bit unreliable
After=pia-vpn.service
Requires=pia-vpn.service
[Service]
Type=simple
User=root
Environment=POSTGRES_HOST=localhost
Environment=POSTGRES_PASSWORD=postgres
Environment=TMDB_API_KEY=theTmdbKey
# Instead of the normal start, wait 30 sec and bail if no VPN
# We're looking for "dev pia" so adjust as needed
#ExecStart=/usr/bin/bitmagnet worker run --all
ExecStart=/bin/sh -c '\
SECONDS=0; \
while [ $SECONDS -lt 30 ]; do \
VPN_IP=$(ip -4 addr show dev pia | awk '\''/inet / { split($2,a,"/"); print a[1] }'\''); \
[ -n "$VPN_IP" ] && break; \
sleep 1; \
done; \
if [ -z "$VPN_IP" ]; then \
echo "Could not get VPN IP on pia interface" >&2; exit 1; \
fi; \
echo "Starting client bound to IP $VPN_IP"; \
export BITMAGNET_DHT_BINDADDRESS=${VPN_IP}:6881 ; \
exec /usr/bin/bitmagnet worker run --all \
'
Restart=on-failure
[Install]
WantedBy=multi-user.target
3 - Players
3.1 - Audioserve
Audioserve is a web audiobook server with a minimalist design. It focuses on delivering audio based on the directory structure you’ve created, eschewing tags embedded in the audio files. Anyone who has worked with internet-sourced audio content will know wisdom of this approach.
Installation
Create an audioserve user and obtain the latest static binary and web client
sudo adduser --system --home /opt/audioserve --disabled-password --disabled-login audioserve
# Download the latest binary to a version folder and create a link for it.
cd /opt/audioserve/
wget -q -O - https://github.com/izderadicka/audioserve/releases/latest/download/audioserve_static.tar.gz | sudo tar xvz
sudo ln -s audioserve_static*/* audioserve
# Download the web-client.
# You'll have to check on the web at https://github.com/izderadicka/audioserve-web/releases/latest/ to see what the current relase is.
# and updat the VER variable accordingly (and check the sketchy nature of using this naming convention in a script)
VER=0.3.3
sudo mkdir /opt/audioserve/audioserve-web-release_v${VER}
cd /opt/audioserve/audioserve-web-release_v${VER}
wget -q -O - https://github.com/izderadicka/audioserve-web/releases/download/v${VER}/audioserve-web-release_v${VER}.tgz | sudo tar xvz
sudo ln -s /opt/audioserve/audioserve-web-release_v${VER} /opt/audioserve/web
Get a ffmpeg binary. Audioserve needs ffmpeg for transcoding media that clients cant directly play. The apt package is quite large, but you can download the static binary at a fraction of the size.
wget -q -O - https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-amd64-static.tar.xz | \
sudo tar -C /usr/local/bin -xvJ --strip-components 1 --wildcards "*ffmpeg" "*ffprobe"
Create a service script. This has the parameter no-authentication as we’ll be relying on a web server proxy to do that for us.
sudo vi /etc/systemd/system/audioserve.service
[Unit]
Description=Audioserve
[Service]
ExecStart=/opt/audioserve/audioserve --config /etc/audioserve.conf --no-authentication
User=audioserve
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable audioserve.service
Configuration
sudo vi /etc/audioserve.conf
behind_proxy: true
client_dir: /opt/audioserve/web
base_dirs:
- /some/place/where/your/audio/is
- /some/place/where/other/audio/is
Operation
Start the service and check it with:
sudo systemctl start audioserve.service
sudo systemctl status audioserve.service
sudo journalctl -u audioserve.service
You can access the web client on port 3000. It may display a banner about the lack of SSL but that is safe to ignore as you test it out. Having more than one base_dir in the config will populate a drop-down at the top. This is convenient if you have separated your library into genres, like Fantasy, Fiction, etc.
To display metadata, simply put image and text file in the folders alongside the audio files. In each folder, the first available image (jpeg or png) is taken as a cover/author picture and first text file (html, txt, md) is taken as description.
Proxy
A good choice is Caddy, and a config file with just these lines in it will work just fine - as long as you actually own the some.web.server domain. This will pop up a login box ala web basic auth and serve it up at the root of that DNS name.
caddy hash-password
sudo vi /etc/caddy/Caddyfile
(auth) {
basicauth {
you ABIGLONGHASHFromAbove
}
}
some.web.server {
import auth
reverse_proxy * http://localhost:3000
}
sudo caddy reload
After you have things working the way you want, you can disable direct access to audioserve by adding this to the config
listen: "127.0.0.1:3000"
Note: Securing the web client this way is more secure, but it prevents the android client from working. Workarounds with wireguard and such can be done but take additional setup.
Troubleshooting
# Launch it in the foreground to see the errors up close
/opt/audioserve/audioserve --no-authentication --config /etc/audioserve.conf
# Print out all the options
/opt/audioserve/audioserve --help
# Figure out what should be in a YAML file by specifiying all the options on the command line and then printing the config. Can be tricky
/opt/audioserve/audioserve --config /etc/audioserve.conf --no-authentication --print-config
If you decide not to proxy with a web server, you’ll want to:
- remove the
--no-authenticationparameter from the service unit file - and add
shared_secret: somePasswordand removebehind_proxyfrom the conf file
3.2 - Calibre-Web
There are a handful of solutions for web eBook delivery but Calibre-Web looks and works the best. It also integrates directly with the Calibre eBook management app.
Installation
This is a python app and that pip for installation. Pip is a bit heavy at 275M but even if you wanted to install Calibre-Web manually you still need pip, so let’s go for it. The successive packages in the brackets are optional, but may be of interest to you.
NOTE: for debian 12 and higher you must set up python venv as pip is unhappy mixing it’s repo with debian. You can’t just delete the /usr/lib/python3.11/EXTERNALLY-MANAGED as some of the required packages want write access.
sudo apt -y install python3-pip
sudo apt install python3-venv
# Optional override of IDs to match existing permissions
sudo groupadd --gid 1001 calibre-web
sudo adduser --uid 1001 --gid 1001 --disabled-password --home /opt/calibre-web calibre-web
sudo -i -u calibre-web
python3 -m venv .venv
source .venv/bin/activate
pip install calibreweb
pip install calibreweb[metadata]
pip install calibreweb[comics]
pip install calibreweb[comics]
pip install calibreweb[goodreads]
# You can change the shell to /usr/sbin/nologin now that we're done with pip
# sudo usermod -s /usr/sbin/nologin calibre-web
exit
sudo vi /etc/systemd/system/calibre-web.service
[Unit]
Description=Calibre-Web
[Service]
ExecStart=/opt/calibre-web/.venv/bin/cps
User=calibre-web
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now calibre-web.service
Migration
All the configuration settings are in the app.db file. You can install new and then copy that file.
scp /opt/calibre-web/.calibre-web/app.db some-other-server:
# On the other server
sudo mv app.db /opt/calibre-web/.calibre-web/app.db
sudo chown calibre-web:calibre-web /opt/calibre-web/.calibre-web/app.db
Operation
You can login with the default creds at
http://192.168.1.18:8083/ admin admin123
It will prompt you for the location of your Calibre database. If it’s writeable, you’ll be able to upload books and make edits from web app, but it’s not strictly required.
Change the admin password by:
Admin User Icon (top right) –> Password –> Save
If you proxy Calibre-Web and authenticate before you allow access, you may whish to allow anonymous browsing and reserve logins for admin access. You can enable that by:
Admin Dial Icon (top right) –> Edit Basic Configuration –> Feature Configuration –> Enable Anonymous Browsing
You can then return the the Admin screen and you’ll see Guest listed as a user. Select that user to turn on the various features. I recommend turn on all except Allow Edit. Selecting the the ‘show..’ selections on the left is best to show all the features.
3.3 - Jellyfin
Jellyfin is the best full-featured personal media server that doesn’t rely on the cloud. It allows for GPU acceleration without a paid subscription. (Looking at you, Plex.)
Preparation
Incus Container
In the Incus GUI, create a new Trixie instance and attach the GPU in the devices section. It will list the hardware available for selection.
System Account
Jellyfin can update and save metadata and artwork alongside the media files instead of in server itself. To get the permissions right, set user numeric IDs in advance by pre-creating the system account.
sudo apt install curl
sudo addgroup --gid 1001 jellyfin
sudo adduser --uid 1001 --gid 1001 --home /var/lib/jellyfin --comment "Jellyfin default user" --disabled-login --disabled-password jellyfin
Installation
curl https://repo.jellyfin.org/install-debuntu.sh | sudo bash
The full instructions are at:
https://jellyfin.org/docs/general/installation/linux
Acceleration
On linux, you can use VA-API or QSV, the latter being preferred1 for better performance. Since debian 13 only works with QSV, it’s an easy choice.
You need the intel-opencl-icd package and since it’s not in the Trixie repos right now, you’ll need to install it from Intel.
To quote the docs:
This package may not be available for newer distro since it currently relies on LLVM 14, which may not be in releases like Debian Trixie. If this is the case a release from the Intel compute-runtime repository may be used instead.
https://github.com/intel/compute-runtime/releases
The jellyfin installer will add the service account to the video group for you, so it should just work by selecting ‘Intel Quicksync (QSV)’ in the Playback -> Transcoding settings and ‘/dev/dri/renderD128’ under that.
Leave everything else at the defaults
On the host, install the GPU tools sudo apt install intel-gpu-tools and observe with sudo intel_gpu_top during a transcode.
Note: The Jellyfin docs may will lead you test VA-API too, without being clear you don’t need it anymore.
3.4 - LibreELEC
One of the best systems for a handling media is LibreELEC. It’s both a Kodi box and a server appliance that’s resistant to abuse. With the right hardware (like a ROCKPro64 or Waveshare) it also makes an excellent portable server for traveling.
Deployment
Download an image from https://libreelec.tv/downloads/ and flash as directed. Enable SSH during the initial setup.
Storage
RAID is a useful feature but only BTRFS works directly. This is fine, but with a little extra work you can add MergerFS, a popular option for combining disks.
BTRFS
Create the RAID set on another PC. If your disks are of different sizes you can use the ‘single’ profile, but leave the metadata mirrored.
sudo mkfs.btrfs -f -L pool -d single -m raid1 /dev/sda /dev/sdb /dev/etc...
After attaching to LibreELEC, the array will be automatically mounted at /media/pool based on label pool you specified above.
MergerFS
This is a good option if you just want to combine disks and unlike most other RAID technologies, if you loose a disk the rest will keep going. Many people combine this with SnapRAID for off-line parity.
But it’s a bit more work.
Cooling
You may want to manage the fan. The RockPro64 has a PWM fan header and LibreELEC loads the pwm_fan module.
Kodi Manual Start
The kodi process can use a significant amount of CPU even at rest. If you’re using this primarily as a file server you can disable kodi from starting automatically.
cp /usr/lib/systemd/system/kodi.service /storage/.config/system.d/kodi-alt.service
systemctl mask kodi
To start kodi, you can enter systemctl start kodi-alt
Remotes
Plug in a cheap Fm4 style remote and it ‘just works’ with kodi. But if you want to customize some remote buttons, say to start kodi manually, you still can.
Enable SMB
To share your media, simply copy the sample file, remove all the preconfigured shares (unless you want them), and add one for your storage pool. Then just enable Samba and reboot (so the file is picked up)
cp /storage/.config/samba.conf.sample /storage/.config/samba.conf
vi /storage/.config/samba.conf
[media]
path = /storage/pool
available = yes
browseable = yes
public = yes
writeable = yes
Config --> LibreELEC --> Services --> Enable Samba
Enable HotSpot
Config --> LibreELEC --> Network --> Wireless Networks
Enable Active and Wireless Access Point and it just works!
Enable Docker
This is a good way handle things like Jellyfin or Plex if you must. In the GUI, go to add-ons, search for the items below and install.
- docker
- LinuxServer.io
- Docker Image Updater
Then you must make sure the docker starts starts after the storage is up or the containers will see an empty folder instead of a mounted one.
vi /storage/.config/system.d/service.system.docker.service
[Unit]
...
...
After=network.target storage-pool.mount
If that fails, you can also tell docker to wait a bit
ExecStartPre=/usr/bin/sleep 120
Remote Management
You may be called upon to look at something remotely. Sadly, there’s no remote access to the GUI but you can use things like autossh to create a persistent remote tunnel, or wireguard to create a VPN connection. Wireguard is usually better.
3.4.1 - Add-ons
You can also use this platform as a server. This seems counter-intuitive at first; to use a media player OS as a server. But in practice it is rock-solid. I have a mixed fleet of 10 or so devices and LibreELEC has better uptime stats than TrueNAS.
The device playing content on your TV is also the media server for the rest of the house. I wouldn’t advertise this as an enterprise solution, but I can’t dispute the results.
Installation
Normal Add-ons
Common tools like rsync, as well as server software like Jellyfin are available. You can browse as descriped below, or use the search tool if you’re looking for something specific.
- Select the gear icon and choose Add-ons
- Choose LibreELEC Add-ons
- Drill down to browse software.
Docker
If you’re on ARM or want more frequent updates, you may want to add Docker and the LinuxServer.io repository.
- Select the gear icon and choose Add-ons
- Search add-ons for “Docker” and install
- Search add-ons for “LinuxServer.io” and install
- Select “Install from repository” and choose “LinuxServer.io’s Docker Add-ons”.
Drill down and add Jellyfin, for example.
3.4.2 - AutoSSH
This allows you to setup and monitor a remote tunnel as the easiest wat to manage remote clients is to let them come to you. To accomplish this, we’ll set up a server, create client keys, test a reverse tunnel, and setup autossh.
The Server
This is simply a server somewhere that everyone can reach via SSH. Create a normal user account with a password and home directory, such as with adduser remote. We will be connecting from our clients for initial setup with this.
The Client
Use SSH to connect to the LibreELEC client, generate a ssh key pair and copy it to the remote server
ssh [email protected]
ssh-keygen -f ~/.ssh/id_rsa -q -P ""
# ssh-copy-id isn't available so you must use the rather harder command below
cat ~/.ssh/id_rsa.pub | ssh -t [email protected] "cat - >> ~/.ssh/authorized_keys"
ssh [email protected]
If all went well you can back out and then test logging in with no password. Make sure to do this and accept the key so th
The Reverse Tunnel
SSH normally connects your terminal to a remote server. Think of this as a encrypted tunnel where your keystrokes are sent to the server and it’s responses are sent back to you. You can send more than your keystrokes, however. You can take any port on your system and send it as well In our case, we’ll take port 22 (where ssh just happens to be listening) and send it to the rendezvous server on port 2222. SSH will continue to accept local connections while also taking connections from the remote port we are tunneling in.
# On the client, issue this command to connect the (-R)remote port 2222 to localhost:22, i.e. the ssh server on the client
ssh -N -R 2222:localhost:22 -o ServerAliveInterval=240 -o ServerAliveCountMax=2 [email protected]
# Leave that running while you login to the rendezvois server and test if you can now ssh to the client by connecting to the forwarded port.
ssh [email protected]
ssh root@localhost -p 2222
# Now exit both and set up Autossh below
Autossh
Autossh is a daemon that monitors ssh sessions to make sure they’re up and operational, restarting them as needed, and this is exactly what we need to make sure the ssh session from the client stays up. To run this as a service, a systemd service file is needed. For LibreELEC, these are in /storage/.config.
vi /storage/.config/system.d/autossh.service
[Unit]
Description=autossh
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=root
EnvironmentFile=/storage/.config/autossh
ExecStart=/storage/.kodi/addons/virtual.system-tools/bin/autossh $SSH_OPTIONS
Restart=always
RestartSec=60
[Install]
WantedBy=multi-user.target
vi /storage/.config/autossh
AUTOSSH_POLL=60
AUTOSSH_FIRST_POLL=30
AUTOSSH_GATETIME=0
AUTOSSH_PORT=22034
SSH_OPTIONS="-N -R 2222:localhost:22 [email protected] -i /storage/.ssh/id_rsa"
systemctl enable autossh.service
systemctl start autossh.service
systemctl status autossh.service
At this point, the client has a SSH connection to your server on port 22, opened port 2222 the ssh server and forwarded that back to it’s own ssh server. You can now connect by:
ssh [email protected]
ssh root@localhost -p 2222
If not, check the logs for errors and try again.
journalctl -b 0 --no-pager | less
Remote Control
Now that you have the client connected, you can use your Rendezvous Server as a Jump Host to access things on the remote client such as it’s web interface and even the console via VNC. Your connection will generally take the form of:
ssh localport:libreelec:libreelec_port -J rendezvoisServer redevoisServer -p autosshPort
The actual command is hard to read as are going through the rendezvois server twice and connecting to localhost on the destination.
ssh -L 8080:localhost:32400 -J [email protected] root@localhost -p 2222
3.4.3 - Building
This works best in an Ubuntu container.
LibreELECT Notes
Installed but no sata hdd. Found this
RPi4 has zero support for PCIe devices so why is it “embarrasing” for LE to omit support for PCIe SATA things in our RPi4 image?
Feel free to send a pull-request to GitHub enabling the kernel config that’s needed.
https://forum.libreelec.tv/thread/27849-sata-controller-error/
Went though thier resouces beginners guid to git https://wiki.libreelec.tv/development/git-tutorial#forking-and-cloning building basics https://wiki.libreelec.tv/development/build-basics specific build commands https://wiki.libreelec.tv/development/build-commands/build-commands-le-12.0.x
and then failed because jammy wasn’t compatibile enough
Created a jammy container and restarted
https://ubuntu.com/server/docs/lxc-containers
sudo lxc-create –template download –name u1 ubuntu jammy amd64 sudo lxc-start –name u1 –daemon sudo lxc-attach u1
Used some of the notes from
https://www.artembutusov.com/libreelec-raid-support/
Did as fork, clone and a
git fetch –all
but couldnt get all the downloads as alsa.org site was down
On a side note, these are needed in the config.txt so that USB works
otg_mode=1,dtoverlay=dwc2,dr_mode=host
I tried a menuconfig and selected ..sata? and got
CONFIG_ATA=m < CONFIG_ATA_VERBOSE_ERROR=y < CONFIG_ATA_FORCE=y CONFIG_ATA_SFF=y CONFIG_ATA_BMDMA=y
Better compare the .config file again
Edited and commited a config.txt but it didn’t show up in the image. Possibly the wrong file or theres another way to realize that chagne
Enabled the SPI interface
https://raspberrypi.stackexchange.com/questions/48228/how-to-enable-spi-on-raspberry-pi-3 https://wiki.libreelec.tv/configuration/config_txt
sudo apt install lxc
# This didn't work for some reason
sudo lxc-create --template download --name u1 --dist ubuntu --release jammy --arch amd64
sudo lxc-create --template download --name u1
sudo lxc-start --name u1 --daemon
sudo lxc-attach u1
# Now inside, build
apt update
apt upgrade
apt-get install gcc make git wget
apt-get install bc patchutils bzip2 gawk gperf zip unzip lzop g++ default-jre u-boot-tools texinfo xfonts-utils xsltproc libncurses5-dev xz-utils
# login and fork so you can clone more easily. Some problem with the creds
cd
git clone https://github.com/agattis/LibreELEC.tv
cd LibreELEC.tv/
git fetch --all
git tag
git remote add upstream https://github.com/LibreELEC/LibreELEC.tv.git
git fetch --all
git checkout libreelec-12.0
git checkout -b CM4-AHCI-Add
PROJECT=RPi ARCH=aarch64 DEVICE=RPi4 tools/download-tool
ls
cat /etc/passwd
pwd
ls /home/
ls /home/ubuntu/
ls
cd ..
mv LibreELEC.tv/ /home/ubuntu/
cd /home/ubuntu/
ls -lah
chown -R ubuntu:ubuntu LibreELEC.tv/
ls -lah
cd LibreELEC.tv/
ls
ls -lah
cd
sudo -i -u ubuntu
ip a
cat /etc/resolv.conf
ip route
sudo -i -u ubuntu
apt install tmux
sudo -i -u ubuntu tmux a
# And back home you can write
ls -lah ls/u1/rootfs/home/ubuntu/LibreELEC.tv/target/
3.4.4 - Fancontrol
Add this to the /storage/bin and create a service unit.
vi /storage/.config/system.d/fancontrol.service
systemctl enable fancontrol
#!/bin/sh
# Summary
#
# Adjust fan speed by percentage when CPU/GPU is between user set
# Min and Max temperatures.
#
# Notes
#
# Temp can be gleaned from the sysfs termal_zone files and are in
# units millidegrees meaning a reading of 30000 is equal to 30.000 C
#
# Fan speed is read and controlled by he pwm_fan module and can be
# read and set from a sysfs file as well. The value can be set from 0 (off)
# to 255 (max). It defaults to 255 at start
## Set Points
# CPU Temp set points
MIN_TEMP=40 # Min desired CPU temp
MAX_TEMP=60 # Max desired CPU temp
# Fan Speeds set points
FAN_OFF=0 # Fan is off
FAN_MIN=38 # Some fans need a minimum of 15% to start from a dead stop.
FAN_MAX=255 # Max cycle for fan
# Frequency
CYCLE_FREQ=6 # How often should we check, in seconds
SHORT_CYCLE_PERCENT=20 # If we are shutting on or of more than this percent of the
# time, just run at min rather than shutting off
## Sensor and Control files
# CPU and GPU sysfs locations
CPU=/sys/class/thermal/thermal_zone0/temp
GPU=/sys/class/thermal/thermal_zone1/temp
# Fan Control files
FAN2=/sys/devices/platform/pwm-fan/hwmon/hwmon2/pwm1
FAN3=/sys/devices/platform/pwm-fan/hwmon/hwmon3/pwm1
## Logic
# The fan control file isn't available until the module loads and
# is unpredictable in path. Wait until it comes up
FAN=""
while [[ -z $FAN ]];do
[[ -f $FAN2 ]] && FAN=$FAN2
[[ -f $FAN3 ]] && FAN=$FAN3
[[ -z $FAN ]] && sleep 1
done
# The sensors are in millidegrees so adjust the user
# set points to the same units
MIN_TEMP=$(( $MIN_TEMP * 1000 ))
MAX_TEMP=$(( $MAX_TEMP * 1000 ))
# Short cycle detection requires us to track the number
# of on-off flips to cycles
CYCLES=0
FLIPS=0
while true; do
# Set TEMP to the highest GPU/CPU Temp
TEMP=""
read TEMP_CPU < $CPU
read TEMP_GPU < $GPU
[[ $TEMP_CPU -gt $TEMP_GPU ]] && TEMP=$TEMP_CPU || TEMP=$TEMP_GPU
# How many degress above or below our min threshold are we?
DEGREES=$(( $TEMP-$MIN_TEMP ))
# What percent of the range between min and max is that?
RANGE=$(( $MAX_TEMP-$MIN_TEMP ))
PERCENT=$(( (100*$DEGREES/$RANGE) ))
# What number between 0 and 255 is that percent?
FAN_SPEED=$(( (255*$PERCENT)/100 ))
# Override the calculated speed for some special cases
if [[ $FAN_SPEED -le $FAN_OFF ]]; then # Set anything 0 or less to 0
FAN_SPEED=$FAN_OFF
elif [[ $FAN_SPEED -lt $FAN_MIN ]]; then # Set anything below the min to min
FAN_SPEED=$FAN_MIN
elif [[ $FAN_SPEED -ge $FAN_MAX ]]; then # Set anything above the max to max
FAN_SPEED=$FAN_MAX
fi
# Did we just flip on or off?
read -r OLD_FAN_SPEED < $FAN
if ( ( [[ $OLD_FAN_SPEED -eq 0 ]] && [[ $FAN_SPEED -ne 0 ]] ) || \
( [[ $OLD_FAN_SPEED -ne 0 ]] && [[ $FAN_SPEED -eq 0 ]] ) ); then
FLIPS=$((FLIPS+1))
fi
# Every 10 cycles, check to see if we are short-cycling
CYCLES=$((CYCLES+1))
if [[ $CYCLES -ge 10 ]] && [[ ! $SHORT_CYCLING ]]; then
FLIP_PERCENT=$(( 100*$FLIPS/$CYCLES ))
if [[ $FLIP_PERCENT -gt $SHORT_CYCLE_PERCENT ]]; then
SHORT_CYCLING=1
echo "Short-cycling detected. Fan will run at min speed rather than shutting off."
else
CYCLES=0;FLIPS=0
fi
fi
# If we are short-cycling and would turn the fan off, just set to min
if [[ $SHORT_CYCLING ]] && [[ $FAN_SPEED -le $FAN_MIN ]]; then
FAN_SPEED=$FAN_MIN
fi
# Every so often, exit short cycle mode to see if conditions have changed
if [[ $SHORT_CYCLING ]] && [[ $CYCLES -gt 10000 ]]; then # Roughly half a day
echo "Exiting short-cycling"
SHORT_CYCLING=""
fi
# Write that to the fan speed control file
echo $FAN_SPEED > $FAN
# Log the stats everyone once in a while
# if [[ $LOG_CYCLES ]] && [[ $LOG_CYCLES -ge 10 ]]; then
# echo "Temp was $TEMP fan set to $FAN_SPEED"
# LOG_CYCLES=""
# else
# LOG_CYCLES=$(($LOG_CYCLES+1))
# fi
sleep $CYCLE_FREQ
done
# Also look at drive temps. The sysfs filesystem isn't useful for
# all drives on RockPro64 so use smartctl instead
#ls -1 /dev/sd? | xargs -n1 smartctl -A | egrep ^194 | awk '{print $4}'
3.4.5 - Hotspot
The Hotspot capability built-in to LibreELEC works, but is rudimentary. It’s primary use case is to allow an operator to authenticate through hotel network portals and such upstream of the device. It’s designed to be as widely compatible as possible, with the trade off of limited performance, especially with multiple clients.
You can instead deploy hostapd. This is the most widely used linux authentication and wireless access point software.
What follows are my rough notes from cobbling things together. I may come back and do it again and clean things up.
The Cobbling
Download hostapd and libnl to the folder /storage/.kodi/userdata/scripts. This location was recommended so it would get backed up.
wget http://mirror.archlinuxarm.org/aarch64/extra/hostapd-2.10-4-aarch64.pkg.tar.xz
wget http://mirror.archlinuxarm.org/aarch64/core/libnl-3.9.0-1-aarch64.pkg.tar.xz
# Extract and copy to the scripts folder
- hostapd
- libnl-3.so.200
- libnl-genl-3.so.200
export LD_LIBRARY_PATH=/storage/bin:$LD_LIBRARY_PATH
export PATH=/storage/bin:$PATH
# You'll also need dnsmasq to hand out IPs.
wget http://mirror.archlinuxarm.org/aarch64/extra/dnsmasq-2.90-1-aarch64.pkg.tar.xz
wget http://mirror.archlinuxarm.org/aarch64/core/libnetfilter_conntrack-1.0.9-2-aarch64.pkg.tar.xz
wget http://mirror.archlinuxarm.org/aarch64/extra/nftables-1:1.0.9-3-aarch64.pkg.tar.xz
cp /storage/test/usr/lib/libnftables.so.1 .
wget http://mirror.archlinuxarm.org/aarch64/core/libnfnetlink-1.0.2-2-aarch64.pkg.tar.xz
cp /storage/test/usr/lib/libnfnetlink.so.0 .
wget http://mirror.archlinuxarm.org/aarch64/core/libnftnl-1.2.6-1-aarch64.pkg.tar.xz
cp /storage/test/usr/lib/libnftnl.so.11 /storage/bin/
wget http://mirror.archlinuxarm.org/aarch64/core/jansson-2.14-4-aarch64.pkg.tar.xz
cp /storage/test/usr/lib/libjansson.so.4 /storage/bin/
wget http://mirror.archlinuxarm.org/aarch64/core/readline-8.2.010-1-aarch64.pkg.tar.xz
cp /storage/test/usr/lib/libreadline.so.8 /storage/bin/
wget http://mirror.archlinuxarm.org/aarch64/core/ncurses-6.5-3-aarch64.pkg.tar.xz
You’ll need a service for all this.
vi /storage/.config/system.d/router.service
[Unit]
Description = Router
After=sys-subsystem-net-devices-wlan0.device
Wants=sys-subsystem-net-devices-wlan0.device
[Service]
Environment=LD_LIBRARY_PATH=/storage/bin
Type=forking
WorkingDirectory=/storage/bin
ExecStart=/storage/bin/ap-up
ExecStop=killall hostapd
ExecStop=killall dnsmasq
[Install]
WantedBy=default.target
with a the script in bin of
#!/bin/bash
ip link set wlan0 down
ip addr flush dev wlan0
ip link set wlan0 up
ip addr add 10.0.0.1/24 dev wlan0
sleep 2
cd /storage/bin
pgrep dnsmasq || /storage/bin/dnsmasq --conf-file=/storage/bin/dnsmasq.conf --dhcp-leasefile=/storage/bin/dnsmasq.leases
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
sysctl -w net.ipv4.ip_forward=1
/storage/bin/hostapd -B /storage/bin/hostapd.conf
3.4.6 - MergerFS on LibreELEC
You’ll need to change up a but from the normal way of deploying. The process outlined here prevents disks from auto-mounting. Another strategy might be to create to ensure the mergerfs unit delays.
Prepare and Exempt Disks
Prepare and exempt the file systems from auto-mounting1 so you can supply your own mount options and make sure they are up before you start MergerFS.
# Format and label each disk the same
mkfs.ext4 /dev/sda
e2label /dev/sda pool-member
# Copy the udev rule for editing
cp /usr/lib/udev/rules.d/95-udevil-mount.rules /storage/.config/udev.rules.d
vi /storage/.config/udev.rules.d/95-udevil-mount.rules
Edit this section by adding the pool-member label from above
# check for special partitions we don't want to auto-mount
IMPORT{builtin}="blkid"
ENV{ID_FS_LABEL}=="EFI|BOOT|Recovery|RECOVERY|SETTINGS|boot|root0|share0|pool-member", GOTO="exit"
Test this by rebooting and making sure the drives are not mounted.
Add Systemd Mount Units
Each filesystem requires a mount unit like below. Create one for each drive named disk1, disk2, etc. Note: The name of the file is import and to mount /storage/disk1 the name of the file must be storage-disk1.mount
vi /storage/.config/system.d/storage-disk1.mount
[Unit]
Description=Mount sda
Requires=dev-sda.device
After=dev-sda.device
[Mount]
What=/dev/sda
Where=/storage/disk1
Type=ext4
Options=rw,noatime,nofail
[Install]
WantedBy=multi-user.target
systemctl enable --now storage-disk1.mount
Download and Test MergerFS
MergerFS isn’t available as an add-on, but you can get it directly from the developer. LibreELEC (or CoreELEC) on ARM have a 32 bit[^2] user space so you’ll need the armhf version.
wget https://github.com/trapexit/mergerfs/releases/latest/download/mergerfs-static-linux_armhf.tar.gz
tar --extract --file=./mergerfs-static-linux_armhf.tar.gz --strip-components=3 usr/local/bin/mergerfs
mkdir bin
mv mergerfs bin/
Mount the drives and run a test like below. Notice the escaped *. That’s needed at the command line to prevent shell globbing.
mkdir /storage/pool
/storage/bin/mergerfs /storage/disk\* /storage/pool/
Create the MergerFS Service
vi /storage/.config/system.d/mergerfs.service
[Unit]
Description = MergerFS Service
After=storage-disk1.mount storage-disk2.mount storage-disk3.mount storage-disk4.mount
Requires=storage-disk1.mount storage-disk2.mount storage-disk3.mount storage-disk4.mount
[Service]
Type=forking
ExecStart=/storage/bin/mergerfs -o category.create=mfs,noatime /storage/disk* /storage/pool/
ExecStop=umount /storage/pool
[Install]
WantedBy=default.target
systemctl enable --now mergerfs.service
Your content should now be available in /storage/pool after boot.
3.4.7 - Remotes
Most remotes just work. Newer ones emulate a keyboard and send well-known multimedia keys like ‘play’ and ‘volume up’. If you want to change what a button does, you can tell Kodi what to do pretty easily. In addition, LibreELEC also supports older remotes using eventlircd and popular ones are already configured. You can add unusual ones as well as get normal remotes to perform arbitrary actions when kodi isn’t running (like telling the computer to start kodi or shutdown cleanly).
Modern Remotes
If you plug in a remote receiver and the kernel makes reference to a keyboard you have a modern remote and Kodi will talk to it directly.
dmesg
input: BESCO KSL81P304 Keyboard as ...
hid-generic 0003:2571:4101.0001: input,hidraw0: USB HID v1.11 Keyboard ...
If you want to change a button action, put kodi into log mode, tail the logfile, and press the button in question to see what event is detected.
# Turn on debug
kodi-send -a toggledebug
# Tail the logfile
tail -f /storage/.kodi/temp/kodi.log
debug <general>: Keyboard: scancode: 0xac, sym: 0xac, unicode: 0x00, modifier: 0x0
debug <general>: HandleKey: browser_home (0xf0b6) pressed, window 10000, action is ActivateWindow(Home)
In this example, we pressed the ‘home’ button on the remote. That was detected as a keyboard press of the browser_home key. This is just one of many defined keys like ’email’ and ‘calculator’ that can be present on a keyboard. Kodi has a default action of that and you can see what it is in the system keymap
# View the system keyboard map to see what's happening by default
cat /usr/share/kodi/system/keymaps/keyboard.xml
To change what happens, create a user keymap. Any entries in it will override the default.
# Create a user keymap that takes you to 'Videos' instead of 'Home'
vi /storage/.kodi/userdata/keymaps/keyboard.xml
<keymap>
<global>
<keyboard>
<browser_home>ActivateWindow(Videos)</browser_home>
</keyboard>
</global>
</keymap>
kodi-send -a reloadkeymaps
Legacy Remotes
How They Work
Some receivers don’t send well-known keys. For these, there’s eventlircd. LibreELEC has a list of popular remotes that fall into this category and will dynamically use it as needed. For instance, pair an Amazon Fire TV remote and udev will fire, match a rule in /usr/lib/udev/rules.d/98-eventlircd.rules, and launch eventlircd with the buttons mapped in /etc/eventlircd.d/aftvsremote.evmap.
These will interface with Kodi using it’s “LIRC” (Linux Infrared Remote Contoll) interface. And just like with keyboards, there’s a set of well-known remote keys Kodi will accept. Some remotes don’t know about these so eventlircd does some pre-translation before relaying to Kodi. If you look in the aftvsremote.evmap file for example, you’ll see that KEY_HOMEPAGE = KEY_HOME.
To find out if your remote falls into this category, enable logging, tail the log, and if your remote has been picked up for handling by eventlircd you’ll see some entries like this.
debug <general>: LIRC: - NEW 66 0 KEY_HOME devinput (KEY_HOME)
debug <general>: HandleKey: percent (0x25) pressed, window 10000, action is PreviousMenu
In the first line, Kodi notes that it’s LIRC interface received a KEY_HOME button press. (Eventlircd actually translated it, but that happened before kodi saw anything.) In the second line, Kodi says it received the key ‘percent’, and preformed the action ‘Back’. The part where Kodi says ‘percent (0x25)’ was pressed seems resistent to documentation, but the action of PreviousMenu is the end result. The main question is why?
Turns out that Kodi has a pre-mapping file for events relayed to it from LIRC systems. There’s a mapping for ‘KEY_HOME’ that kodi translates to the well-known key ‘start’. Then Kodi checks the normal keymap file and ‘start’ translates to the Kodi action ‘Back’
Take a look at the system LIRC mapping file to see for yourself.
# The Lircmap file has the Kodi well-known button (start) surrounding the original remote command (KEY_HOME)
grep KEY_HOME /usr/share/kodi/system/Lircmap.xml
<start>KEY_HOME</start>
Then take a look at the normal mapping file to see how start get’s handled
# The keymap file has the well-known Kodi button surrounding the Kodi action,
grep start /usr/share/kodi/system/keymaps/remote.xml
<start>PreviousMenu</start>
You’ll actually see quite a few things are mapped to ‘start’ as it does different things depending on what part of Kodi you are accessing at the time.
Changing Button Mappings
You have a few options an they are listed here in increasing complexity. Specifically, you can
- Edit the keymap
- Edit the Lircmap and keymap
- Edit the eventlircd evmap
Edit the Keymap
To change what the KEY_HOME button does you can create a user keymap like before and override it. It just needs a changed from keyboard to remote for entering through the LIRC interface. In this example we’ve set it to actually take you home via the kodi function ActivateWindow(Home).
vi /storage/.kodi/userdata/keymaps/remote.xml
<keymap>
<global>
<remote>
<start>ActivateWindow(Home)</start>
</remote>
</global>
</keymap>
Edit the Lircmap and Keymap
This can occasionally cause problems though - such as when you have another button that already gets translated to start and you want it to keep working the same. In this case, you make an edit at the Lircmap level to translate KEY_HOME to some other button first, then map that button to the action you want. (You can’t put the Kodi function above in the Lircmap file so you have to do a double hop.)
First, let’s determine what the device name should be with the irw command.
irw
# Hit a button and the device name will be at the end
66 0 KEY_HOME devinput
Now let’s pick a key. My remote doesn’t have a ‘red’ key, so lets hijack that one. Note the device name devinput from the above.
vi /storage/.kodi/userdata/Lircmap.xml
<lircmap>
<remote device="devinput">
<red>KEY_HOME</red>
</remote>
</lircmap>
Then map the key restart kodi (the keymap reload command doesn’t handle Lircmap)
vi /storage/.kodi/userdata/keymaps/remote.xml
<keymap>
<global>
<remote>
<red>ActivateWindow(Home)</red>
</remote>
</global>
</keymap>
systemctl restart kodi
Edit the Eventlircd Evmap
You can also change what evenlircd does. If LibreELEC wasn’t a read-only filesystem you’d have done this first. But you can do it with a but more work than the above if you prefer.
# Copy the evmap files
cp -r /etc/eventlircd.d /storage/.config/
# Override where the daemon looks for it's configs
systemctl edit --full eventlircd
# change the ExecStart line to refer to the new location - add vvv to the end for more log info
ExecStart=/usr/sbin/eventlircd -f --evmap=/storage/.config/eventlircd.d --socket=/run/lirc/lircd -vvv
# Restart, replug the device and grep the logs to see what evmap is in use
systemctl restart eventlircd
journalctl | grep evmap
# Edit that map to change how home is mapped (yours may not use the default map)
vi /storage/.config/eventlircd.d/default.evmap
KEY_HOMEPAGE = KEY_HOME
Dealing With Unknown Buttons
Sometimes, you’ll have a button that does nothing at all.
debug <general>: LIRC: - NEW ac 0 KEY_HOMEPAGE devinput (KEY_HOMEPAGE)
debug <general>: HandleKey: 0 (0x0, obc255) pressed, window 10016, action is
In this example Kodi received the KEY_HOMEPAGE button, consulted it’s Lircmap.xml and didn’t find anything. This is because eventlircd didn’t recognize the remote and translate it to KEY_HOME like before. That’s OK, we can just add a user LIRC mapping. If you look through the system file you’ll see things like ‘KEY_HOME’ are tto the ‘start’ button. So let’s do the same.
vi /storage/.kodi/userdata/Lircmap.xml
<lircmap>
<remote device="devinput">
<start>KEY_HOMEPAGE</start>
</remote>
</lircmap>
systemctl restart kodi
Check the log and you’ll see that you now get
debug <general>: LIRC: - NEW ac 0 KEY_HOMEPAGE devinput (KEY_HOMEPAGE)
debug <general>: HandleKey: 251 (0xfb, obc4) pressed, window 10025, action is ActivateWindow(Home)
Remotes Outside Kodi
You may want a remote to work outside of kodi too - say because you want to start kodi with a remote button. If you have a modern remote that eventlircd didn’t capture, you must first add your remote to the list of udev rules.
Capture The Remote
First you must identify the remote with lsusb. It’s probably the only non-hub device listed.
lsusb
...
...
Bus 006 Device 002: ID 2571:4101 BESCO KSL81P304
^ ^
Vendor ID -------------/ \--------- Model ID
...
Then, copy the udev rule file and add a custom rule for your remote.
cp /usr/lib/udev/rules.d/98-eventlircd.rules /storage/.config/udev.rules.d/
vi /storage/.config/udev.rules.d/98-eventlircd.rules
...
...
...
ENV{ID_USB_INTERFACES}=="", IMPORT{builtin}="usb_id"
# Add the rule under the above line so the USB IDs are available.
# change the numbers to match the ID from lsusb
ENV{ID_VENDOR_ID}=="2571", ENV{ID_MODEL_ID}=="4101", \
ENV{eventlircd_enable}="true", \
ENV{eventlircd_evmap}="default.evmap"
...
Now, reboot, turn on logging and see what the buttons show up as. You can also install the system tools add-on in kodi, and at the command line, stop kodi and the eventlircd service, then run evtest and press some buttons. You should see something like
Testing ... (interrupt to exit)
Event: time 1710468265.112925, type 4 (EV_MSC), code 4 (MSC_SCAN), value c0223
Event: time 1710468265.112925, type 1 (EV_KEY), code 172 (KEY_HOMEPAGE), value 1
Event: time 1710468265.112925, -------------- SYN_REPORT ------------
Event: time 1710468265.200987, type 4 (EV_MSC), code 4 (MSC_SCAN), value c0223
Event: time 1710468265.200987, type 1 (EV_KEY), code 172 (KEY_HOMEPAGE), value 0
Event: time 1710468265.200987, -------------- SYN_REPORT ------------
Configure and Enable irexec
Now that you have seen the event, you must have the irexec process watching for it to take action. Luckily, LibreELEC already includes it.
vi /storage/.config/system.d/irexec.service
[Unit]
Description=IR Remote irexec config
After=eventlircd.service
Wants=eventlircd.service
[Service]
ExecStart=/usr/bin/irexec --daemon /storage/.lircrc
Type=forking
[Install]
WantedBy=multi-user.target
We’ll create a the config file next. The config is the command or script to run. systemctl start kodi in our case.
vi /storage/.lircrc
begin
prog = irexec
button = KEY_HOMEPAGE
config = systemctl start kodi
end
Let’s enable and start it up
systemctl enable --now irexec
Go ahead and stop kodi, then press the KEY_HOMEPAGE button on your remote. Try config entries like echo start kodi > /storage/test-results if you have issues and wonder if it’s running.
Notes
You may notice that eventlircd is always running, even if it has no remotes. That’s of a unit file is in /usr/lib/systemd/system/multi-user.target.wants/. I’m not sure of why this is the case when there is no remote in play.
3.5 - Plex
Plex is the preeminent personal media server. While they’ve locked some features behind a subscription and are branching out into cloud providers, it remains a solid choice. They have clients for a lot of different Tablets and TVs, and importantly make connecting your family to your home videos easy.
Installation
Plex has jumped on the pipe-to-shell installation method and you can now run this to install.
curl -LsSf https://repo.plex.tv/scripts/setupRepo.sh | sudo bash
This sets up the repo and installation you’d have done manually in the past.
Configuration
Unattended Upgrades
To allow unattended updates of plex, install the unattended upgrade package and a site to the Origins-Pattern section.
Note: The Plex installer may be doing this already at this point, but I’ve left this hear just in case.
sudo apt -y install unattended-upgrades
sudo vi /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Origins-Pattern {
...
...
"site=downloads.plex.tv";
};
Authorized IPs
Most private ranges are automatically granted access, but you may need to adjust.
sudo vim "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Preferences.xml"
... allowedNetworks="192.168.1.0/24" ...
Metadata Library
The metadata library can get very large. Many tens of gigabytes in some cases. So you may wish to relocate it for space or even security reasons.
sudo service stop plexmediaserver
sudo mv /var/lib/plexmediaserver /mnt/crypt
sudo ln -s /mnt/crypt/plexmediaserver /var/lib/plexmediaserver
sudo chown plex:plex /var/lib/plexmediaserver
Firewall Access
If you’re using Ubuntu and have UFW running, adjust as below.
sudo vim /etc/ufw/applications.d/plexmediaserver
[plexmediaserver]
title=Plex Media Server
description=Plex Media Server is the back-end media server component of Plex
ports=32400/tcp
# Add custom rules as needed
sudo ufw allow from xxx.xxx.xx.0/23 to any app plexmediaserver
sudo ufw deny from xxx.xxx.0.0/16 to any app plexmediaserver
sudo ufw allow plexmediaserver
Hardware Transcoding
Operation
Command Line Control
You can kick off scans via the command line, but you have to invoke the commands as the plex user.
#!/bin/bash
sudo su -c "export LD_LIBRARY_PATH=/usr/lib/plexmediaserver;/usr/lib/plexmediaserver/Plex\ Media\ Scanner --scan" plex
You can also just become the plex user, of course, if it’s not too awkward
sudo -i -u plex
/usr/lib/plexmediaserver/Plex\ Media\ Scanner --list --section 1
Searching for mis-matches in the DB
When you have a large collection, it becomes almost impossible to find where some items land at. You can however, search the database
sudo apt install sqllite3
sqlite3 "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Plug-in Support/Databases/com.plexapp.plugins.library.db"
select media_item_id,file from media_parts where file like "%Kid Party E07E01.mkv%";
select metadata_item_id,hints from media_items where id=1011881;
select title from metadata_items where id=173491;
Or for a complex join
SELECT
metadata_items.title,media_parts.file
FROM
metadata_items
JOIN media_parts JOIN media_items
WHERE
metadata_items.library_section_id=1
AND
metadata_items.id=media_items.metadata_item_id
AND
media_items.id=media_parts.media_item_id
AND
media_parts.file LIKE "%Kid Party E07E01.mkv%";
Checking the Logs
tail -f /var/lib/plexmediaserver/Library/Application\ Support/Plex\ Media\ Server/Logs/Plex\ Media\ Server.log
Sources
Database info: https://forums.plex.tv/t/howto-query-data-from-plex-on-a-mac/11636