Skip to content

2025

Virtual Switch with systemd-networkd

They call it a bridge, but I like to call it a virtual switch: Linux bridges are a really interesting concept I've come across recently.

Here was the use case: Through wifi interface wlp3s0 my laptop (archlinux btw) was connected to a network that had internet access. Had I enabled the default network interface in virt-manager the guest windows machine would get access to the internet: you all know what happens when windows gets internet access; it downloads updates and forces you to update. So I didn't want the guest windows vm to access the internet, but I did want it to access my IP camera network which wasn't connected to the internet. My laptop was connected to this network via ethernet —this means my laptop ethernet interface enp5s0 had a LAN IP address assigned to it just like the other client cameras in the network. I wanted the windows guest vm to access this network so I could install the software that could initialize my IP cameras (SmartPSS, SmartPSS Lite, and ODM: Onvif Device Manager): 3 of the cameras needed this software for configuration but the other 3 had a convenient web interface. Still, I'm not complaining because when there is good old Linux on your side you can always find a way .

The solution here is to use a Linux bridge (or a "virtual switch"). This setup turns our ethernet interface into an ethernet port on a switch. The ethernet port on a switch doesn't have its own ip address like the ethernet interface does, the port just links you to the things connected on other port.

In this case the connection to the ethernet port just puts two more devices in the network: br0 and the VM's virtual interface.

┌─────────────────────────────────────┐
│           br0 (Virtual Switch)      │
│  ┌─────────────────────────────────┐│
│  │ Port 1: enp5s0 (Physical)      ││ ← Connected to 10.0.0.0/24 network
│  │ Port 2: VM's virtual interface ││ ← Your Windows VM will connect here
│  │ Port 3: Host's br0 interface   ││ ← Your host's network access
│  └─────────────────────────────────┘│
└─────────────────────────────────────┘

The config files that make it happen (if you've ever worked with systemd before you'd be familiar with the /etc/systemd/system directory where you usually place .service files)

/etc/systemd/network/br0.netdev
1
2
3
[NetDev]
Name=br0
Kind=bridge
/etc/systemd/network/br0.network
1
2
3
4
5
[Match]
Name=br0

[Network]
DHCP=yes

DHCP=yes

Our bridge interface will automatically get an IP addressed assigned to it by the DHCP server running on 10.0.0.1

/etc/systemd/network/enp5s0.network
1
2
3
4
5
6
7
[Match]
Name=enp5s0

[Network]
Bridge=br0
DHCP=no
IPForward=yes

With all this in place, once you execute sudo systemctl restart systemd-networkd you should see a new br0 interface in the output of ip addr command. However, you might also see that enp5s0 interfaces gets an IP address too —this isn't what we expected since enp5s0 is now just a "port" or replaced by a new br0 interface. When enp5s0 has an ip address you might find that you can't ping other devices on the IP camera network.

I found out that it was dhcpcd.service that was assigning an IP address to enp5s0. To prevent it from getting an address I did:

sudo nvim /etc/dhcpcd.conf

Add this line at the top or bottom of the file:

denyinterfaces enp5s0

Restart dhcpcd:

sudo systemctl restart dhcpcd

Flush the Current IP and Restart systemd-networkd:

# Remove the current IP from enp5s0
sudo ip addr flush dev enp5s0

# Restart systemd-networkd to properly configure the bridge
sudo systemctl restart systemd-networkd

Now enp5s0 has no IP address and now it no longer interferes with connecting to other devices on the network.

Warcraft III on Arch Linux

Download ElAmigos Repack: https://1337x.to/torrent/3130265/Warcraft-III-Complete-Edition-MULTi6/

unrar x Warcraft.III.Complete.Edition.MULTi6.rar
cd Warcraft.III.Complete.Edition.MULTi6
sudo mount -o loop IGG-Warcraft.III.Complete.Edition.MULTi6.iso /mnt

Now paste this lutris script somewhere. It was adapted from here: https://lutris.net/games/warcraft-iii-reign-of-chaos/,https://lutris.net/games/install/19676/view

war3.yml
name: Warcraft III - Reign of Chaos
game_slug: warcraft-iii-reign-of-chaos
runner: wine
version: ElAmigos Repack
slug: warcraft-iii-reign-of-chaos-elamigos
script:
  files:
  - mod: https://github.com/legluondunet/MyLittleLutrisScripts/raw/master/Warcraft%20III%20-%20Reign%20of%20Chaos/RenderEdge_Widescreen.mix
  - script: https://github.com/legluondunet/MyLittleLutrisScripts/raw/master/Warcraft%20III%20-%20Reign%20of%20Chaos/resolution.sh
  - reg_file: https://github.com/legluondunet/MyLittleLutrisScripts/raw/master/Warcraft%20III%20-%20Reign%20of%20Chaos/warcraft_iii_cd_utf8.reg
  game:
    args: -opengl -window
    exe: drive_c/Games/WarCraft III/Warcraft III.exe
    prefix: $GAMEDIR
  installer:
  - task:
      arch: win64
      name: create_prefix
      prefix: $GAMEDIR
  - task:
      app: baekmuk arial lavfilters
      name: winetricks
      prefix: $GAMEDIR
  - insert-disc:
      requires: reign.ico
  - task:
      description: Installing Warcraft III (ElAmigos Repack)...
      executable: $DISC/setup.exe
      name: wineexec
  - merge:
      dst: $GAMEDIR/drive_c/Program Files (x86)/Warcraft III
      src: reg_file
  - chmodx: script
  - execute:
      args: $RESOLUTION_WIDTH $RESOLUTION_HEIGHT
      file: script
  - task:
      filename: $GAMEDIR/drive_c/Games/WarCraft III/warcraft_iii_cd_utf8.reg
      name: set_regedit_file
  - copy:
      dst: $GAMEDIR/drive_c/Games/WarCraft III
      src: mod
  system:
    env:
      MESA_LOADER_DRIVER_OVERRIDE: zink
    gamescope: false
    gamescope_fps_limiter: '60'
    gamescope_game_res: 1920x1080
    gamescope_output_res: 1920x1080
  wine:
    dxvk: false

Now in lutris: Add > Install from a local script and point it to that lutris script file.

Rest just follow the installation wizard.

GTA San Andreas on Arch Linux

Get the iso

Find the latest best place to torrent from here: https://www.reddit.com/r/Piracy/wiki/megathread/all_purpose/

I can confirm GTA-San-Andreas-HOODLUM-Plus-SAMP-Multiplayer from https://1337x.to works.

Install Lutris

Info

Enable multilib in /etc/pacman.conf first by uncommenting:

[multilib]
Include = /etc/pacman.d/mirrorlist

How to install lutris instructions were clearly laid out by İbrahim Korucuoğlu at https://www.siberoloji.com/how-to-install-and-use-lutris-on-arch-linux. I'm just reproducing the steps here:

sudo pacman -S mesa lib32-mesa vulkan-radeon lib32-vulkan-radeon
# For Nvidia
# sudo pacman -S nvidia nvidia-utils lib32-nvidia-utils
# For Intel
# sudo pacman -S mesa lib32-mesa vulkan-intel lib32-vulkan-intel
# For AMD
sudo pacman -S mesa lib32-mesa vulkan-radeon lib32-vulkan-radeon
sudo pacman -S vulkan-tools
vulkaninfo | less
sudo pacman -S lutris
sudo pacman -S wine wine-gecko wine-mono
sudo pacman -S lib32-gnutls lib32-libldap lib32-mpg123 lib32-openal lib32-v4l-utils lib32-libpulse lib32-alsa-plugins lib32-libxcomposite lib32-libxinerama lib32-ncurses lib32-libxml2 lib32-freetype2 lib32-libpng lib32-sdl2
sudo pacman -S winetricks
paru -S dxvk-bin

Install proton-ce-custom from aur

paru -S proton-ge-custom

Configure Lutris

Update 2025-05-25

I went with proton-ge-custom because of the recommendation that appeared in lutris. But system wine had better performance and significantly faster startup time. You can skip this section if you go with.

1750839104.png

1750709603.png

Preferences > Runners > Wine

Select proton-ge-custom.

1750709643.png

Mount the downloaded iso

sudo mount -o loop Grand\ Theft\ Auto\ \(GTA\)\ San\ Andreas-HOODLUM/hlm-gtasa.iso /mnt

Visit https://lutris.net/games/grand-theft-auto-san-andreas/ and press the Install button. This will open some dialog in Lutris. Go through the steps and point to the /mnt/setup.exe file.

Hit yes and proceed through the install. It will take a while. You'll know when its done, the red Abort button will go away and it will show Success.

Chromium Flags

If you're on wayland you might want to configure chrome to use xorg/xwayland. There seems to be some issue switching between Lutris (that uses xorg backend) and chrome on wayland.

> chrome://flags/
    > Preferred Ozone Platform
        > X11

Transcribe videos with google colab and openai whisper

Google colab provides powerful GPUs with 12G of VRAM even at free tier. I foud this very useful to first generate srt files of chinese youtube videos and then translate the chinese srt files into english srt files.

Sample yt-dlp command to download video

# proxy, cookies, format and output name are not compulsory.
yt-dlp --proxy socks5://localhost:1080/ --cookies /tmp/cookies.txt -f "bestvideo[height=720]+bestaudio" 'https://www.youtube.com/watch?v=XlmWtg4ksaw' -o '藏南的诅咒:困死在喜马拉雅南坡的印度'

Sample ffmpeg command to extract audio from video

ffmpeg -i input.webm -vn -acodec libmp3lame -ab 192k output.mp3

First visit https://colab.research.google.com/

File
    > New notebook in Drive

Set the runtime type

Runtime
    > Change runtime type

Select python3 as interpreter and t4 gpu as hardware accelator

1749154186.png

Each code bock below is inserted by pressing the +Code button in the UI first and then entering the text. Lines that beings with ! is run in the os shell environment, while the rest are run in the selected interpreter (here python3). After typing in each code blocks, press the run button:

1749139785.png

The codeblocks (run in sequence)

!pip install openai-whisper
from google.colab import files
uploaded = files.upload() # (1)
  1. Click on Choose Files, navigate to and select file.
filename = list(uploaded.keys())[0]
print(f"Uploaded file: {filename}")
import os
os.environ['FNAME'] = filename
!whisper "$FNAME" --output_format srt --language zh --model turbo

Note

Replace zh with the spoken language in the uploaded audio file

filename_without_ext = os.path.splitext(os.environ['FNAME'])[0]
files.download(f"{filename_without_ext}.srt")

Note

  1. The generated srt file has the same name but different srt as extension.

Translate with google translate

At https://translate.google.com, in Documents tab you see that google only supports .docx, .pdf, .pptx, .xlsx.

1749152901.png

To work around this limitation, use libreoffice.

libreoffice --convert-to "docx:MS Word 2007 XML" output.srt

This creates output.docx. Get it translated at google translate and download the resulting docx. Convert it back with

libreoffice --convert-to "txt:Text" output-eng.docx

Rename this file to your "video name.srt" and you're good to go!

Configuration management with mkdocs and pymdownx.snippets

I believe this is a better way to manage your config files than uploading them to github. With this approach all you need to do is sync your configs file into the config folder within the root of your mkdocs site. They can easily be embedded as snippets in markdown files with appropriate syntax highlighting and contents of these config files also turn up in site search.

Here's an example:

$ mkdocs new vectorspace.xyz
$ cd vectorspace.xyz
$ nvim mkdocs.yml # (1)
$ mkdir configs
$ cp ~/.zshrc configs/
$ nvim docs/index.md # (2)
  1. look down further for mkdocs.yml
  2. look down further for index.md
mkdocs.yml
1
2
3
site_name: My Docs
markdown_extensions:
  - pymdownx.snippets # (1)
  1. For pydownx extension, you need to install python-pymdown-extensions on archlinux
docs/index.md
# Welcome to MkDocs

For full documentation visit [mkdocs.org](https://www.mkdocs.org).

## Commands

* `mkdocs new [dir-name]` - Create a new project.
* `mkdocs serve` - Start the live-reloading docs server.
* `mkdocs build` - Build the documentation site.
* `mkdocs -h` - Print help message and exit.

## Project layout

    mkdocs.yml    # The configuration file.
    docs/
        index.md  # The documentation homepage.
        ...       # Other markdown pages, images and other files.

```zsh
--8<-- "configs/.zshrc"
```

Here I've just added:

```zsh
--8<-- "configs/.zshrc"
```

... to the end of the autogenerated docs/index.md file when you first create a site. Check the results of this by:

# Inside the directory that contains the mkdocs.yml file
mkdocs serve -a 127.0.0.1:9000

see the results for yourself at 127.0.0.1:9000

pydownx is just one of the many awesome extensions developed by github id facelessuser. Check out more at their site: https://facelessuser.github.io/pymdown-extensions/