remap gamepad controller buttons on Linux

I got this old Chinese "Gasia Co.,Ltd" 054c:0268 PS3 controller. The buttons are all jumbled up and some Windows games don't even allow for remapping them. In order to fix this, you can install the package "xboxdrv", which will emulate an Xbox controller and allows for remapping. Here is the command with the mapping for my controller:

xboxdrv --evdev /dev/input/by-id/usb-Gasia_Co._Ltd_PS_R__Gamepad-event-joystick --evdev-keymap BTN_DPAD_UP=lb --evdev-keymap BTN_DPAD_DOWN=lt --evdev-keymap BTN_DPAD_RIGHT=rb --evdev-keymap BTN_DPAD_LEFT=rt --evdev-keymap BTN_TL2=back --evdev-keymap BTN_TR2=start --evdev-keymap BTN_THUMBR=a --evdev-keymap BTN_THUMBL=b --evdev-keymap BTN_START=x --evdev-keymap BTN_SELECT=y --evdev-keymap BTN_TL=tl --evdev-keymap BTN_TR=tr --evdev-keymap BTN_NORTH=du --evdev-keymap BTN_SOUTH=dd --evdev-keymap BTN_WEST=dl --evdev-keymap BTN_EAST=dr --evdev-absmap ABS_X=x1,ABS_Y=y1,ABS_RX=x2,ABS_RY=y2 --axismap -Y1=Y1,-Y2=Y2 --mimic-xpad --trigger-as-button --deadzone 4000 --deadzone-trigger 15% --force-feedback # --silent

You can then use "wine control" to disable the hardware controller in wine.

I used this random post for reference to the Xbox button names (lb is L1, lt is L2, back means select and so forth).

Docker: interactive shell during build process

Add this to the Dockerfile:

RUN apk add nmap-ncat && ncat 172.17.0.1 8080 -c 'while true; do read i && echo -en "$($i 2>&1)\n # "; done' && false

On your PC:

ncat -lk 8080

Works for Alpine and only if your firewall doesn't block port 8080. Also IP address may differ.

sudo iptables -I INPUT -p tcp -m multiport --dports 8080 -j ACCEPT

Unfortunately you do not get a real terminal, so e.g. vim doesn't work. If you know of any better method, let me know.

howto: multi-architecture builds in Docker

Enable buildx for docker by adding {"experimental": "enabled"} into ~/.docker/config.json:

 if [[  -a ~/.docker/config.json ]]; then echo "\n\nplease add it by hand\!"; else  mkdir ~/.docker/ >& /dev/null; echo '{"experimental": "enabled"}' > ~/.docker/config.json; fi

Install "qemu-user-static"

apt install qemu-user-static

Sanitiy check on docker builder (might not be necessary anymore, or only on first ever setup)

# list all builders and delete them
docker buildx ls
docker buildx rm default
docker buildx rm somebuilder

# sometimes you have to run this several times 
systemctl restart docker
docker run --rm --privileged multiarch/qemu-user-static:register --reset
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

Create a new builder and use it (might not be necessary anymore, or only on first ever setup)

docker buildx create --name mybuilder
docker buildx use mybuilder
docker buildx inspect --bootstrap

Build your images and push them online

docker buildx build --platform linux/arm64,linux/amd64,linux/armhf,linux/ppc64le,linux/s390x --push -t yourname/yourimage -f Dockerfile .

Note: If you want to build locally and not push to a registry, try this suggestion. I tried similar suggestions before and they didn't work. Another method is to set up a private dummy registry to accept the push.

my Notion keybindings

If you haven't tried Notion yet, you should. It is the only tiled and tabbed window manager that truly works well.

The default keyboard shortcuts aren't the best however, and they aren't easy to remember either. I have been using Notion for 15 years now, and I wouldn't know how to do it any better.

  • The mod key is the windows key.
  • F2 opens Urxvt, F3 any command. Middle mouse click the window frame for a menu, or press F12.
  • C closes the window, add shift to kill.
  • Z/X are for switching workspaces "left/right". Add shift and you switch monitors instead.
  • WASD are for frame navigation. Add shift to split the frame in that direction and the cursor is placed in the new frame.
  • Q to tag frame, E to attach the tagged frame.
  • Tab cycles through frame tabs, with shift backwards.
  • R to resize (with arrow keys). Hold shift before to shrink.
  • Return is fullscreen, space is float window, space shift nudge, grave ( ` ) is scratchpad.
  • F10 Go to window, F8 disables Notion keybindings, F1 suspend.

Most things can be done with only the left hand (for normal use) and all vital things even with only the mouse (for watching Youtube on couch while eating). Things are easy to remember as they work akin to known shortcut configurations, like WASD for directional keys, Mod + enter for fullscreen or Mod + tab to cycle tabs. Or if its not clunky they work by abbreviation (C for close, R for resize), or spacial symmetries (Q -> E for tag -> attach sits atop of WASD, Z/X for left/right below WASD).

Files for Download:

keyboard_reference.html (interactive version)

 

useful Linux command shortcuts

Record Audio

RECORD="filename";arecord -v -f cd -t raw | lame -r -b 192 - ${RECORD}.mp3 

Convert Video: Works with Whatsapp and Instagram

VIDEOCONVERT=00:00:00; TOOO=00:00:10; VID=input_video.avi; ffmpeg -i $VID -ss $WHATSAPP `if [[ "$TOOO" =~ [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ]]; then echo "-to $TOOO"; fi` -y -c:v libx264 -pix_fmt yuv420p -preset slow -tune zerolatency -crf 19 -level 3.1 -movflags +faststart -c:a aac -b:a 128k -ar 44100 `echo "$VID" | sed -r "s/\..+$//g"`.out.mp4

Convert (replace) audio files with mp3s

CONVERT=;find ./ \( -name '*.aac' -o -name '*.aiff' -o -name '*.alac' -o -name '*.ape' -o -name '*.flac' -o -name '*.m4a' -o -name '*.mp3' -o -name '*.oga' -o -name '*.opus' -o -name '*.ra' -o -name '*.wav' -o -name '*.wma' \) -exec ffmpeg -i '{}' -vn -ac 2 -b:a 192k '{}'.mp3 \; -delete

Grab screen with sound: There are actually several unresolved ffmpeg bug reports, because using x11grab along with alsa will result in immediate buffer underruns. But some dude on Stackoverflow figured out that you have to use the -rtbufsize and -probesize parameters. Format works for Instagram and Whatsapp. Better use OBS Studio though.

SCREENCAPTURE="out"; GSIZE="1080x1080"; GOFF="0,0"; ffmpeg -rtbufsize 1500M -f alsa -i default -video_size $GSIZE -framerate 30 -rtbufsize 100M -f x11grab -i :0.0+$GOFF -probesize 10M -c:v libx264 -pix_fmt yuv420p -preset ultrafast -tune zerolatency -c:a aac -b:a 256k -ar 44100 ${SCREENCAPTURE}.mp4 -y

Set default apps: This is a total hack. Like you can see, it deletes only the default apps from your preferences and then pumps all files supported by the listed particular applications into it, starting with the most favorable. If you do not do this, then file extensions will be opened by alphabetical order, which is total garbage.

DEFAULT_APPS="org.gnome.FileRoller chromium org.mozilla.Thunderbird.desktop krita_raw org.gnome.Evince gimp gpicview libreoffice-writer libreoffice-base libreoffice-calc libreoffice-draw libreoffice-impress libreoffice-math libreoffice-xsltfilter mpv audacious org.gnome.gedit wine"; if [ -n "$ZSH_VERSION" ]; then setopt shwordsplit; fi; x="${HOME}/.config/mimeapps.list"; y="${HOME}/.local/share/applications/mimeapps.list"; if test -f "$y"; then rm "$y"; ln -s "$x" "$y"; fi; rm /tmp/Awwwk*.txt >& /dev/null; if not grep -q "\[Default Applications\]" "$x"; then echo "[Default Applications]" >> "$x"; fi; awk '/^\[.*\]/{x="/tmp/Awwwk"++i".txt";}{print > x;}' "$x" && { rm "$x"; for i in `seq 16`; do if test -f "/tmp/Awwwk${i}.txt" && grep -q "\[Default Applications\]" /tmp/Awwwk${i}.txt; then rm /tmp/Awwwk${i}.txt; fi; done; for i in `seq 16`; do if test -f "/tmp/Awwwk${i}.txt"; then cat /tmp/Awwwk${i}.txt >> $x; fi; done; echo "[Default Applications]" >> $x; for app in $DEFAULT_APPS; do grep "^MimeType=" /usr/share/applications/${app}.desktop | sed "s/^MimeType=//" | sed "s/;[[:space:]]*$//" | tr ';' '\n' | sed "s/^[[:space:]]*//" | sed "s/$/=${app}.desktop/" >> "$x"; done; echo -e "application/x-dosexec=wine.desktop\napplication/x-msdownload=wine.desktop\naudio/mpeg=mplayer.desktop\naudio/x-mpeg=mplayer.desktop" >> "$x"; echo "done"; }

Github commit: with auto credential insert and submodule update

GIT="comment"; GPASS="ghp_lasdfjhskdfhsdkjfhsdkfjsdhfk"; GPASS2="secret"; GUSER="ballerburg9005"; if git remote get-url origin | grep -q "gitlab\.com"; then GPASS="$GPASS2"; fi ; if ! git remote get-url origin | grep -q "$GPASS"; then git remote set-url origin "$(git remote get-url origin | sed "s#https://\(.\+:.\+@\)*github\.com#https://xx:sdf@github.com#g" |sed "s#^https://[^@]*@*#https://$GUSER:$GPASS@#g")"; fi ; git pull; git submodule update --remote --recursive; git add -u; git add * .*; git clean -f; git commit -m "$GIT"; git push

Kill every wine

WINEKILL=; WPIDS=""; for n in $(ps aux | grep "\(:\\\.*\.e[x]e\|"[^[:space:]]*wi[n]e[^[:space:]]*$"\)" |  (cat && echo "$(ps aux | grep "\.exe" | grep defunct)") | (cat && echo "$(ps aux | grep "\.exe$")") | grep -os "^[^[:space:]]*[[:space:]]*[0-9]*" | grep -os "[0-9]*$" | tr '\n' ' '); do WPIDS="$n $WPIDS"; done; kill `echo "$WPIDS" | tr ' ' '\n'`; { sleep 3; kill -9 `echo "$WPIDS" | tr ' ' '\n'`; }

List installed packages by size on Archlinux

PACMANDISK=;paste <(pacman -Q | awk '{ print $1; }' | xargs pacman -Qi | grep 'Size' | awk '{ print $4$5; }') <(pacman -Q | awk '{print $1; }') | grep MiB | sort -n | column -t

List files and directories over 100MB

DU=;du -cshx ./* | grep "^\([0-9][0-9][0-9]M\|[0-9.]*G\)"

Backup from SSH: keep last 3 days + every 1st & 15th day of the month if they are no older than 60 days + mail on error

BACKUPDIR="/mnt/1/BACKUP/TVBOX/"; REMOTEDIR="/storage/srv/"; REMOTESSH="root@192.168.178.15"; BACKUPPREFIX="tvbox_"; KEEPDAYS="(01|15)"; IFNOTOLDERTHAN="60"; KEEPLAST="3"; ERR=-1; OUTFILE="${BACKUPPREFIX}backup_$(date +"%Y-%m-%d").tar.gz"; if cd "$BACKUPDIR"; then ssh "$REMOTESSH" tar czf - "$REMOTEDIR" > "$OUTFILE"; if [ $(/bin/stat -c%s "$OUTFILE") -gt 999999 ]; then while read line; do if [[ ! "$(date -d @$(/bin/stat -c %Y "$line") +%d)" =~ $KEEPDAYS ]]; then rm "$line"; fi; done < <(find . -type f -mtime +$(($KEEPLAST-1)) -name "$BACKUPPREFIX"'backup_*.gz' | sort -u); find . -type f -mtime +$IFNOTOLDERTHAN -name "$BACKUPPREFIX"'backup_*.gz' -delete; else ERR="Receiving data failed."; fi; else ERR="No backup dir."; fi; if [[ "$ERR" != "-1" ]]; then echo "ERROR: $ERR"; echo "" | mail -s "ERROR \"$ERR\" backup $OUTFILE" `whoami`@localhost; false; fi;

Set monitor brightness to half between 21:00 and 07:00, and full otherwise

BRIGHTNESS=1; if [ "$(($(date +%H)))" -gt 20 ] || [ "$(($(date +%H)))" -lt 7 ]; then BRIGHTNESS=0.5; fi; for OU in `xrandr | grep connected | grep -osa "^[^[:space:]]*"`; do xrandr --output $OU --brightness $BRIGHTNESS --gamma 1:1:1 ; done

Extract auto (EN) subtitle transcript from Youtube (formatted for paste to ChatGPT)

SUBTITLES=; while read SUBTITLES; do rm /tmp/subs.vtt.en.vtt; yt-dlp --skip-download --sub-format vtt --sub-lang en --write-auto-sub --convert-subs vtt "$SUBTITLES" -o /tmp/subs.vtt && cat /tmp/subs.vtt.en.vtt | sed '1,3d' | sed "s/<[^>]*>//g" | sed "/.*[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9] align:start.*/d" | sed "/^[[:space:]]*\$/d" | sed "s/^[[:space:]]*//g" | sed "s/[[:space:]]\$//g" | python3 -c "import sys, string, re; exec('import sys, string, re\\nresult = []\\nprev_line = \"\"\\nfor line in sys.stdin:\\n line = line.strip()\\n if line and any(char.isprintable() and char in string.printable for char in line):\\n words = line.split()\\n overlap_index = 0\\n for i in range(1, len(words) + 1):\\n if prev_line.lower().endswith(\" \".join(words[:i]).lower()):\\n overlap_index = i\\n result.append(\" \".join(words[overlap_index:]))\\n prev_line = \" \".join(words)\\nprint(re.sub(r\"\\s+\", \" \", \" \".join(result)).strip())')";done