Skip to content

maxkagamine/dotfiles

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

maxkagamine's dotfiles

bash  |  git  |  wsl  |  unraid  |  mkvtoolnix  | ⚙ misc utils  |  sweetroll  |  more…

Behold, GNU Stow: the mod manager for your Linux home directory! Anyone who's used Vortex or MO2 to mod games like Skyrim will find this familiar: mod (dot) files are organized into separate folders, and the mod manager (stow) combines them into the game (home) directory using symlinks.

As Stow doesn't (yet) support pre/post-install hooks, I'm emulating it by placing Makefiles in the mod directories and including them from the main Makefile. This keeps mods self-contained with any needed package install steps etc., and also allows mods to depend on other mods, with Make automatically figuring out which mods need to be installed and in what order:

Dependency graph

Best part about this setup is it doesn't require any dotfile-specific frameworks or YAML files. Just run make.

Notable mods (headers link to the relevant file/directory):

Applies the convention of loading configuration files from a directory to bashrc: after setting some common aliases and such, sources every file in ~/.config/bashrc.d/. This way the other mods can put their stuff in e.g. bashrc.d/git.sh rather than one big file as is traditional. (The system-wide /etc/profile already does this with /etc/profile.d/*.)

(Psst: if you want to change your ls colors, my file might be an easier starting-off point than --print-database. I spent the time formatting it so you don't have to.)

Git aliases and aliases (including my favorite: the alias alias, git alias) + the "gg" function I use so much I wrote an article about it, and of course what would be a Max Kagamine system without a myriad of Skyrim references (brace yourself).

Oh and empty string is git status:

Mukashi mukashi (Once upon a time)...
git status is too long,” Max thought as he sat at his desk.
So with the magic of git config --global, it became git s.
...But that was too long.
So he aliased it to gs in his bashrc; just two letters, see?
But these two, too, were too long!
So he dropped the 's', just g, now, short as can be.
But even one letter 'twas one letter too long!
And so it became, the shortest git status of all:
Empty string!

True story. This is a trick I learned a long time ago: using PROMPT_COMMAND (or a precmd hook) to compare the last history entry to that which was seen the previous time the prompt was shown, as hitting enter at an empty prompt will run the prompt command again, but the last history number will be the same. Side effect is hitting Ctrl+C (but not Ctrl+U or Alt+Shift+#) at a prompt will trigger git status, too.

Also, check out git-branch-fzf, my awesome fzf-powered interactive branch switcher with keyboard shortcuts to toggle remote branches, delete branches (including remote and even the current branch!), and to fetch the latest of a branch before switching.

wsl

For "Tamriel," my main machine running the Windows Subsystem for Linux, because I can't computer without a command line but also can't not Windows.

This Alt+V keybind to paste Windows paths as Linux paths should be useful to any WSL users. unclip is an alias for xsel -bo, for which I've written a WSL shim (less janky than using PowerShell for this), which lets commands like npx serve that aren't WSL-aware copy things to your Windows clipboard.

Using Yubikey for GPG & SSH in WSL

In the past, I was using wsl2-ssh-pageant which uses socat to replace the gpg-agent socket with one that runs an exe that bridges Gpg4win. The bridge itself worked well (with a small fix), but despite my best efforts I could never get the socket shenanigans to work reliably.

In the end that was too much of a hassle, so I switched to using usbipd-win which connects the Yubikey directly to Linux. So far, this has proved much simpler. The downside is that connecting a device to WSL means disconnecting it from Windows; if you need the Yubikey to log into a website, you'll have to temporarily detach it from WSL.

  1. Install WSL USB Manager.
    • This will install usbipd-win & WSL dependencies automatically. (If on first run you get an error about the usbipd wsl command being removed, exit WSL USB Manager from the system tray and restart it to make it realize you have the new version.)
    • Move the shortcut from %appdata%\Microsoft\Windows\Start Menu\Programs into Startup so it runs at login.
  2. Right click on the Yubikey in the device list (should say "Smartcard Reader") and Attach to WSL. The Yubikey should show up now if you run lsusb in WSL. (Arch users: sudo pacman -S usbutils)
  3. Right click again and choose "Auto-Attach Device", then "Device".
  4. Ubuntu users: sudo apt install scdaemon (Arch users can skip this, as it's included in the gnupg package.)
  5. If you run gpg --card-status now in WSL, it'll give you an error that says "gpg: selecting card failed: No such device" unless you run gpg as root. This has to do with the permissions of the usb device in /dev. There are two ways to fix this:
    • What was working for me until I tried upgrading to Ubuntu 24.04 ("noble") was to install pcscd in addition to scdaemon. This is a separate daemon that handles communication with smartcards. Ubuntu 24.04 however introduced some kind of security policy change that broke it. Incidentally, this was the final straw that got me to finally switch to Arch, so unfortunately I don't have a solution. It might work for you, but I suggest trying the below first; you may not need pcscd at all:
    • Add a udev rule to fix the device permissions:
      1. Check the Yubikey's vendor & product numbers in lsusb (the part after "ID").
      2. You can see the current permissions using ls -l /dev/bus/usb/<bus id>/<device id>.
      3. sudo nano /lib/udev/rules.d/yubikey.rules and add the following, substituting in your Yubikey's vendor & product numbers and your username:
        SUBSYSTEM=="usb", ATTR{idVendor}=="1050", ATTR{idProduct}=="0406", MODE="666", OWNER="max", GROUP="max"
        
        Note: I found different versions of this online, but setting all three of those was what finally worked for me. If you want to dig into the udev syntax, see Writing udev rules and udev(7).
      4. Unplug the Yubikey and plug it back in, or detach & re-attach from WSL USB Manager.
      5. gpg --card-status should work without root now. Run the ls again to confirm the new permissions (check lsusb again, as the device ID may have changed).
  6. Set SSH_AUTH_SOCK and GPG_TTY in your .bashrc as shown here.
  7. Add enable-ssh-support to ~/.gnupg/gpg-agent.conf
  8. Add Match host * exec "gpg-connect-agent updatestartuptty /bye" to ~/.ssh/config
    • Explanation for why updatestartuptty is necessary here; running it via ssh config comes from this answer. Supposedly GPG_TTY is enough, but for whatever reason on my machine that only worked for gpg signing and not the ssh agent ¯\_(ツ)_/¯
    • Note: Without a GUI pinentry program, some Git features in VSCode (like auto-fetch) won't work until you've unlocked the card in a terminal (e.g. by running git fetch yourself).
  9. Assuming you've added your GPG key as an SSH key in GitHub (gpg --export-ssh-key <key id>), ssh git@github.com should work now!

Setting up Arch in WSL

  1. Download the ArchWSL zip, extract to %localappdata%\Arch (or wherever), and run the exe
  2. Set the root password, create your own user, add it to the wheel group, and set its password:
    # passwd
    # useradd -m -G wheel -s /bin/bash max
    # passwd max
    
    Fun fact: I looked up the origin of the "wheel" name. It comes from "big wheel" which is an older way of saying "head honcho." According to Ngram the phrase had a surgence in popularity in the late 40s through the 50s. So the term "wheel" is basically 1960s-programmer slang for "Administrator." The more you know!
  3. EDITOR=nano visudo and uncomment the %wheel line towards the bottom to allow admins to sudo.
    • The reason we're not adding a sudoers.d file here like the ArchWSL setup guide suggests is we want to be able to override this with our own sudoers file, but they're evaluated in lexigraphical order and we don't want a file starting with "w" overriding us. Sudoers files should also always be edited using visudo.
  4. Exit out of WSL and Arch.exe config --default-user max.
  5. Initialize the pacman keyring (this is the last step from the setup guide; everything after this is custom):
    $ sudo pacman-key --init
    $ sudo pacman-key --populate
    $ sudo pacman -Sy archlinux-keyring
    $ sudo pacman -Su
    
  6. Consider changing the default pacman mirror: https://archlinux.org/mirrorlist/
    • This seemed to help with the timeout issue (and overall download speed), but it might be a good idea to set XferCommand to enable retries as shown here once the segfault bug in pacman 6.1 is fixed.
    • Take note: not all of the mirrors listed here are trustworthy. Stick to the universities.
  7. Fix the Yubikey's device permissions so GPG can access it without root (explained above):
    $ sudo pacman -S usbutils # Installs lsusb
    $ lsusb # Confirm yubikey's vendor & product numbers
    $ sudo nano /lib/udev/rules.d/yubikey.rules
    SUBSYSTEM=="usb", ATTR{idVendor}=="1050", ATTR{idProduct}=="0406", MODE="666", OWNER="max", GROUP="max"
    $ gpg --card-status # Should work now without root after detaching & re-attaching the Yubikey
    
  8. Import public keys:
    $ curl https://github.com/maxkagamine.gpg | gpg --import -
    $ curl https://github.com/web-flow.gpg | gpg --import -
    
    One-liner to set the trust for all keys to "ultimate":
    $ gpg --list-keys --fingerprint --keyid-format long | sed -En '/fingerprint/{s/.*=|\s+//g;s/$/:6:/;p}' | gpg --import-ownertrust
    
  9. Install the bare minimum needed packages:
    $ sudo pacman -S base-devel git
    
  10. Clone using HTTP first, since we need to dotfiles to set up GPG as the SSH agent:
$ mkdir Projects && cd Projects
$ git clone https://github.com/maxkagamine/dotfiles.git
$ cd dotfiles
$ rm ~/.bash_profile ~/.bashrc
$ make
  1. Check that SSH works now, and then switch the repo to SSH:
    $ . ~/.bashrc  # No .r alias yet
    $ gpg-connect-agent reloadagent /bye
    $ ssh git@github.com
    $ git remote set-url origin git@github.com:maxkagamine/dotfiles.git
    
  2. Hooray!

unraid

For "Sovngarde," my NAS. There isn't much in this mod (just a CDPATH and a function to list/monitor files on the array that are being accessed), but if you're running Unraid as well, see How to install GNU Stow on Unraid. Here's my user script, set to run on array start, if it happens to be useful:

cat /boot/config/plugins/user.scripts/scripts/install_dotfiles/script
#!/bin/bash
#name=Install dotfiles
#description=&lpar;Re&rpar;clone & install dotfiles.
#argumentDescription=Branch
#argumentDefault=master
#clearLog=true
set -eo pipefail

export PATH="/usr/local/bin:$PATH"
export HOME=/root

DOTFILES_DIR=~/dotfiles
BRANCH=${1:-master}

# Nuke existing dotfiles
rm -rfv ~/.bashrc ~/.bash_profile "$DOTFILES_DIR"

# Clean up symlinks
find ~ -xtype l -exec rm -v -- {} +
find ~ -depth -type d -empty -exec rmdir -v -- {} \;

# Clone repo
git clone -b "$BRANCH" https://github.com/maxkagamine/dotfiles.git "$DOTFILES_DIR"

# Install
cd "$DOTFILES_DIR"
make

Also take a look at:

Tools for batch remuxing MKVs using mkvtoolnix: mkv-ls shows tracks in a table similar to the GUI but groups identical track listings for batch processing with mkv-batch.

For example, if I wanted to keep only the Japanese audio and remove the Signs & Songs tracks from everything except the "Another Epilogue" special (which mkv-ls shows has different tracks):

(The escaped filenames in gray are for copy/pasting into the mkv-batch command, but for screenshot purposes I used the !() glob syntax instead.)

Additional tools:

  • mkv-cat — Concatenates the input MKVs, adding chapters for each file.
  • mkv-extract-subs — Batch extracts all subtitles from the given MKVs.
  • mkv-extract-fonts — Batch extracts all unique fonts (by filename) from the given MKVs.
  • mkv-rm-cover — Removes all image/jpeg and image/png attachments from the given MKVs.
  • mkv-clean — Removes the title and video track name (both used occasionally just to advertise the encoding group), cover image (some groups plaster the series cover on every episode), and common Windows system fonts (which are often unnecessarily included with subs and do nothing but waste space) from the given MKVs.

Miscellaneous utilities:

  • append-crc — Adds (or updates) a file's crc32 hash to its filename.
  • cron-wrapper — Wrapper script for cronjobs that prevents multiple instances, handles logging, and triggers a notification on error. Used for pull-from-seedbox and another script that runs yt-dlp to backup YouTube playlists.
  • flatten - Flattens the contents of a directory such that "foo/bar/file.jpg" is renamed to "foo - bar - file.jpg", with an optional prefix/suffix added to the filenames.
  • intersect-csvs — Creates CSVs containing only rows that exist in two or more of the given CSVs. For example, given A.csv, B.csv, and C.csv, creates A+B.csv, A+C.csv, B+C.csv, and A+B+C.csv. I used this to create a map of arcades in Tokyo that have my favorite games.
  • mkanimedir — Turns a MAL link and a bunch of episodes into a nice folder.
  • mkmoviedir — Like mkanimedir but for an IMDb link.
  • upscale — Wrapper for several AI image upscalers, with options for automatic batch processing.
  • weigh — Shows the total size of files, directories, or stdin (optionally gzipped).

I need to ask you to stop. That... committing... is making people nervous.

In case you missed it: Nuke a git repo with unrelenting force: the FUS RO DAH command

Fancy keyboard shortcuts (also powers the aforementioned git-branch-fzf)

Contains a convert-to-srgb script I created to help deal with color profile issues when working with certain images. For each input image, if it contains a non-sRGB color profile, extracts the profile with exiftool (as imagemagick sometimes fails to recognize embedded ICC profiles) and converts it to sRGB. Used by ugoira-to-mp4.

Because nothing on the Internet is guaranteed to be there tomorrow.