├── .config ├── sxiv ├── yt-dlp │ └── config ├── wget │ └── wgetrc ├── python │ └── pythonrc ├── pinentry │ └── preexec ├── pulse │ └── daemon.conf ├── lf │ ├── cleaner │ ├── icons │ └── scope ├── latexmk │ └── latexmkrc ├── pipewire │ └── pipewire.conf.d │ │ └── user-session.conf ├── locale.conf ├── youtube-dl │ └── config ├── shell │ ├── inputrc │ ├── bm-dirs │ ├── bm-files │ ├── aliasrc │ └── profile ├── gtk-3.0 │ └── settings.ini ├── user-dirs.dirs ├── gtk-2.0 │ └── gtkrc-2.0 ├── fontconfig │ └── conf.d │ │ ├── 10-no-sub-pixel.conf │ │ ├── 30-metric-aliases.conf │ │ ├── 40-fonts.conf │ │ ├── 20-symbols.conf │ │ └── 10-powerline-symbols.conf ├── nvim │ └── auto_fcitx.vim ├── x11 │ ├── keyboard_layouts │ ├── xinitrc │ ├── xprofile │ └── xresources ├── nsxiv │ └── exec │ │ ├── image-info │ │ └── key-handler ├── i3 │ ├── nadeshiko.conf │ └── ws10.json ├── mpd │ └── mpd.conf ├── ncmpcpp │ ├── bindings │ └── config ├── mpv │ └── input.conf ├── zathura │ └── zathurarc ├── i3blocks │ └── config ├── git │ └── config ├── firefox │ └── larbs.js ├── redshift.conf ├── newsboat │ └── config ├── rofi │ └── config.rasi ├── alacritty │ └── alacritty.toml └── mimeapps.list ├── .local ├── bin │ ├── sxiv │ ├── dmenu │ ├── xdg-terminal-exec │ ├── trympv │ ├── i3cmds │ │ ├── dropdowncalc │ │ ├── winresize │ │ ├── toggletouchpad │ │ ├── ducksearch │ │ ├── somesearch │ │ ├── ddspawn │ │ └── hover │ ├── pulsemixer-default-source │ ├── tsp_onfinish │ ├── statusbar │ │ ├── sb-cpu_freq │ │ ├── sb-headphone-plug │ │ ├── sb-mpdup │ │ ├── sb-load_average │ │ ├── sb-brightness │ │ ├── sb-tasks │ │ ├── sb-mailbox │ │ ├── sb-pacpackages │ │ ├── sb-calendar │ │ ├── sb-chip_temp │ │ ├── sb-torrent │ │ ├── sb-moonphase │ │ ├── sb-popupgrade │ │ ├── sb-music │ │ ├── sb-cpubars │ │ ├── sb-disk │ │ ├── sb-internet │ │ ├── sb-pulsevol │ │ ├── sb-nettraf │ │ ├── sb-memory │ │ ├── sb-battery │ │ ├── sb-ticker │ │ ├── sb-cpu_usage │ │ ├── sb-price │ │ └── sb-local_ipaddr │ ├── remapd │ ├── getkeys │ ├── podentr │ ├── showclip │ ├── dmenupass │ ├── fingerbox │ ├── curlwttr │ ├── getcomproot │ ├── camtoggle │ ├── queueandnotify │ ├── pauseallmpv │ ├── ifinstalled │ ├── opout │ ├── qndl │ ├── td-toggle │ ├── lmc │ ├── fftemp │ ├── rssadd │ ├── listmarks │ ├── dmenuunicode │ ├── lfub │ ├── archnews │ ├── lf-select │ ├── dmenumountcifs │ ├── setbg │ ├── sd │ ├── unmounter │ ├── remaps │ ├── lf-file-op │ ├── qolibri-mpv │ ├── weath │ ├── rotdir │ ├── tag │ ├── termcolors │ ├── dmenuhandler │ ├── bookmarkctl │ ├── booksplit │ ├── otp │ ├── sysact │ ├── getbib │ ├── linkhandler │ ├── noisereduce │ ├── compiler │ ├── rankspellings │ ├── shortcuts │ ├── maimocr │ ├── rank-nitter-instances │ ├── rank-invidious-instances │ ├── rssget │ ├── mounter │ ├── slider │ └── local-pronunciations └── share │ ├── larbs │ ├── ttymaps.kmap │ └── getkeys │ │ ├── calcurse │ │ ├── nsxiv │ │ ├── zathura │ │ ├── ncmpcpp │ │ ├── newsboat │ │ └── mutt │ ├── icons │ └── fingerbox.png │ └── applications │ ├── dmenuunicode.desktop │ ├── newsboat-rss-add.desktop │ ├── neomutt.desktop │ ├── vwebp.desktop │ ├── syncthing.desktop │ ├── displayselect.desktop │ ├── tv_asahi.desktop │ ├── tv_tokyo.desktop │ ├── tv_news24.desktop │ ├── tv_tokyomx.desktop │ ├── linkhandler.desktop │ ├── lf.desktop │ ├── tv_utako.desktop │ ├── anki.desktop │ ├── mozc-config.desktop │ ├── nvim.desktop │ ├── firefox-temp.desktop │ └── firefox.desktop ├── .zprofile ├── .gtkrc-2.0 ├── .github └── FUNDING.yml ├── .gitignore ├── .gitmodules └── README.md /.config/sxiv: -------------------------------------------------------------------------------- 1 | nsxiv -------------------------------------------------------------------------------- /.local/bin/sxiv: -------------------------------------------------------------------------------- 1 | /usr/bin/nsxiv -------------------------------------------------------------------------------- /.zprofile: -------------------------------------------------------------------------------- 1 | .config/shell/profile -------------------------------------------------------------------------------- /.gtkrc-2.0: -------------------------------------------------------------------------------- 1 | .config/gtk-2.0/gtkrc-2.0 -------------------------------------------------------------------------------- /.config/yt-dlp/config: -------------------------------------------------------------------------------- 1 | ../youtube-dl/config -------------------------------------------------------------------------------- /.config/wget/wgetrc: -------------------------------------------------------------------------------- 1 | hsts-file=~/.cache/wget-hsts 2 | -------------------------------------------------------------------------------- /.local/bin/dmenu: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rofi -dmenu -i "$@" 3 | -------------------------------------------------------------------------------- /.local/bin/xdg-terminal-exec: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | "$TERMINAL" -e "$@" 4 | -------------------------------------------------------------------------------- /.local/share/larbs/ttymaps.kmap: -------------------------------------------------------------------------------- 1 | keycode 1 = Caps_Lock 2 | keycode 58 = Escape 3 | -------------------------------------------------------------------------------- /.local/bin/trympv: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mpv -quiet -- "$@" || "${BROWSER:-firefox}" -- "$@" 4 | -------------------------------------------------------------------------------- /.config/python/pythonrc: -------------------------------------------------------------------------------- 1 | import readline 2 | readline.write_history_file = lambda *args: None 3 | -------------------------------------------------------------------------------- /.local/bin/i3cmds/dropdowncalc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ifinstalled bc && echo "Welcome to the Calculator." && bc -lq 4 | -------------------------------------------------------------------------------- /.local/share/icons/fingerbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tatsumoto-ren/dotfiles/HEAD/.local/share/icons/fingerbox.png -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: https://tatsumoto.neocities.org/blog/donating-to-tatsumoto.html 4 | -------------------------------------------------------------------------------- /.local/share/applications/dmenuunicode.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=dmenu unicode 4 | Exec=dmenuunicode 5 | Icon=face-sad 6 | -------------------------------------------------------------------------------- /.local/share/applications/newsboat-rss-add.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=RSS feed addition 4 | Exec=/usr/bin/env rssadd %U 5 | -------------------------------------------------------------------------------- /.local/bin/i3cmds/winresize: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | echo "📐" | dmenu -p "Give width and height:" | xargs xdotool windowsize "$(xdotool getwindowfocus)" 3 | -------------------------------------------------------------------------------- /.local/bin/pulsemixer-default-source: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pulsemixer --list-sources | 4 | awk -F':|,' '/, Default$/ { print $3; exit; }' | 5 | sed 's/^\s*//g; s/\s*$//g' 6 | -------------------------------------------------------------------------------- /.local/bin/tsp_onfinish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh 2 | 3 | # The arguments passed are: jobid errorlevel output_filename command 4 | 5 | notify-send "Job $1 finished with status $2" "$4" 6 | -------------------------------------------------------------------------------- /.local/share/applications/neomutt.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=Neomutt 4 | GenericName=Mail Client 5 | Exec=i3-sensible-terminal -e neomutt %u 6 | Icon=evolution 7 | -------------------------------------------------------------------------------- /.local/share/applications/vwebp.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Version=1.0 4 | Type=Application 5 | NoDisplay=true 6 | Exec=vwebp -info -mt -- %f 7 | Name=vwebp 8 | Comment=vwebp 9 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-cpu_freq: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh -e 2 | 3 | grep -F MHz /proc/cpuinfo | cut -d: -f2 | awk ' 4 | { 5 | sum+=$0 6 | } 7 | END { 8 | printf "GHz %.2f\n", sum / FNR / 1000 9 | }' 10 | -------------------------------------------------------------------------------- /.local/share/applications/syncthing.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Syncthing 3 | GenericName=Syncthing 4 | Comment=Syncthing 5 | Exec=syncthing 6 | Type=Application 7 | Icon=syncthing-gtk 8 | Categories=Network; 9 | -------------------------------------------------------------------------------- /.local/bin/remapd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Rerun the remaps script whenever a new input device is added. 4 | 5 | while :; do 6 | remaps 7 | grep -qP -m1 '[^un]bind.+\/[^:]+\(usb\)' <(udevadm monitor -u -t seat -s input -s usb) 8 | done 9 | -------------------------------------------------------------------------------- /.config/pinentry/preexec: -------------------------------------------------------------------------------- 1 | #!/hint/sh 2 | 3 | # Define additional functionality for pinentry. For example 4 | test -e /usr/lib/libgcr-base-3.so.1 && exec /usr/bin/pinentry-gnome3 "$@" 5 | #test -e /usr/lib/libQt5Widgets.so.5 && exec /usr/bin/pinentry-qt "$@" 6 | -------------------------------------------------------------------------------- /.config/pulse/daemon.conf: -------------------------------------------------------------------------------- 1 | # Never exit pulseaudio if idle. This is to deal with an issue of Chromium 2 | # browsers not properly starting Pulseaudio by themselves. When the underlying 3 | # issue is solved, this file/directory should be removed. 4 | exit-idle-time = -1 5 | -------------------------------------------------------------------------------- /.local/bin/getkeys: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cat "${XDG_DATA_HOME:-$HOME/.local/share}"/larbs/getkeys/"$1" 2>/dev/null && exit 4 | echo "Run command with one of the following arguments for info about that program:" 5 | ls "${XDG_DATA_HOME:-$HOME/.local/share}"/larbs/getkeys 6 | -------------------------------------------------------------------------------- /.local/bin/i3cmds/toggletouchpad: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # Toggle touchpad. Requires xf86-input-synaptics. 3 | (synclient | grep "TouchpadOff.*1" && synclient TouchpadOff=0)>/dev/null && echo "TouchPad reactivated." && exit 4 | synclient TouchpadOff=1 && echo "TouchPad deactivated." 5 | -------------------------------------------------------------------------------- /.local/bin/podentr: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # entr command to run `queueandnotify` when newsboat queue is changed 4 | 5 | [ "$(pgrep -x "$(basename "$0")" | wc -l)" -gt 2 ] && exit 6 | 7 | echo "${XDG_DATA_HOME:-$HOME/.local/share}"/newsboat/queue | entr -p queueandnotify 2>/dev/null 8 | -------------------------------------------------------------------------------- /.local/share/applications/displayselect.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=Display Select 4 | Comment=Select Display 5 | GenericName=Settings 6 | Icon=utilities-terminal 7 | Exec=displayselect 8 | Categories=ConsoleOnly;System; 9 | MimeType=inode/directory; 10 | -------------------------------------------------------------------------------- /.config/lf/cleaner: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # https://github.com/jstkdng/ueberzugpp/blob/master/scripts/lf/cleaner 4 | #ueberzugpp cmd -s "$UB_SOCKET" -a remove -i PREVIEW 5 | 6 | if [ -n "$FIFO_UEBERZUG" ]; then 7 | printf '{"action": "remove", "identifier": "PREVIEW"}\n' > "$FIFO_UEBERZUG" 8 | fi 9 | -------------------------------------------------------------------------------- /.config/latexmk/latexmkrc: -------------------------------------------------------------------------------- 1 | $bibtex_use = 1.5; 2 | $cleanup_includes_cusdep_generated = 1; 3 | $cleanup_includes_generated = 1; 4 | $out_dir = "out"; 5 | $pdf_mode = 5; 6 | $silent = 1; 7 | 8 | # SyncTeX 9 | push(@generated_exts, ("synctex.*")); 10 | push(@extra_xelatex_options, '-synctex=1') ; 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local or machine-specific shell aliases 2 | /.config/shell/localrc 3 | # Machine-specific icc profiles 4 | /.local/share/icc 5 | # Various firefox profiles 6 | /.local/share/applications/firefox-* 7 | # Everyone has their own bookmarks 8 | /.config/newsboat/urls 9 | 10 | # Cache 11 | mimeinfo.cache 12 | -------------------------------------------------------------------------------- /.local/share/applications/tv_asahi.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Type=Application 4 | Exec=mpv "https://mov3.co/ja/tvasahi/" 5 | Name=テレビ朝日 6 | GenericName=TV Asahi 7 | Comment=Watch TV 8 | Icon=mpv 9 | Terminal=false 10 | StartupNotify=true 11 | Categories=Video;Player;TV; 12 | StartupWMClass=mpv 13 | -------------------------------------------------------------------------------- /.local/share/applications/tv_tokyo.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Type=Application 4 | Exec=mpv "https://mov3.co/en/tvtokyo/" 5 | Name=テレビ東京 6 | GenericName=TV Tokyo 7 | Comment=Watch TV 8 | Icon=mpv 9 | Terminal=false 10 | StartupNotify=true 11 | Categories=Video;Player;TV; 12 | StartupWMClass=mpv 13 | -------------------------------------------------------------------------------- /.local/share/applications/tv_news24.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Type=Application 4 | Exec=mpv "https://www.news24.jp/" 5 | Name=日テレNEWS24 6 | GenericName=NEWS24 7 | Comment=Watch the news 8 | Icon=mpv 9 | Terminal=false 10 | StartupNotify=true 11 | Categories=Video;Player;TV; 12 | StartupWMClass=mpv 13 | -------------------------------------------------------------------------------- /.local/share/applications/tv_tokyomx.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Type=Application 4 | Exec=mpv "https://mov3.co/en/tokyomx/" 5 | Name=TOKYO MX 6 | GenericName=Tokyo MX 7 | Comment=Watch TV 8 | Icon=mpv 9 | Terminal=false 10 | StartupNotify=true 11 | Categories=Video;Player;TV; 12 | StartupWMClass=mpv 13 | -------------------------------------------------------------------------------- /.local/bin/showclip: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Display contents of selection via dunst if running. 4 | # Separate script for i3. 5 | 6 | clip=$(xclip -o -selection clipboard) 7 | prim=$(xclip -o -selection primary) 8 | 9 | [ -n "$clip" ] && notify-send "Clipboard:" "$clip" 10 | [ -n "$prim" ] && notify-send "Primary:" "$prim" 11 | -------------------------------------------------------------------------------- /.local/bin/dmenupass: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script is the SUDO_ASKPASS variable, meaning that it will be used as a 4 | # password prompt if needed. 5 | 6 | if pacman -Qq "rofi" >/dev/null; then 7 | rofi -dmenu -password -p "$1" 8 | else 9 | dmenu -sb "#d79921" -sf "#1d2021" -nf "#000000" -nb "#000000" -p "$1" <&- && echo 10 | fi 11 | -------------------------------------------------------------------------------- /.config/pipewire/pipewire.conf.d/user-session.conf: -------------------------------------------------------------------------------- 1 | context.exec = [ 2 | { path = "/usr/bin/wireplumber" args = "" condition = [ { exec.session-manager = null } { exec.session-manager = true } ] } 3 | { path = "/usr/bin/pipewire" args = "-c pipewire-pulse.conf" condition = [ { exec.pipewire-pulse = null } { exec.pipewire-pulse = true } ] } 4 | ] 5 | -------------------------------------------------------------------------------- /.local/share/applications/linkhandler.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Type=Application 4 | Name=Link Handler 5 | Exec=linkhandler %u 6 | Comment=Feed script a url or file location 7 | Icon=browser 8 | Terminal=false 9 | MimeType=x-scheme-handler/unknown;x-scheme-handler/about;x-scheme-handler/https;x-scheme-handler/http;text/html; 10 | -------------------------------------------------------------------------------- /.local/bin/fingerbox: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Fingerbox is a simple browser launcher initially meant to run Firefox with a fake TZ. 4 | 5 | export TZ=UTC 6 | 7 | for browser in "$BROWSER" librewolf icecat firefox chromium; do 8 | if command -v "$browser" && [ "$browser" != "$(basename -- "$0")" ]; then 9 | exec "$browser" "$@" 10 | fi 11 | done 12 | -------------------------------------------------------------------------------- /.local/share/applications/lf.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=LF File Manager 4 | Comment=Browse the filesystem with the file manager 5 | GenericName=File Manager 6 | Icon=system-file-manager 7 | Exec=i3-sensible-terminal --title lf -e lf %f 8 | Categories=ConsoleOnly;System;FileTools;FileManager 9 | MimeType=inode/directory; 10 | -------------------------------------------------------------------------------- /.local/share/applications/tv_utako.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Type=Application 4 | Exec=mpv "https://gitflic.ru/project/utako/utako/blob/raw?file=jp.m3u" 5 | Name=IPTV-JP 6 | GenericName=IPTV-JP 7 | Comment=Watch TV 8 | Icon=mpv 9 | Terminal=false 10 | StartupNotify=true 11 | Categories=Video;Player;TV; 12 | StartupWMClass=mpv 13 | -------------------------------------------------------------------------------- /.local/bin/curlwttr: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | readonly result=$(curl -s \ 6 | --max-time 10 \ 7 | --compressed \ 8 | -H "Accept-Language: ${LANG%_*}" \ 9 | "https://wttr.in/$*" 2>/dev/null 10 | ) 11 | 12 | if [[ -n $result ]] && ! [[ ${result,,} =~ sorry|unknow|error|time-out ]]; then 13 | echo "$result" 14 | else 15 | exit 1 16 | fi 17 | -------------------------------------------------------------------------------- /.config/locale.conf: -------------------------------------------------------------------------------- 1 | LANG=en_US.UTF-8 2 | LC_CTYPE=en_US.UTF-8 3 | LC_NUMERIC=en_US.UTF-8 4 | LC_TIME=en_US.UTF-8 5 | LC_COLLATE=en_US.UTF-8 6 | LC_MONETARY=en_US.UTF-8 7 | LC_MESSAGES=en_US.UTF-8 8 | LC_PAPER=en_US.UTF-8 9 | LC_NAME=en_US.UTF-8 10 | LC_ADDRESS=en_US.UTF-8 11 | LC_TELEPHONE=en_US.UTF-8 12 | LC_MEASUREMENT=en_US.UTF-8 13 | LC_IDENTIFICATION=en_US.UTF-8 14 | -------------------------------------------------------------------------------- /.local/share/applications/anki.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Anki 3 | Comment=An intelligent spaced-repetition memory training program 4 | GenericName=Flashcards 5 | Exec=anki %f 6 | TryExec=anki 7 | Icon=anki 8 | Categories=Education;Languages;KDE;Qt; 9 | Terminal=false 10 | Type=Application 11 | Version=1.0 12 | MimeType=application/x-apkg;application/x-anki;application/x-ankiaddon; 13 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-headphone-plug: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This loop will update the volume statusbar module whenever headphones 4 | # are connected or disconnected. 5 | # https://linux.die.net/man/8/acpid 6 | # https://unix.stackexchange.com/a/128007 7 | 8 | acpi_listen | grep --line-buffered -F 'jack/headphone HEADPHONE' | while read -r line; do 9 | pkill -RTMIN+10 "${STATUSBAR:-i3blocks}" 10 | done 11 | -------------------------------------------------------------------------------- /.local/share/larbs/getkeys/calcurse: -------------------------------------------------------------------------------- 1 | _ 2 | ___ __ _| | ___ _ _ _ __ ___ ___ 3 | / __/ _` | |/ __| | | | '__/ __|/ _ \ 4 | | (_| (_| | | (__| |_| | | \__ \ __/ 5 | \___\__,_|_|\___|\__,_|_| |___/\___| 6 | 7 | calcurse is the calendar and schedule manager. 8 | tab - Switch from calendar to todo to appointments 9 | h/j/k/l - Move left/down/up/right 10 | Most other bindings are listed in the program. 11 | -------------------------------------------------------------------------------- /.local/bin/getcomproot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # A helper script for LaTeX/groff files used by `compiler` and `opout`. 4 | # The user can add the root file of a larger project as a comment as below: 5 | # % root = mainfile.tex 6 | # And the compiler script will run on that instead of the opened file. 7 | 8 | texroot="$(sed -n 's/^\s*%.*root\s*=\s*\(\S\+\).*/\1/p' "${1}")" 9 | [ -f "${texroot}" ] && readlink -f "${texroot}" || exit "1" 10 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-mpdup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | pgrep -x mpd || mpd # Start mpd 4 | command -v mpc || exit # Exit if no mpc 5 | 6 | # This loop will update the mpd statusbar module whenever a command changes the 7 | # music player's status. mpd must be running on X's start for this to work. 8 | 9 | while :; do 10 | if mpc idle; then 11 | pkill -RTMIN+11 "${STATUSBAR:-i3blocks}" 12 | else 13 | break 14 | fi 15 | done 16 | -------------------------------------------------------------------------------- /.local/bin/camtoggle: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if ! pkill -f /dev/video; then 4 | setsid -f mpv \ 5 | --no-osc \ 6 | --no-input-default-bindings \ 7 | --input-conf=/dev/null \ 8 | --geometry=-0-0 \ 9 | --autofit=30% \ 10 | --title="mpvfloat" \ 11 | --profile=low-latency \ 12 | --untimed \ 13 | --no-cache \ 14 | "$(ls /dev/video* | head -n 1)" 15 | notify-send "Camtoggle" "Launched." 16 | else 17 | notify-send "Camtoggle" "Killed." 18 | fi 19 | -------------------------------------------------------------------------------- /.local/bin/queueandnotify: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Podboat sucks. This script replaces it. 4 | # It reads the newsboat queue, queuing downloads with taskspooler. 5 | # It also removes the junk from extensions. 6 | queuefile="${XDG_DATA_HOME:-$HOME/.local/share}/newsboat/queue" 7 | 8 | while read -r line; do 9 | [ -z "$line" ] && continue 10 | url="${line%%[ ]*}" 11 | qndl "$url" "curl -LO" 12 | done < "$queuefile" 13 | 14 | echo > "$queuefile" 15 | -------------------------------------------------------------------------------- /.config/youtube-dl/config: -------------------------------------------------------------------------------- 1 | --sub-lang 'en,en-US,en-GB,ja,ru' 2 | --write-subs 3 | --convert-subs ass 4 | --no-mtime 5 | --ignore-errors 6 | --continue 7 | --add-metadata 8 | -f 'bestvideo[height<=1080]+bestaudio,best' 9 | -o '/mnt/archive/video/ytdl/%(upload_date)s - %(title).64s.%(ext)s' 10 | --merge-output-format mp4 11 | --user-agent "Mozilla/5.0 (Windows NT 10.0; rv:94.0) Gecko/20100101 Firefox/94.0" 12 | --geo-bypass 13 | --proxy socks5://127.0.0.1:10801/ 14 | -------------------------------------------------------------------------------- /.local/share/applications/mozc-config.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Name=Mozc Configuration 4 | GenericName=Input Method Editor Configuration 5 | Comment=Configure Mozc 6 | Exec=/usr/lib/mozc/mozc_tool --mode=config_dialog 7 | Icon=/usr/share/fcitx/mozc/icon/mozc.png 8 | Terminal=false 9 | Type=Application 10 | StartupNotify=false 11 | Categories=Settings; 12 | Keywords=web;browser;internet; 13 | Actions=new-window;new-private-window;banking;profile-manager; 14 | -------------------------------------------------------------------------------- /.local/share/applications/nvim.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=Neovim text editor 4 | GenericName=Text Editor 5 | TryExec=nvim 6 | Exec=i3-sensible-terminal -e nvim %F 7 | Keywords=Text;editor; 8 | Icon=nvim 9 | Categories=Utility;TextEditor; 10 | StartupNotify=false 11 | MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++; 12 | -------------------------------------------------------------------------------- /.local/share/larbs/getkeys/nsxiv: -------------------------------------------------------------------------------- 1 | _ __ _____ _(_)_ __ 2 | | '_ \/ __\ \/ / \ \ / / 3 | | | | \__ \> <| |\ V / 4 | |_| |_|___/_/\_\_| \_/ 5 | nsxiv is the image viewer. 6 | h/j/k/l - Pan image 7 | -/+ - Zoom out/in 8 | Enter - Toggle thumbnail mode 9 | f - Fullscreen 10 | n/p - Previous/next image in list/directory 11 | r - Reload image if changed 12 | m - Mark/unmark image 13 | w - Zoom to fit window 14 | ctrl-x - Run external command (see ~/.config/nsxiv/exec/key-handler for options) 15 | -------------------------------------------------------------------------------- /.config/shell/inputrc: -------------------------------------------------------------------------------- 1 | $include /etc/inputrc 2 | set editing-mode vi 3 | set completion-ignore-case on 4 | $if mode=vi 5 | 6 | set show-mode-in-prompt on 7 | set vi-ins-mode-string \1\e[6 q\2 8 | set vi-cmd-mode-string \1\e[2 q\2 9 | 10 | set keymap vi-command 11 | # these are for vi-command mode 12 | Control-l: clear-screen 13 | Control-a: beginning-of-line 14 | 15 | set keymap vi-insert 16 | # these are for vi-insert mode 17 | Control-l: clear-screen 18 | Control-a: beginning-of-line 19 | 20 | $endif 21 | -------------------------------------------------------------------------------- /.local/bin/pauseallmpv: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # You might notice all mpv commands are aliased to have this input-ipc-server 4 | # thing. That's just for this particular command, which allows us to pause 5 | # every single one of them with one command! This is bound to super + shift + p 6 | # (with other things) by default and is used in some other places. 7 | 8 | [[ -d /tmp/mpvSockets ]] && for i in /tmp/mpvSockets/*; do 9 | echo '{ "command": ["set_property", "pause", true] }' | socat - "$i"; 10 | done 11 | true 12 | -------------------------------------------------------------------------------- /.local/share/applications/firefox-temp.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Name=Fingerbox / Temp 4 | GenericName=Temporary Web Browser profile 5 | Comment=Browse the Web 6 | Exec=fftemp %u 7 | Icon=fingerbox 8 | Terminal=false 9 | Type=Application 10 | MimeType=text/html;text/xml;application/xhtml+xml;application/vnd.mozilla.xul+xml;text/mml;x-scheme-handler/http;x-scheme-handler/https; 11 | StartupNotify=true 12 | Categories=Network;WebBrowser; 13 | Keywords=web;browser;internet; 14 | StartupWMClass=Firefox 15 | -------------------------------------------------------------------------------- /.local/bin/ifinstalled: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Some scripts require programs not installed by default. 4 | # I use this little script to check to see if a command exists and if it doesn't 5 | # it informs the user that they need that command to continue. 6 | 7 | for x in "$@"; do 8 | if ! which "$x" >/dev/null 2>&1 && ! pacman -Qq "$x" >/dev/null 2>&1; then 9 | echo "Error: $x must be installed for this function." >&2 10 | notify-send -u critical "📦 $x" "$x must be installed for this function." 11 | exit 1 12 | fi 13 | done 14 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-load_average: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | list_cpu_hogs() { 4 | ps axch -o cmd,%cpu | 5 | awk '{cmd[$1]+=$2} END {for (i in cmd) print i, cmd[i]}' | 6 | sort -nrk2 | 7 | head 8 | } 9 | 10 | notify_hogs() { 11 | notify-send "CPU hogs" "$(list_cpu_hogs)\\n(100% per core)" 12 | } 13 | 14 | if [[ $BLOCK_BUTTON == 1 ]]; then 15 | notify_hogs 16 | fi 17 | 18 | readonly load=$(cut -f1 -d' ' /proc/loadavg) 19 | 20 | echo "AVG $load" 21 | echo " $load" 22 | awk "-vl=$load" "-vn=$(nproc)" 'BEGIN{if(l>n){exit(33);}}' 23 | -------------------------------------------------------------------------------- /.local/bin/opout: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # opout: "open output": A general handler for opening a file's intended output, 4 | # usually the pdf of a compiled document. I find this useful especially 5 | # running from vim. 6 | 7 | basename="${1%.*}" 8 | 9 | case "${*}" in 10 | *.typ|*.tex|*.sil|*.m[dse]|*.[rR]md|*.mom|*.[0-9]) target="$(getcomproot "$1" || echo "$1")" ; setsid -f xdg-open "${target%.*}".pdf >/dev/null 2>&1 ;; 11 | *.html) setsid -f "$BROWSER" "$basename".html >/dev/null 2>&1 ;; 12 | *.sent) setsid -f sent "$1" >/dev/null 2>&1 ;; 13 | esac 14 | -------------------------------------------------------------------------------- /.local/bin/qndl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # $1 is a url; $2 is a command 4 | 5 | if [ -z "$1" ]; then 6 | exit 1 7 | fi 8 | 9 | base="$(basename -- "$1")" 10 | cmd="$2" 11 | 12 | notify-send "qndl" "⏳ Queuing $base..." 13 | 14 | if [ -z "$cmd" ]; then 15 | cmd="yt-dlp --embed-metadata -ic" 16 | fi 17 | 18 | idnum="$(tsp $cmd "$1")" 19 | realname="$(echo "$base" | sed "s/?\(source\|dest\).*//;s/%20/ /g")" 20 | 21 | if [ "$base" != "$realname" ]; then 22 | tsp -D "$idnum" mv "$base" "$realname" 23 | fi 24 | tsp -D "$idnum" notify-send "👍 $realname done." 25 | -------------------------------------------------------------------------------- /.config/gtk-3.0/settings.ini: -------------------------------------------------------------------------------- 1 | [Settings] 2 | gtk-application-prefer-dark-theme=0 3 | gtk-theme-name=Arc-Darker 4 | gtk-icon-theme-name=Papirus 5 | gtk-font-name=Noto Sans CJK JP 9 6 | gtk-cursor-theme-size=18 7 | gtk-toolbar-style=GTK_TOOLBAR_BOTH_HORIZ 8 | gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR 9 | gtk-button-images=1 10 | gtk-menu-images=1 11 | gtk-enable-event-sounds=1 12 | gtk-enable-input-feedback-sounds=1 13 | gtk-xft-antialias=1 14 | gtk-xft-hinting=1 15 | gtk-xft-hintstyle=hintslight 16 | gtk-xft-rgba=none 17 | gtk-modules=canberra-gtk-module 18 | gtk-cursor-theme-name=Adwaita 19 | -------------------------------------------------------------------------------- /.local/bin/td-toggle: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # If transmission-daemon is running, will ask to kill, else will ask to start. 4 | 5 | if pidof transmission-daemon >/dev/null ; 6 | then 7 | [ "$(printf "No\\nYes" | dmenu -i -p "Turn off transmission-daemon?")" = "Yes" ] && killall transmission-daemon && notify-send "transmission-daemon disabled." 8 | else 9 | ifinstalled transmission-cli || exit 10 | [ "$(printf "No\\nYes" | dmenu -i -p "Turn on transmission daemon?")" = "Yes" ] && transmission-daemon && notify-send "transmission-daemon enabled." 11 | fi 12 | sleep 3 && pkill -RTMIN+7 "${STATUSBAR:-i3blocks}" 13 | -------------------------------------------------------------------------------- /.local/share/larbs/getkeys/zathura: -------------------------------------------------------------------------------- 1 | _ _ 2 | ______ _| |_| |__ _ _ _ __ __ _ 3 | |_ / _` | __| '_ \| | | | '__/ _` | 4 | / / (_| | |_| | | | |_| | | | (_| | 5 | /___\__,_|\__|_| |_|\__,_|_| \__,_| 6 | 7 | zathura is the pdf/djvu reader. 8 | h/j/k/l - Move left/down/up/right in document 9 | d/u - Down/up a half page 10 | gg - Top of document 11 | G - Bottom of document 12 | f - Highlight URLS to follow 13 | J/K - Zoom out/in 14 | s - Zoom to fit width 15 | a - Zoom to fit height 16 | r - Reload document if changed 17 | R - Rotate document 18 | D - Toggle dual-page mode 19 | p - Print document 20 | -------------------------------------------------------------------------------- /.local/bin/lmc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | STEP="${2:-5}" 4 | 5 | case "$1" in 6 | toggle-mic) 7 | pamixer --default-source --toggle-mute ;; 8 | toggle*) 9 | pamixer --toggle-mute ;; 10 | mute) 11 | pamixer --mute ;; 12 | mute-mic) 13 | pamixer --default-source --mute ;; 14 | unmute) 15 | pamixer --unmute ;; 16 | up) 17 | pamixer --increase "$STEP" ;; 18 | down) 19 | pamixer --decrease "$STEP" ;; 20 | control) 21 | pulsemixer ;; 22 | *) 23 | notify-send -u critical "$(basename -- "$0")" "Unsupported operation: ${1:-empty string}." ;; 24 | esac >/dev/null 25 | 26 | pkill -RTMIN+10 "${STATUSBAR:-i3blocks}" & 27 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-brightness: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # current brightness 4 | curr_brightness=$(cat /sys/class/backlight/*/brightness) 5 | 6 | # max_brightness 7 | max_brightness=$(cat /sys/class/backlight/*/max_brightness) 8 | 9 | # brightness percentage 10 | brightness_per=$((100 * curr_brightness / max_brightness)) 11 | 12 | case $BLOCK_BUTTON in 13 | 1) 14 | ;; 15 | 3) 16 | notify-send "💡 Brightness module" "\- Shows current brightness level ☀️." 17 | ;; 18 | 6) 19 | setsid -f "$TERMINAL" -e "$EDITOR" "$0" 20 | ;; 21 | esac 22 | 23 | echo "💡 ${brightness_per}%" 24 | -------------------------------------------------------------------------------- /.local/bin/fftemp: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | readonly TZ=UTC 4 | readonly BROWSER=$(command -v librewolf icecat iceweasel firefox | head -1) 5 | readonly fftmpdir=/tmp/firefox-temp 6 | 7 | export TZ BROWSER 8 | 9 | mkdir -p "$fftmpdir" && chmod 700 "$fftmpdir" && 10 | echo "Created $fftmpdir directory." || exit 1 11 | 12 | if command -v firejail; then 13 | firejail --seccomp --profile=firefox --private="$fftmpdir" \ 14 | "$BROWSER" --new-instance --no-remote "$@" 15 | else 16 | echo "Firejail is not installed.">&2 && 17 | "$BROWSER" --new-instance --profile "$fftmpdir" --no-remote "$@" 18 | fi 19 | rm -rf "$fftmpdir" && echo "Bye-bye!" 20 | -------------------------------------------------------------------------------- /.local/bin/rssadd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if echo "$1" | grep -q "https*://\S\+\.[A-Za-z]\+\S*" ; then 4 | url="$1" 5 | else 6 | url="$(grep -Eom1 '<[^>]+(rel="self"|application/[a-z]+\+xml)[^>]+>' "$1" | 7 | grep -o "https?://[^\" ]")" 8 | 9 | echo "$url" | grep -q "https*://\S\+\.[A-Za-z]\+\S*" || 10 | notify-send "That doesn't look like a full URL." && exit 1 11 | fi 12 | 13 | RSSFILE="${XDG_CONFIG_HOME:-$HOME/.config}/newsboat/urls" 14 | if awk '{print $1}' "$RSSFILE" | grep "^$url$" >/dev/null; then 15 | notify-send "You already have this RSS feed." 16 | else 17 | echo "$url" >> "$RSSFILE" && notify-send "RSS feed added." 18 | fi 19 | -------------------------------------------------------------------------------- /.local/share/larbs/getkeys/ncmpcpp: -------------------------------------------------------------------------------- 1 | 2 | _ __ ___ _ __ ___ _ __ ___ _ __ _ __ 3 | | '_ \ / __| '_ ` _ \| '_ \ / __| '_ \| '_ \ 4 | | | | | (__| | | | | | |_) | (__| |_) | |_) | 5 | |_| |_|\___|_| |_| |_| .__/ \___| .__/| .__/ 6 | |_| |_| |_| 7 | 8 | ncmpcpp is the music player. 9 | h/j/k/l - Move left/down/up/right 10 | d/u - Down/up page 11 | a - Add song(s) to playlist 12 | c - Clear playlist 13 | g - Go to top 14 | G - Go to bottom 15 | p - Pause 16 | m - Media library 17 | f - Music sorted by directory structure 18 | t - Tag editor 19 | s - Search 20 | v - Visualizer 21 | P - Playlist 22 | -------------------------------------------------------------------------------- /.local/bin/listmarks: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | urldecode() { 6 | local url 7 | url=$(cut -f1 -d' ') 8 | url=${url//file:\/\//} 9 | url=${url//+/ } 10 | url=${url//%/\\x} 11 | printf -- '%b\n' "$url" 12 | } 13 | 14 | if [[ $* =~ ^(dirs|files)$ ]]; then 15 | sed \ 16 | -e 's/\s*#.*$//' \ 17 | -e '/^\s*$/d' \ 18 | -e 's/^\S*\s*//' \ 19 | -e 's|~|$HOME|' \ 20 | "${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-$*" | 21 | while read -r line; do 22 | eval "echo $line" 23 | done 24 | if [[ $* == dirs ]]; then 25 | urldecode < "${XDG_CONFIG_HOME:-$HOME/.config}/gtk-3.0/bookmarks" 26 | fi 27 | fi | sort -u 28 | -------------------------------------------------------------------------------- /.local/bin/dmenuunicode: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # The famous "get a menu of emojis to copy" script. 4 | 5 | # Get user selection via dmenu from emoji file. 6 | chosen=$(cut -d ';' -f1 ~/.local/share/larbs/chars/* | dmenu -i -l 30 -p 'Select emoji' | sed "s/ .*//") 7 | 8 | # Exit if none chosen. 9 | [ -z "$chosen" ] && exit 10 | 11 | # If you run this command with an argument, it will automatically insert the 12 | # character. Otherwise, show a message that the emoji has been copied. 13 | if [ -n "$1" ]; then 14 | xdotool type "$chosen" 15 | else 16 | printf "%s" "$chosen" | xclip -selection clipboard 17 | notify-send "'$chosen' copied to clipboard." & 18 | fi 19 | -------------------------------------------------------------------------------- /.local/bin/i3cmds/ducksearch: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # Gives a dmenu prompt to search DuckDuckGo. 3 | # Without input, will open DuckDuckGo.com. 4 | # URLs will be directly handed to the browser. 5 | # Anything else, it search it. 6 | 7 | browser=${BROWSER:-firefox} 8 | 9 | pgrep -x dmenu && exit 10 | 11 | choice=$(echo "🦆" | dmenu -i -p "Search DuckDuckGo:") || exit 1 12 | 13 | if [ "$choice" = "🦆" ]; then 14 | "$browser" "https://duckduckgo.com" 15 | else 16 | if echo "$choice" | grep "^(http:\/\/|https:\/\/)?[a-zA-Z0-9]+\.[a-zA-Z]+(/)?.*$"; then 17 | "$browser" "$choice" 18 | else 19 | "$browser" "https://duckduckgo.com/?q=$choice&t=ffab&atb=v1-1" 20 | fi 21 | fi 22 | -------------------------------------------------------------------------------- /.config/user-dirs.dirs: -------------------------------------------------------------------------------- 1 | # This file is written by xdg-user-dirs-update 2 | # If you want to change or add directories, just edit the line you're 3 | # interested in. All local changes will be retained on the next run. 4 | # Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped 5 | # homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an 6 | # absolute path. No other format is supported. 7 | # 8 | XDG_DESKTOP_DIR="$HOME/Desktop" 9 | XDG_DOWNLOAD_DIR="$HOME/Downloads" 10 | XDG_TEMPLATES_DIR="$HOME/Templates" 11 | XDG_PUBLICSHARE_DIR="$HOME/Public" 12 | XDG_DOCUMENTS_DIR="$HOME/Documents" 13 | XDG_MUSIC_DIR="$HOME/Music" 14 | XDG_PICTURES_DIR="$HOME/Pictures" 15 | XDG_VIDEOS_DIR="$HOME/Videos" 16 | -------------------------------------------------------------------------------- /.config/gtk-2.0/gtkrc-2.0: -------------------------------------------------------------------------------- 1 | # DO NOT EDIT! This file will be overwritten by LXAppearance. 2 | # Any customization should be done in ~/.gtkrc-2.0.mine instead. 3 | 4 | include "~/.gtkrc-2.0.mine" 5 | gtk-theme-name="Arc-Darker" 6 | gtk-icon-theme-name="Papirus" 7 | gtk-font-name="Noto Sans CJK JP 9" 8 | gtk-cursor-theme-name="Adwaita" 9 | gtk-cursor-theme-size=18 10 | gtk-toolbar-style=GTK_TOOLBAR_BOTH_HORIZ 11 | gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR 12 | gtk-button-images=1 13 | gtk-menu-images=1 14 | gtk-enable-event-sounds=1 15 | gtk-enable-input-feedback-sounds=1 16 | gtk-xft-antialias=1 17 | gtk-xft-hinting=1 18 | gtk-xft-hintstyle="hintslight" 19 | gtk-xft-rgba="none" 20 | gtk-modules="canberra-gtk-module" 21 | -------------------------------------------------------------------------------- /.config/shell/bm-dirs: -------------------------------------------------------------------------------- 1 | # You can add comments to these files with # 2 | 3 | # Home 4 | downloads ~/Downloads 5 | pictures ~/Pictures 6 | documents ~/Documents 7 | syncthing ~/Documents/syncthing 8 | proj ~/Documents/Projects 9 | blog ~/Documents/Projects/bashblog/site/blog 10 | addons ~/Documents/anki_addons 11 | 12 | # Dotfiles 13 | cf ~/.config 14 | cac ~/.cache 15 | sc ~/.local/bin 16 | sr ~/.local/share 17 | rr ~/.local/src 18 | 19 | # External drives 20 | mnt /mnt 21 | avideo /mnt/archive/video 22 | audio /mnt/archive/audio 23 | ongoing /mnt/d/ongoing 24 | dvideo /mnt/d/video 25 | ytdl /mnt/archive/video/ytdl 26 | books /mnt/archive/books 27 | subs /mnt/archive/japanese/kitsunekko-mirror/subtitles 28 | japanese /mnt/archive/japanese/ 29 | -------------------------------------------------------------------------------- /.config/fontconfig/conf.d/10-no-sub-pixel.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Disable sub-pixel rendering 5 | 6 | 7 | 13 | none 14 | 15 | 16 | -------------------------------------------------------------------------------- /.config/nvim/auto_fcitx.vim: -------------------------------------------------------------------------------- 1 | " Auto Fcitx 2 | " https://wiki.archlinux.org/title/Fcitx#Vim 3 | let g:input_toggle = 1 4 | function! FcitxDisable() 5 | let s:input_status = system("fcitx-remote") 6 | if s:input_status == 2 7 | let g:input_toggle = 1 8 | let l:a = system("fcitx-remote -c") 9 | endif 10 | endfunction 11 | 12 | function! FcitxEnable() 13 | let s:input_status = system("fcitx-remote") 14 | if s:input_status != 2 && g:input_toggle == 1 15 | let l:a = system("fcitx-remote -o") 16 | let g:input_toggle = 0 17 | endif 18 | endfunction 19 | 20 | set ttimeoutlen=150 21 | "Exit insert mode 22 | autocmd InsertLeave * call FcitxDisable() 23 | "Enter insert mode 24 | autocmd InsertEnter * call FcitxEnable() 25 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-tasks: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Originally by Andr3as07 4 | # Some changes by Luke 5 | # Rebuild by Tenyun 6 | 7 | # This block displays the number running background tasks. Requires tsp. 8 | 9 | num=$(tsp -l | awk -v numr=0 -v numq=0 '{if (/running/)numr++; if (/queued/)numq++} END{print numr+numq"("numq")"}') 10 | 11 | # Handle mouse clicks 12 | case $BLOCK_BUTTON in 13 | 1) setsid -f "$TERMINAL" -e tsp -l ;; 14 | 3) notify-send "Tasks module" "🤖: number of running/queued background tasks 15 | - Left click opens tsp" ;; # Right click 16 | 2) $EDITOR "$0" ;; # Middle click 17 | 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; 18 | esac 19 | 20 | [ "$num" != "0(0)" ] && 21 | echo "🤖$num" 22 | -------------------------------------------------------------------------------- /.local/share/larbs/getkeys/newsboat: -------------------------------------------------------------------------------- 1 | _ _ 2 | _ __ _____ _____| |__ ___ __ _| |_ 3 | | '_ \ / _ \ \ /\ / / __| '_ \ / _ \ / _` | __| 4 | | | | | __/\ V V /\__ \ |_) | (_) | (_| | |_ 5 | |_| |_|\___| \_/\_/ |___/_.__/ \___/ \__,_|\__| 6 | 7 | newsboat is the RSS reader. 8 | j/k - Move down/up 9 | l - Open entry 10 | h/q - Back/quit 11 | Q - Quit immediately 12 | J/K - Previous/next feed 13 | n - Next unread 14 | N - Previous unread 15 | a - Toggle article read/unread 16 | A - Mark all as read 17 | U - Show all URLs 18 | ,, - Open main link with linkhandler 19 | ,p - Pick which program to open link with 20 | ,v - Open video link in mpv 21 | ,w - Open link in w3m 22 | ,c - Copy link to clipboard 23 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-mailbox: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Displays number of unread mail and an loading icon if updating. 4 | # When clicked, brings up `neomutt`. 5 | 6 | case $BLOCK_BUTTON in 7 | 1) setsid -w -f "$TERMINAL" -e neomutt; pkill -RTMIN+12 "${STATUSBAR:-i3blocks}" ;; 8 | 2) setsid -f mw -Y >/dev/null ;; 9 | 3) notify-send "📬 Mail module" "\- Shows unread mail 10 | - Shows 🔃 if syncing mail 11 | - Left click opens neomutt 12 | - Middle click syncs mail" ;; 13 | 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; 14 | esac 15 | 16 | unread="$(find "${XDG_DATA_HOME:-$HOME/.local/share}"/mail/*/[Ii][Nn][Bb][Oo][Xx]/new/* -type f | wc -l 2>/dev/null)" 17 | 18 | pidof mbsync >/dev/null 2>&1 && icon="🔃" 19 | 20 | [ "$unread" = "0" ] && [ "$icon" = "" ] || echo "📬$unread$icon" 21 | -------------------------------------------------------------------------------- /.config/x11/keyboard_layouts: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Fcitx 4 | # https://wiki.archlinux.org/index.php/Fcitx 5 | find_fcitx() { 6 | for cmd in fcitx5 fcitx; do 7 | command -v "$cmd" && return 8 | done 9 | } 10 | 11 | if [ -n "${fcitx:=$(find_fcitx)}" ]; then 12 | # Define the environment variables to register the input method modules. 13 | export GTK_IM_MODULE=fcitx 14 | export QT_IM_MODULE=fcitx 15 | export XMODIFIERS=@im=fcitx 16 | setxkbmap -model pc104 \ 17 | -layout us \ 18 | -variant altgr-intl \ 19 | -option terminate:ctrl_alt_bksp,caps:escape 20 | "$fcitx" -dr 2>/dev/null & 21 | else 22 | setxkbmap -model pc104 \ 23 | -layout us,ru \ 24 | -variant altgr-intl,winkeys \ 25 | -option terminate:ctrl_alt_bksp,caps:escape,grp:win_space_toggle 26 | fi 27 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-pacpackages: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Displays number of upgradeable packages. 4 | # When clicked, it will run an upgrade via pacman. 5 | # Requires checkupdates. checkupdates is owned by pacman-contrib. 6 | 7 | readonly cache_file=~/.cache/checkupdates 8 | 9 | print_cache() { 10 | if [ -s "$cache_file" ]; then 11 | cat "$cache_file" 12 | else 13 | echo "None." 14 | fi 15 | } 16 | 17 | case $BLOCK_BUTTON in 18 | 1) notify-send "Upgradeable packages" "$(print_cache)" &;; 19 | 3) setsid -f "$TERMINAL" -e sb-popupgrade ;; 20 | 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; 21 | esac 22 | 23 | printf -- "UPD " 24 | 25 | if [[ -n $BLOCK_BUTTON ]]; then 26 | wc -l <"$cache_file" 27 | else 28 | checkupdates | tee "$cache_file" | wc -l || echo "?" 29 | fi 30 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-calendar: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | date '+%b %d (%a)' 4 | date '+%d.%m' 5 | 6 | mark_weekend() { 7 | sed \ 8 | -e 's|Su|&|' \ 9 | -e 's|Sa|&|' 10 | } 11 | 12 | mark_day() { 13 | sed \ 14 | -e "s/..7m//;" \ 15 | -e "s/..0m/<\/span><\/b>/;" 16 | } 17 | 18 | show_cal() { 19 | cal -m -c1 -3 --color=always | mark_weekend | mark_day 20 | } 21 | 22 | case $BLOCK_BUTTON in 23 | 1) 24 | notify-send Calendar "$(show_cal)" 25 | command -v calcurse && notify-send "Appointments" "$(calcurse -D ~/.config/calcurse -d3)" ;; 26 | 2) 27 | setsid -f i3-sensible-terminal -e 'calcurse -D ~/.config/calcurse' & ;; 28 | 6) 29 | setsid -f i3-sensible-terminal -e "$EDITOR" "$0" ;; 30 | esac 31 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-chip_temp: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | case $BLOCK_BUTTON in 4 | 1) notify-send "🖥 CPU hogs" "$(ps axch -o cmd:15,%cpu --sort=-%cpu | head)\\n(100% per core)" ;; 5 | 3) i3-msg -q exec "$TERMINAL -e htop" ;; 6 | 6) i3-msg -q exec "$TERMINAL -e $EDITOR $0" ;; 7 | esac 8 | 9 | readonly temp="$(eval "${query:?}" | tr -cd '[:digit:].')" 10 | readonly label="${chip_label:-CPU}" 11 | [ -z "$temp" ] && exit 1 12 | 13 | awk -v temp="$temp" -v label="$label" ' 14 | BEGIN { 15 | print label" "temp"°C" 16 | if (temp < 60) { 17 | print 18 | exit 19 | } 20 | 21 | # if above 60 22 | print label" "temp"°C" 23 | 24 | # color 25 | if (temp > 90) { 26 | print("#FF0000") 27 | } else if (temp > 80) { 28 | print("#FFAE00") 29 | } else if (temp > 70) { 30 | print("#FFF600") 31 | } 32 | }' 33 | -------------------------------------------------------------------------------- /.config/nsxiv/exec/image-info: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Example for $XDG_CONFIG_HOME/sxiv/exec/image-info 4 | # Called by sxiv(1) whenever an image gets loaded. 5 | # The output is displayed in sxiv's status bar. 6 | # Arguments: 7 | # $1: path to image file 8 | # $2: image width 9 | # $3: image height 10 | 11 | s=" | " # field separator 12 | 13 | exec 2>/dev/null 14 | 15 | filename=$(basename -- "$1") 16 | filesize=$(du -Hh -- "$1" | cut -f 1) 17 | mimetype=$(file -b --mime-type -- "$1") 18 | 19 | geometry="${2}x${3}" 20 | tags=$(identify -format '%[IPTC:2:25]' ":$1" | tr ';' ',') 21 | 22 | echo "${filesize}${s}${geometry}${tags:+$s}${tags}${s}${mimetype}${s}${filename}" 23 | 24 | # If running as a child of lf, select the current file. 25 | if [ -n "$id" ]; then 26 | lf -remote "send $id select \"$filename\" " 27 | fi 28 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-torrent: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | transmission-remote -l | grep % | 4 | sed " # The letters are for sorting and will not appear. 5 | s/.*Stopped.*/A 🛑/; 6 | s/.*Seeding.*/Z 🌱/; 7 | s/.*100%.*/N ✅/; 8 | s/.*Idle.*/B 🕰️/; 9 | s/.*Uploading.*/L ⬆️/; 10 | s/.*%.*/M ⬇️/" | 11 | sort -h | uniq -c | awk '{print $3 $1}' | paste -sd ' ' - 12 | 13 | case $BLOCK_BUTTON in 14 | 1) setsid -f "$TERMINAL" -e stig ;; 15 | 2) td-toggle ;; 16 | 3) notify-send "🌱 Torrent module" "\- Left click to open stig. 17 | - Middle click to toggle transmission. 18 | - Shift click to edit script. 19 | Module shows number of torrents: 20 | 🛑: paused 21 | 🕰: idle (seeds needed) 22 | 🔼: uploading (unfinished) 23 | 🔽: downloading 24 | ✅: done 25 | 🌱: done and seeding" ;; 26 | 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; 27 | esac 28 | -------------------------------------------------------------------------------- /.local/bin/lfub: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # https://github.com/jstkdng/ueberzugpp/blob/master/scripts/lf/lfub 4 | 5 | # This is a wrapper script for lf that allows it to create image previews with 6 | # ueberzug. This works in concert with the lf configuration file and the 7 | # lf-cleaner script. 8 | 9 | set -e 10 | 11 | if ! command -v ueberzug >/dev/null 2>&1; then 12 | exec lf "$@" 13 | fi 14 | 15 | cleanup() { 16 | exec 3>&- 17 | rm "$FIFO_UEBERZUG" 18 | } 19 | 20 | if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then 21 | lf "$@" 22 | else 23 | [ ! -d "$HOME/.cache/lf" ] && mkdir -p "$HOME/.cache/lf" 24 | export FIFO_UEBERZUG="$HOME/.cache/lf/ueberzug-$$" 25 | mkfifo "$FIFO_UEBERZUG" 26 | ueberzug layer -s <"$FIFO_UEBERZUG" -p json & 27 | exec 3>"$FIFO_UEBERZUG" 28 | trap cleanup HUP INT QUIT TERM PWR EXIT 29 | lf "$@" 3>&- 30 | fi 31 | -------------------------------------------------------------------------------- /.config/fontconfig/conf.d/30-metric-aliases.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | 15 | Helvetica 16 | Arial 17 | 18 | 19 | Times 20 | Times New Roman 21 | 22 | 23 | Courier 24 | Courier New 25 | 26 | 27 | -------------------------------------------------------------------------------- /.local/bin/archnews: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | archnews() { 4 | local -r cached_page=$HOME/.cache/archnews 5 | local -r current_page=/tmp/archnews 6 | 7 | curl --max-time 20 -s "https://archlinux.org/feeds/news/" -o "$current_page" 8 | 9 | if ! [[ -s $current_page ]]; then 10 | echo "Couldn't connect to archlinux.org." 11 | return 1 12 | fi 13 | 14 | if ! cmp -s "$current_page" "$cached_page"; then 15 | echo "*** MANUAL INTERVENTION NEEDED ***" 16 | tee "$cached_page" < "$current_page" | 17 | xmllint --xpath '//item/title | //item/pubDate' /dev/stdin | 18 | paste - - -d '' | 19 | sed -r -e 's:([^<]*?)([^<]*?):\2\t\1:g' | 20 | sed '3q' | sed 's/>/>/g; s/\s[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\s+0000\s/ - /g' 21 | 22 | xdg-open 'https://www.archlinux.org/news/' 23 | fi 24 | 25 | rm -- "$current_page" 26 | } 27 | 28 | archnews 29 | -------------------------------------------------------------------------------- /.local/share/applications/firefox.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Name=Fingerbox / Main profile 4 | GenericName=Web Browser 5 | Comment=Browse the Web 6 | Exec=fingerbox -P Main %u 7 | Icon=fingerbox 8 | Terminal=false 9 | Type=Application 10 | MimeType=text/html;text/xml;application/xhtml+xml;application/vnd.mozilla.xul+xml;text/mml;x-scheme-handler/http;x-scheme-handler/https; 11 | StartupNotify=true 12 | Categories=Network;WebBrowser; 13 | Keywords=web;browser;internet; 14 | Actions=new-window;new-private-window;profile-manager; 15 | StartupWMClass=Firefox 16 | 17 | [Desktop Action new-window] 18 | Name=New Window 19 | Exec=fingerbox --new-window %u 20 | 21 | [Desktop Action new-private-window] 22 | Name=New Private Window 23 | Exec=fingerbox --private-window %u 24 | 25 | [Desktop Action profile-manager] 26 | Name=Profile manager 27 | Exec=fingerbox -p -no-remote %u 28 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule ".config/mpv/scripts/mpvSockets"] 2 | path = .config/mpv/scripts/mpvSockets 3 | url = https://github.com/wis/mpvSockets.git 4 | [submodule ".config/mpv/scripts/subs2srs"] 5 | path = .config/mpv/scripts/subs2srs 6 | url = https://github.com/Ajatt-Tools/mpvacious.git 7 | [submodule ".config/mpv/scripts/videoclip"] 8 | path = .config/mpv/scripts/videoclip 9 | url = https://github.com/Ajatt-Tools/videoclip.git 10 | [submodule ".config/mpv/scripts/autosubsync"] 11 | path = .config/mpv/scripts/autosubsync 12 | url = https://github.com/Ajatt-Tools/autosubsync-mpv.git 13 | [submodule ".config/mpv/scripts/sub-transition"] 14 | path = .config/mpv/scripts/sub-transition 15 | url = https://github.com/Ajatt-Tools/sub-transition.git 16 | [submodule ".config/alacritty/alacritty-theme"] 17 | path = .config/alacritty/themes 18 | url = https://github.com/alacritty/alacritty-theme.git 19 | -------------------------------------------------------------------------------- /.config/i3/nadeshiko.conf: -------------------------------------------------------------------------------- 1 | # Monitors 2 | # You can get the names of your outputs by running: xrandr -q 3 | set $monitor1 "HDMI3" 4 | set $monitor2 "DP1" 5 | 6 | # Workspace Monitors 7 | workspace $ws1 output $monitor1 8 | workspace $ws2 output $monitor1 9 | workspace $ws3 output $monitor1 10 | workspace $ws4 output $monitor1 11 | workspace $ws5 output $monitor1 12 | workspace $ws6 output $monitor1 13 | workspace $ws7 output $monitor1 14 | workspace $ws8 output $monitor1 15 | # 16 | workspace $ws9 output $monitor2 17 | workspace $ws10 output $monitor2 18 | 19 | # Load ICC profile 20 | #exec --no-startup-id xcalib -v -o $monitor1 ~/.local/share/icc/main_monitor.icc 21 | 22 | # Autostart 23 | exec --no-startup-id qbittorrent --no-splash 24 | exec --no-startup-id throne --no-splash 25 | exec --no-startup-id xrandr --output $monitor1 --primary 26 | exec --no-startup-id transformers_ocr listen 27 | #exec goldendict 28 | -------------------------------------------------------------------------------- /.local/bin/lf-select: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # View files with nsxiv and and select them in lf. 4 | 5 | readonly first_file="$1" 6 | exe=$(basename -- "$0") 7 | readonly exe 8 | 9 | where_is_sxiv() { 10 | for cmd in nsxiv sxiv; do 11 | if command -v "$cmd" >/dev/null 2>&1; then 12 | echo "$cmd" 13 | return 14 | fi 15 | done 16 | echo "sxiv is not found in this system." >&2 17 | exit 1 18 | } 19 | 20 | if ! [ -f "$first_file" ]; then 21 | notify-send "$exe" "first arg is not a file!" 22 | exit 1 23 | fi 24 | 25 | if [ -z "$id" ]; then 26 | notify-send "$exe" "lf id is not set!" 27 | exit 1 28 | fi 29 | 30 | rotdir "$first_file" | 31 | grep -i "\.\(png\|jpg\|jpeg\|gif\|webp\|avif\|tif\|ico\)\(_large\)*$" | 32 | "$(where_is_sxiv)" -aio 2>/dev/null | 33 | while read -r file; do 34 | if [ -n "$file" ]; then 35 | lf -remote "send $id select \"$file\" " 36 | lf -remote "send $id toggle" 37 | fi 38 | done 39 | -------------------------------------------------------------------------------- /.config/i3/ws10.json: -------------------------------------------------------------------------------- 1 | { 2 | "layout": "splitv", 3 | "percent": 0.5, 4 | "type": "con", 5 | "nodes": [ 6 | { 7 | "name": "htop", 8 | "percent": 0.5, 9 | "type": "con", 10 | "swallows": [ 11 | { 12 | "title": "htop$" 13 | } 14 | ] 15 | }, 16 | { 17 | "name": "journalctl", 18 | "percent": 0.5, 19 | "type": "con", 20 | "swallows": [ 21 | { 22 | "title": "journalctl" 23 | } 24 | ] 25 | }, 26 | { 27 | "name": "terminal", 28 | "percent": 0.5, 29 | "type": "con", 30 | "swallows": [ 31 | { 32 | "title": "terminal" 33 | } 34 | ] 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /.local/bin/dmenumountcifs: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Gives a dmenu prompt to mount unmounted local NAS shares for read/write. 3 | # Requirements - "%wheel ALL=(ALL) NOPASSWD: ALL" 4 | # 5 | # Browse for mDNS/DNS-SD services using the Avahi daemon... 6 | srvname=$(avahi-browse _smb._tcp -t | awk '{print $4}' | dmenu -i -p "Which NAS?") || exit 1 7 | notify-send "Searching for network shares..." "Please wait..." 8 | # Choose share disk... 9 | share=$(smbclient -L "$srvname" -N | grep Disk | awk '{print $1}' | dmenu -i -p "Mount which share?") || exit 1 10 | # Format URL... 11 | share2mnt=//"$srvname".local/"$share" 12 | 13 | sharemount() { 14 | mounted=$(mount -v | grep "$share2mnt") || ([ ! -d /mnt/"$share" ] && sudo mkdir /mnt/"$share") 15 | [ -z "$mounted" ] && sudo mount -t cifs "$share2mnt" -o user=nobody,password="",noperm /mnt/"$share" && notify-send "Netshare $share mounted" && exit 0 16 | notify-send "Netshare $share already mounted"; exit 1 17 | } 18 | 19 | sharemount 20 | -------------------------------------------------------------------------------- /.local/bin/i3cmds/somesearch: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | pgrep -x dmenu && exit 6 | 7 | readonly prompts=$(cat <<-EOF 8 | ZEal 9 | DUckduckgo 10 | SEarx 11 | SAkuraparis 12 | MANual 13 | EOF 14 | ) 15 | 16 | readonly choice=$(echo "$prompts" | dmenu -i -p "Search:") || exit 1 17 | readonly s=${choice#* } 18 | readonly cmd=${choice%% *} 19 | 20 | browse() { 21 | setsid -f "${BROWSER:-firefox}" "$@" 22 | } 23 | 24 | case $cmd in 25 | 'ze') 26 | setsid -f zeal "$s" 27 | ;; 28 | 'du') 29 | browse "https://duckduckgo.com/?q=${s}&t=ffab&atb=v1-1" 30 | ;; 31 | 'se') 32 | browse "https://searx.work/search?q=${s}&language=auto&safesearch=0&categories=general" 33 | ;; 34 | 'sa') 35 | browse "https://sakura-paris.org/dict/明鏡国語辞典/exact/${s}" 36 | ;; 37 | 'man') 38 | if man -k "^$s$" >/dev/null; then 39 | man -Tpdf "${s}" | zathura -; 40 | else 41 | notify-send "manual" "nothing appropriate" & 42 | fi 43 | ;; 44 | *) 45 | exit 1 46 | ;; 47 | esac 48 | -------------------------------------------------------------------------------- /.local/bin/setbg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script does the following: 4 | # Run by itself, set the wallpaper (at X start). 5 | # If given a file, set that as the new wallpaper. 6 | # If given a directory, choose random file in it. 7 | 8 | readonly linkpath="${XDG_DATA_HOME:-$HOME/.local/share}/bg" 9 | 10 | setwallpaper() { 11 | hsetroot -solid '#242934' 12 | xwallpaper --zoom "$*" 13 | } 14 | 15 | die() { 16 | echo "Error: Couldn't set wallpaper." >&2 17 | notify-send -u critical "Error" "Couldn't set wallpaper." 18 | exit 1 19 | } 20 | 21 | if [ -d "$1" ]; then 22 | readonly givenpath="$(find "$1" -type f -iregex '.*\.\(jpg\|jpeg\|png\|gif\)' | shuf -n 1)" 23 | else 24 | readonly givenpath="$1" 25 | fi 26 | 27 | if [ -f "$givenpath" ]; then 28 | if setwallpaper "$givenpath" && ln -srf -- "$givenpath" "$linkpath"; then 29 | notify-send -i "$linkpath" "Wallpaper changed." 30 | else 31 | setwallpaper "$linkpath" 32 | die 33 | fi 34 | else 35 | setwallpaper "$linkpath" || die 36 | fi 37 | -------------------------------------------------------------------------------- /.local/bin/i3cmds/ddspawn: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Toggle floating dropdown terminal in i3, or start if non-existing. 4 | # $1 is the script run in the terminal. 5 | # All other args are terminal settings. 6 | # Terminal names are in dropdown_* to allow easily setting i3 settings. 7 | 8 | ifinstalled xwininfo || exit 9 | 10 | [ -z "$1" ] && exit 11 | 12 | case $TERMINAL in 13 | st) 14 | nameopt='-n ';; 15 | *rxvt*) 16 | nameopt='-name ';; 17 | termite) 18 | nameopt='--name=';; 19 | alacritty) 20 | nameopt='--class=';; 21 | *) 22 | echo "Could not recognize your TERMINAL \"$TERMINAL\". Please add it to $0.">&2 23 | exit 1 24 | esac 25 | 26 | script=$1 27 | shift 28 | if xwininfo -tree -root | grep "(\"dropdown_$script\" "; 29 | then 30 | echo "Window detected." 31 | i3 "[instance=\"dropdown_$script\"] scratchpad show; [instance=\"dropdown_$script\"] move position center" 32 | else 33 | echo "Window not detected... spawning." 34 | i3 "exec --no-startup-id $TERMINAL ${nameopt}dropdown_$script $* -e $script" 35 | fi 36 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-moonphase: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Shows the current moon phase. 4 | 5 | moonfile="${XDG_DATA_HOME:-$HOME/.local/share}/moonphase" 6 | 7 | [ -s "$moonfile" ] && [ "$(stat -c %y "$moonfile" 2>/dev/null | cut -d' ' -f1)" = "$(date '+%Y-%m-%d')" ] || 8 | { curl -sf "wttr.in/?format=%m" > "$moonfile" || exit 1 ;} 9 | 10 | icon="$(cat "$moonfile")" 11 | 12 | case "$icon" in 13 | 🌑) name="New" ;; 14 | 🌒) name="Waxing Crescent" ;; 15 | 🌓) name="First Quarter" ;; 16 | 🌔) name="Waxing Gibbous" ;; 17 | 🌕) name="Full" ;; 18 | 🌖) name="Waning Gibbous" ;; 19 | 🌗) name="Last Quarter" ;; 20 | 🌘) name="Waning Crescent" ;; 21 | *) exit 1 ;; 22 | esac 23 | 24 | echo "${icon-?}" 25 | 26 | case $BLOCK_BUTTON in 27 | 3) notify-send "🌜 Moon phase module" "Displays current moon phase. 28 | - 🌑: New 29 | - 🌒: Waxing Crescent 30 | - 🌓: First Quarter 31 | - 🌔: Waxing Gibbous 32 | - 🌕: Full 33 | - 🌖: Waning Gibbous 34 | - 🌗: Last Quarter 35 | - 🌘: Waning Crescent" ;; 36 | 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; 37 | esac 38 | -------------------------------------------------------------------------------- /.config/lf/icons: -------------------------------------------------------------------------------- 1 | di 📁 2 | fi 📃 3 | tw 🤝 4 | ow 📂 5 | ln ⛓ 6 | or ❌ 7 | ex 🎯 8 | *.txt ✍ 9 | *.mom ✍ 10 | *.me ✍ 11 | *.ms ✍ 12 | *.avif 🖼 13 | *.png 🖼 14 | *.webp 🖼 15 | *.ico 🖼 16 | *.jpg 📸 17 | *.jpe 📸 18 | *.jpeg 📸 19 | *.gif 🖼 20 | *.svg 🗺 21 | *.tif 🖼 22 | *.tiff 🖼 23 | *.xcf 🖌 24 | *.html 🌎 25 | *.xml 📰 26 | *.gpg 🔒 27 | *.css 🎨 28 | *.pdf 📚 29 | *.djvu 📚 30 | *.epub 📚 31 | *.csv 📓 32 | *.xlsx 📓 33 | *.tex 📜 34 | *.md 📘 35 | *.r 📊 36 | *.R 📊 37 | *.rmd 📊 38 | *.Rmd 📊 39 | *.m 📊 40 | *.mp3 🎵 41 | *.opus 🎵 42 | *.ogg 🎵 43 | *.m4a 🎵 44 | *.flac 🎼 45 | *.wav 🎼 46 | *.mkv 🎥 47 | *.mp4 🎥 48 | *.webm 🎥 49 | *.mpeg 🎥 50 | *.avi 🎥 51 | *.mov 🎥 52 | *.mpg 🎥 53 | *.wmv 🎥 54 | *.m4b 🎥 55 | *.flv 🎥 56 | *.zip 📦 57 | *.rar 📦 58 | *.7z 📦 59 | *.tar 📦 60 | *.z64 🎮 61 | *.v64 🎮 62 | *.n64 🎮 63 | *.gba 🎮 64 | *.nes 🎮 65 | *.gdi 🎮 66 | *.1 ℹ 67 | *.nfo ℹ 68 | *.info ℹ 69 | *.log 📙 70 | *.iso 📀 71 | *.img 📀 72 | *.bib 🎓 73 | *.ged 👪 74 | *.part 💔 75 | *.torrent 🔽 76 | *.jar ♨ 77 | *.java ♨ 78 | -------------------------------------------------------------------------------- /.local/share/larbs/getkeys/mutt: -------------------------------------------------------------------------------- 1 | _ _ 2 | _ __ ___ _ _| |_| |_ 3 | | '_ ` _ \| | | | __| __| 4 | | | | | | | |_| | |_| |_ 5 | |_| |_| |_|\__,_|\__|\__| 6 | 7 | mutt is the email client. 8 | j/k - Move down/up 9 | d/u - Move down/up half page 10 | gg - Move to top 11 | v - View/download attachments 12 | G - Move to last message 13 | r - Reply 14 | R - Reply all 15 | S - Sync/save mailbox changes 16 | D - Mark message for deletion 17 | U - Unmark message for deletion 18 | ctrl-u - Seek urls 19 | ,, - Seek urls 20 | ctrl-f - Search mail indexed with notmuch 21 | ctrl-r - Mark all as read 22 | l - Limit mail 23 | o - Run quick sync with offlineimap 24 | O - Run full sync with offlineimap 25 | C - Copy a message to another mailbox 26 | M - Move a message to another mailbox 27 | B - Hide/reveal sidebar 28 | ctrl-j/k - Move down/up on sidebar 29 | ctrl-o - Open box selected in sidebar 30 | gi - Go to inbox 31 | gs - Go to sent mail 32 | gd - Go to drafts 33 | gS - Go to spam 34 | i# - Go to a different account (# is the number of the account) 35 | -------------------------------------------------------------------------------- /.local/bin/i3cmds/hover: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script moves the selected window to the bottom left/right of the screen. 4 | command -v xdotool || exit 1 5 | # If $1 is left, hovers in the bottom left, if right, the bottom right 6 | [ -z "$1" ] && exit 1 7 | 8 | padding=10 9 | current=$(xdotool getwindowfocus) 10 | newwidth=$(($(xdotool getdisplaygeometry | awk '{print $2}') / 3)) 11 | newheight=$(($(xdotool getdisplaygeometry | awk '{print $1}') / 3)) 12 | xdotool windowsize "$current" $newheight $newwidth 13 | newsize=$(xdotool getwindowgeometry "$current" | grep Geometry | sed -e 's/x/ /g' | awk '{print $3}') 14 | newwidth=$(xdotool getwindowgeometry "$current" | grep Geometry | grep -o " [0-9]*") 15 | 16 | case "$1" in 17 | left) horizontal=$padding; vertical=$(($(xdotool getdisplaygeometry | awk '{print $2}') - newsize - padding)) ;; 18 | right) horizontal=$(($(xdotool getdisplaygeometry | awk '{print $1}') - newwidth - padding)) ; vertical=$(($(xdotool getdisplaygeometry | awk '{print $2}') - newsize - padding)) ;; 19 | esac 20 | xdotool windowmove "$current" $horizontal $vertical 21 | -------------------------------------------------------------------------------- /.local/bin/sd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Open a terminal window in the same directory as the currently active window. 4 | 5 | windowPID=$(xprop -id "$(xprop -root | sed -n "/_NET_ACTIVE_WINDOW/ s/^.*# // p")" | sed -n "/PID/ s/^.*= // p") 6 | PIDlist=$(pstree -lpATna "$windowPID" | sed -En 's/.*,([0-9]+).*/\1/p' | tac) 7 | for PID in $PIDlist; do 8 | cmdline=$(ps -o args= -p "$PID") 9 | process_group_leader=$(ps -o comm= -p "$(ps -o pgid= -p "$PID" | tr -d ' ')") 10 | cwd=$(readlink /proc/"$PID"/cwd) 11 | # zsh and lf won't be ignored even if it shows ~ or / 12 | case "$cmdline" in 13 | 'lf -server') continue ;; 14 | "${SHELL##*/}"|'lf'|'lf '*) break ;; 15 | esac 16 | # git (and its sub-processes) will show the root of a repository instead of the actual cwd, so they're ignored 17 | [ "$process_group_leader" = 'git' ] || [ ! -d "$cwd" ] && continue 18 | # This is to ignore programs that show ~ or / instead of the actual working directory 19 | [ "$cwd" != "$HOME" ] && [ "$cwd" != '/' ] && break 20 | done 21 | [ "$PWD" != "$cwd" ] && [ -d "$cwd" ] && { cd "$cwd" || exit 1; } 22 | "$TERMINAL" 23 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-popupgrade: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | notify_pacman_i3_block() { 6 | pkill -RTMIN+8 "${STATUSBAR:-i3blocks}" 7 | } 8 | 9 | pac_upgrade() { 10 | if command -v pacapt >/dev/null 2>&1; then 11 | # On Ubuntu, pacapt can be used to upgrade system packages. 12 | # Snap is heavily utilized on Ubuntu. Upgrade snap packages as well. 13 | sudo pacapt -Syu 14 | sudo snap refresh 15 | elif pacman -Qq trizen >/dev/null; then 16 | trizen -Syu 17 | elif pacman -Qq paru >/dev/null; then 18 | paru -Syu 19 | else 20 | sudo pacman -Syu 21 | fi 22 | } 23 | 24 | pipx_upgrade() { 25 | if command -v pipx >/dev/null 2>&1; then 26 | pipx upgrade-all 27 | fi 28 | } 29 | 30 | main() { 31 | if ! command -v pacapt >/dev/null 2>&1; then 32 | archnews || exit 1 33 | fi 34 | 35 | echo "Beginning upgrade." 36 | pac_upgrade 37 | notify_pacman_i3_block 38 | remaps 39 | pipx_upgrade 40 | echo "Upgrade complete." 41 | 42 | if [ "$1" != "--no-wait" ]; then 43 | echo "Press to exit window." 44 | read -r _ 45 | fi 46 | } 47 | 48 | main "$@" 49 | -------------------------------------------------------------------------------- /.config/fontconfig/conf.d/40-fonts.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | serif 6 | 7 | Libertinus Serif 8 | Joy Pixels 9 | Noto Color Emoji 10 | FontAwesome 11 | 12 | 13 | 14 | sans-serif 15 | 16 | Libertinus Sans 17 | Joy Pixels 18 | Noto Color Emoji 19 | FontAwesome 20 | 21 | 22 | 23 | sans 24 | 25 | Libertinus Sans 26 | Joy Pixels 27 | Noto Color Emoji 28 | FontAwesome 29 | 30 | 31 | 32 | monospace 33 | 34 | Noto Sans Mono 35 | Libertinus Mono 36 | FontAwesome 37 | Braille 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /.config/x11/xinitrc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # xinitrc runs automatically when you run startx. 4 | # https://wiki.archlinux.org/index.php/Xinit#xinitrc 5 | export GDK_BACKEND=x11 6 | export XDG_SESSION_TYPE=x11 7 | 8 | # https://forum.manjaro.org/t/how-to-theme-gtk4-apps-in-manjaro-xfce/100189/7 9 | # https://forum.manjaro.org/t/setting-theme-for-gtk4-applications/165845 10 | export GTK_THEME='Arc-Darker' 11 | 12 | # Start some nice programs 13 | if [ -d /etc/X11/xinit/xinitrc.d ]; then 14 | for f in /etc/X11/xinit/xinitrc.d/?*.sh; do 15 | # shellcheck source=/dev/null 16 | [ -x "$f" ] && . "$f" 17 | done 18 | unset f 19 | fi 20 | 21 | # There are some small but important commands that need to be run 22 | # when we start the graphical environment. 23 | # shellcheck source=/dev/null 24 | . "${XDG_CONFIG_HOME:-$HOME/.config}/x11/xprofile" 25 | 26 | # Activate dbus variables 27 | dbus-update-activation-environment --all 28 | 29 | # Your default WM is determined in your `~/.profile` on login. 30 | # Here we run the proper command to run when the graphical environment starts. 31 | dbus-launch ssh-agent "${WM:-i3}" 32 | -------------------------------------------------------------------------------- /.local/bin/unmounter: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Unmount USB drives or Android phones. Replaces the older `dmenuumount`. Fewer 4 | # prompt and also de-decrypts LUKS drives that are unmounted. 5 | 6 | set -e 7 | 8 | mounteddroids="$(grep simple-mtpfs /etc/mtab | awk '{print "📱" $2}')" 9 | lsblkoutput="$(lsblk -nrpo "name,type,size,mountpoint")" 10 | mounteddrives="$(echo "$lsblkoutput" | awk '($2=="part"||$2="crypt")&&$4!~/\/boot|\/home$|SWAP/&&length($4)>1{printf "💾%s (%s)\n",$4,$3}')" 11 | 12 | allunmountable="$(echo "$mounteddroids 13 | $mounteddrives" | sed "/^$/d;s/ *$//")" 14 | test -n "$allunmountable" 15 | 16 | chosen="$(echo "$allunmountable" | dmenu -i -p "Unmount which drive?")" 17 | chosen="${chosen%% *}" 18 | test -n "$chosen" 19 | 20 | sudo -A umount -l "/${chosen#*/}" 21 | notify-send "Device unmounted." "$chosen has been unmounted." 22 | 23 | # Close the chosen drive if decrypted. 24 | cryptid="$(echo "$lsblkoutput" | grep "/${chosen#*/}$")" 25 | cryptid="${cryptid%% *}" 26 | test -b /dev/mapper/"${cryptid##*/}" 27 | sudo -A cryptsetup close "$cryptid" 28 | notify-send "🔒Device dencryption closed." "Drive is now securely locked again." 29 | -------------------------------------------------------------------------------- /.local/bin/remaps: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is called on startup to remap keys. 4 | 5 | # 1. Power saving behaviour of monitors when the computer is not in use 6 | # Disable screen saver blanking and set all the DPMS timeouts to zero. 7 | # https://wiki.archlinux.org/index.php/Display_Power_Management_Signaling 8 | # 9 | # 2. Override LXDE keyboard/mouse settings 10 | # Decrease key repeat delay to 300ms and increase key repeat rate to 50 per second. 11 | # 12 | # Mouse: xset m accel_mult[/accel_div] [threshold] 13 | # Autorepeat: xset r rate delay [rate] 14 | # TIP: The q option gives you information on the current settings. 15 | xset \ 16 | s off \ 17 | dpms 0 0 0 \ 18 | m 0 0 \ 19 | r rate 300 50 \ 20 | b off 21 | 22 | # Map the caps lock key to super, and map the menu key to right super. 23 | setxkbmap -option terminate:ctrl_alt_bksp,caps:super,altwin:menu_win 24 | 25 | # When caps lock is pressed only once, treat it as escape. 26 | killall xcape || true 27 | xcape -e 'Super_L=Escape' 28 | 29 | # Turn off caps lock if on since there is no longer a key for it. 30 | if xset -q | grep -q "Caps Lock:\s*on"; then 31 | xdotool key Caps_Lock 32 | fi 33 | -------------------------------------------------------------------------------- /.local/bin/lf-file-op: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | # Take file path and copy it to the clipboard in one of the three formats: uri, path, filename. 6 | 7 | rawurlencode() { 8 | # /questions/296536/how-to-urlencode-data-for-curl-command 9 | local -r string=${1} 10 | local -r strlen=${#string} 11 | local encoded="" 12 | local pos c o 13 | 14 | for (( pos=0 ; pos Options > External Program 5 | # You'll be able to play the audio in qolibri and paste it in an Anki note as an ogg/opus file. 6 | # When run from Qolibri, $1 is guaranteed to be the path to an audio file. 7 | 8 | readonly file_path=${1:?} 9 | readonly tmp_file_path=/tmp/qolibri-$RANDOM.ogg 10 | readonly bitrate=32k 11 | 12 | to_opus() { 13 | local -r in=${1:?} out=${2:?} 14 | ffmpeg \ 15 | -y \ 16 | -vn \ 17 | -nostdin \ 18 | -hide_banner \ 19 | -loglevel info \ 20 | -i "$in" \ 21 | -acodec libopus \ 22 | -map_metadata -1 \ 23 | -ac 1 \ 24 | -ab "$bitrate" \ 25 | -vbr on \ 26 | -compression_level 10 \ 27 | -application voip \ 28 | "$out" 29 | } 30 | 31 | # Play the file 32 | mpv --keep-open=no --force-window=no "$1" & 33 | 34 | # Convert from wav to ogg/opus 35 | to_opus "$file_path" "$tmp_file_path" 36 | 37 | # Copy the URI to clipboard. 38 | echo "file://$tmp_file_path" | xclip -in -selection clipboard -target "text/uri-list" 39 | 40 | # Clean up after 60 seconds. 41 | sleep 60s 42 | rm -- "$tmp_file_path" 43 | wait 44 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-music: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | filter() { 4 | input=$( 5 | cat -- - | 6 | sed \ 7 | -e '/^volume:/d;' -e 's/ *$//' -e 's/&/\&/g' \ 8 | -e 's//\>/g' 10 | ) 11 | songname="$(echo "$input" | head -1)" 12 | 13 | if [ -z "$songname" ]; then 14 | echo " Stopped" 15 | echo "" 16 | echo "#888888" 17 | return 18 | fi 19 | 20 | if echo "$input" | tail -1 | grep -q 'playing'; then 21 | echo " $songname" 22 | echo " $songname" | colrm 30 23 | else 24 | echo " $songname" 25 | echo "$(echo " $songname" | colrm 30)" 26 | fi 27 | } 28 | 29 | { pidof -x sb-mpdup || setsid -f sb-mpdup; } >/dev/null 2>&1 & 30 | 31 | case $BLOCK_BUTTON in 32 | 1) # left click, launch ncmpcpp 33 | mpc status | filter 34 | setsid -f "$TERMINAL" -e ncmpcpp -s playlist 35 | ;; 36 | 37 | 3) # right click, pause/unpause 38 | mpc toggle | filter ;; 39 | 40 | 4) # scroll up, previous 41 | mpc prev | filter ;; 42 | 43 | 5) # scroll down, next 44 | mpc next | filter ;; 45 | 46 | 6) # edit 47 | mpc status | filter 48 | setsid -f "$TERMINAL" -e "$EDITOR" "$0" 49 | ;; 50 | 51 | *) 52 | mpc status | filter 53 | ;; 54 | esac 55 | -------------------------------------------------------------------------------- /.config/ncmpcpp/bindings: -------------------------------------------------------------------------------- 1 | def_key "+" 2 | show_clock 3 | def_key "=" 4 | volume_up 5 | def_key "j" 6 | scroll_down 7 | def_key "k" 8 | scroll_up 9 | def_key "ctrl-u" 10 | page_up 11 | def_key "ctrl-d" 12 | page_down 13 | def_key "u" 14 | page_up 15 | def_key "d" 16 | page_down 17 | def_key "h" 18 | previous_column 19 | def_key "l" 20 | next_column 21 | def_key "." 22 | show_lyrics 23 | def_key "n" 24 | next_found_item 25 | def_key "N" 26 | previous_found_item 27 | def_key "J" 28 | move_sort_order_down 29 | def_key "K" 30 | move_sort_order_up 31 | def_key "h" 32 | jump_to_parent_directory 33 | def_key "l" 34 | enter_directory 35 | def_key "l" 36 | run_action 37 | def_key "l" 38 | play_item 39 | def_key "m" 40 | show_media_library 41 | def_key "m" 42 | toggle_media_library_columns_mode 43 | def_key "t" 44 | show_tag_editor 45 | def_key "v" 46 | show_visualizer 47 | def_key "G" 48 | move_end 49 | def_key "g" 50 | move_home 51 | def_key "U" 52 | update_database 53 | def_key "s" 54 | reset_search_engine 55 | def_key "s" 56 | show_search_engine 57 | def_key "f" 58 | show_browser 59 | def_key "f" 60 | change_browse_mode 61 | def_key "x" 62 | delete_playlist_items 63 | def_key "P" 64 | show_playlist 65 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-cpubars: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Module showing CPU load as a changing bars. 4 | # Just like in polybar. 5 | # Each bar represents amount of load on one core since 6 | # last run. 7 | 8 | # Cache in tmpfs to improve speed and reduce SSD load 9 | cache=/tmp/cpubarscache 10 | 11 | case $BLOCK_BUTTON in 12 | 2) setsid -f "$TERMINAL" -e htop ;; 13 | 3) notify-send "CPU load module" "Each bar represents one CPU core" &;; 14 | 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; 15 | esac 16 | 17 | # id total idle 18 | stats=$(awk '/cpu[0-9]+/ {printf "%d %d %d\n", substr($1,4), ($2 + $3 + $4 + $5), $5 }' /proc/stat) 19 | [ ! -f $cache ] && echo "$stats" >"$cache" 20 | old=$(cat "$cache") 21 | [ -n "$LABEL" ] && printf "$LABEL " 22 | echo "$stats" | while read -r row; do 23 | id=${row%% *} 24 | rest=${row#* } 25 | total=${rest%% *} 26 | idle=${rest##* } 27 | 28 | case "$(echo "$old" | awk '{if ($1 == id) 29 | printf "%d\n", (1 - (idle - $3) / (total - $2))*100 /12.5}' \ 30 | id="$id" total="$total" idle="$idle")" in 31 | 32 | "0") printf "▁" ;; 33 | "1") printf "▂" ;; 34 | "2") printf "▃" ;; 35 | "3") printf "▄" ;; 36 | "4") printf "▅" ;; 37 | "5") printf "▆" ;; 38 | "6") printf "▇" ;; 39 | "7") printf "█" ;; 40 | "8") printf "█" ;; 41 | esac 42 | done 43 | printf "\\n" 44 | echo "$stats" >"$cache" 45 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-disk: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Status bar module for disk space 4 | 5 | readonly DIR="${BLOCK_INSTANCE:-/}" 6 | 7 | notify_stats() { 8 | local -r stats=$( 9 | df -hl --output=target,used,size,pcent -x devtmpfs -x tmpfs -x efivarfs | 10 | sed 's/^\/home.*$/&<\/span><\/b>/' 11 | ) 12 | local -r swap_stats=$( 13 | { 14 | printf -- "Device\tUsed\tSize\tUse%%\n" 15 | swapon -s | 16 | sed '1d' | 17 | awk '{ printf "%s\t%0.2fG\t%0.2fG\t%d%\n", $1, $4 / 1024 / 1024, $3 / 1024 / 1024, $4 / $3 * 100; }'; 18 | } | column -t -s$'\t' 19 | ) 20 | setsid -f notify-send -t 30000 " Disk space" "$stats\n\n$swap_stats" & 21 | } 22 | 23 | case $BLOCK_BUTTON in 24 | 1) notify_stats ;; 25 | 3) setsid -f "$TERMINAL" -e ncdu "$DIR" ;; 26 | 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; 27 | esac 28 | 29 | df -h "$DIR" --output=avail,pcent,target | awk ' 30 | /[0-9]/ { 31 | if ($3 ~ "/home") { 32 | dir_icon="" 33 | } else { 34 | dir_icon="" 35 | } 36 | 37 | print $3 " " $1 38 | print dir_icon " " $1 39 | 40 | # convert usage percent to integer 41 | gsub("%", "", $2) 42 | $2 = int($2) 43 | 44 | # color 45 | if ($2 > 90) { 46 | print("#FF0000") 47 | } else if ($2 > 80) { 48 | print("#FFAE00") 49 | } else if ($2 > 70) { 50 | print("#FFF600") 51 | } 52 | exit 53 | }' 54 | -------------------------------------------------------------------------------- /.config/mpv/input.conf: -------------------------------------------------------------------------------- 1 | # mpv keybindings 2 | 3 | # Increase / decrease subtitle font size 4 | # https://www.reddit.com/r/mpv/comments/dg5yzj/trouble_decreasing_subtitles_size/ 5 | / add sub-scale +0.1 6 | ? add sub-scale -0.1 7 | 8 | # AO volume controls (numpad): 9 | #+ add ao-volume 2 10 | #- add ao-volume -2 11 | 12 | # Cycle video aspect ratios; "-1" is the container aspect 13 | A cycle-values video-aspect "16:9" "16:10" "4:3" "2.35:1" "-1" 14 | 15 | # Vim-like seeking 16 | l seek 5 17 | h seek -5 18 | j seek -60 19 | k seek 60 20 | 21 | # Cycle between subtitle files 22 | K cycle sub 23 | J cycle sub down 24 | 25 | # Skip to previous/next subtitle line (disabled - use mpvacioius) 26 | #H no-osd sub-seek -1 27 | #L no-osd sub-seek 1 28 | 29 | # Search sub-text on Jisho.org 30 | # https://github.com/mpv-player/mpv/issues/4695#issuecomment-609876072 31 | #Ctrl+j run "/bin/sh" "-c" "xdg-open 'https://jisho.org/search?keyword=${sub-text}'" 32 | 33 | # skip to next/previous file 34 | > playlist-next 35 | < playlist-prev 36 | 37 | # Add/subtract 100 ms delay from subs 38 | Z add sub-delay +0.1 39 | z add sub-delay -0.1 40 | 41 | # Adjust timing to previous/next subtitle 42 | X sub-step 1 43 | x sub-step -1 44 | 45 | V script-binding visibility 46 | 47 | # Mouse wheel movements 48 | #WHEEL_UP add volume 2 49 | #WHEEL_DOWN add volume -2 50 | #WHEEL_UP seek 5 51 | #WHEEL_DOWN seek -5 52 | -------------------------------------------------------------------------------- /.config/zathura/zathurarc: -------------------------------------------------------------------------------- 1 | # Zathura configuration file 2 | # See man `man zathurarc' 3 | 4 | # Open document in fit-width mode by default 5 | 6 | set adjust-open "best-fit" 7 | 8 | # One page per row by default 9 | 10 | set pages-per-row 1 11 | 12 | # Zoom settings 13 | 14 | set zoom-min 10 15 | set recolor-reverse-video "true" 16 | set recolor-keephue "true" 17 | set recolor "false" 18 | set render-loading "false" 19 | set scroll-step 50 20 | set guioptions "shv" 21 | set font "Hack 12" 22 | set selection-clipboard "clipboard" 23 | set window-title-basename "true" 24 | set sandbox none 25 | set statusbar-h-padding 0 26 | set statusbar-v-padding 0 27 | set page-padding 1 28 | set selection-clipboard clipboard 29 | map D toggle_page_mode 30 | map r reload 31 | map R rotate 32 | map i recolor 33 | map p print 34 | map g goto top 35 | map u scroll half-up 36 | map d scroll half-down 37 | map m toggle_page_mode 38 | 39 | # Scroll 40 | 41 | set scroll-page-aware "true" 42 | set smooth-scroll "true" 43 | set scroll-full-overlap 0.01 44 | set scroll-step 100 45 | 46 | map [fullscreen] u scroll half-up 47 | map [fullscreen] d scroll half-down 48 | map [fullscreen] D toggle_page_mode 49 | map [fullscreen] r reload 50 | map [fullscreen] R rotate 51 | map [fullscreen] K zoom in 52 | map [fullscreen] J zoom out 53 | map [fullscreen] i recolor 54 | map [fullscreen] p print 55 | map [fullscreen] g goto top 56 | -------------------------------------------------------------------------------- /.config/fontconfig/conf.d/20-symbols.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 26 | 27 | 28 | 29 | Hack 30 | 31 | Pomodoro 32 | FontAwesome 33 | Octicons 34 | Icomoon 35 | PowerlineSymbols 36 | Noto Sans Mono CJK JP 37 | Noto Color Emoji 38 | Hack Nerd Font Mono 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /.config/ncmpcpp/config: -------------------------------------------------------------------------------- 1 | # vim: filetype=conf 2 | 3 | ncmpcpp_directory = "~/.config/ncmpcpp" 4 | lyrics_directory = "~/.local/share/lyrics" 5 | mpd_music_dir = "/mnt/archive/audio" 6 | message_delay_time = "1" 7 | visualizer_type = "spectrum" 8 | song_list_format = {$4%a - }{%t}|{$8%f$9}$R{$3(%l)$9} 9 | song_status_format = $b{{$8"%t"}} $3by {$4%a{ $3in $7%b{ (%y)}} $3}|{$8%f} 10 | song_library_format = {%n - }{%t}|{%f} 11 | alternative_header_first_line_format = $b$1$aqqu$/a$9 {%t}|{%f} $1$atqq$/a$9$/b 12 | alternative_header_second_line_format = {{$4$b%a$/b$9}{ - $7%b$9}{ ($4%y$9)}}|{%D} 13 | current_item_prefix = $(cyan)$r$b 14 | current_item_suffix = $/r$(end)$/b 15 | current_item_inactive_column_prefix = $(magenta)$r 16 | current_item_inactive_column_suffix = $/r$(end) 17 | playlist_display_mode = columns 18 | browser_display_mode = columns 19 | progressbar_look = -> 20 | media_library_primary_tag = album_artist 21 | media_library_albums_split_by_date = no 22 | startup_screen = "media_library" 23 | display_volume_level = no 24 | ignore_leading_the = yes 25 | external_editor = nvim 26 | use_console_editor = yes 27 | empty_tag_color = magenta 28 | main_window_color = white 29 | progressbar_color = black:b 30 | progressbar_elapsed_color = blue:b 31 | statusbar_color = red 32 | statusbar_time_color = cyan:b 33 | execute_on_song_change="pkill -RTMIN+11 i3blocks" 34 | execute_on_player_state_change="pkill -RTMIN+11 i3blocks" 35 | -------------------------------------------------------------------------------- /.local/bin/weath: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Get the weather on the terminal. You can pass an alternative location as a parameter, 4 | # and/or use the 'cp' option to copy the forecast as plaintext to the clipboard. 5 | 6 | report="${XDG_CACHE_HOME:-$HOME/.cache}/weatherreport" 7 | 8 | if [ "$1" = 'cp' ]; then 9 | # shellcheck disable=SC2015 10 | [ -z "$2" ] && sed 's/\x1b\[[^m]*m//g' "$report" | xclip -selection clipboard && 11 | notify-send "Weather forecast for '${LOCATION:-$(head -n 1 "$report" | cut -d' ' -f3-)}' copied to clipboard." || 12 | { data="$(curl -sfm 5 "${WTTRURL:-wttr.in}/$2?T")" && 13 | notify-send "Weather forecast for '$2' copied to clipboard." && 14 | echo "$data" | xclip -selection clipboard || 15 | notify-send 'Failed to get weather forecast!' 'Check your internet connection and the supplied location.'; } 16 | else 17 | [ -n "$2" ] && 18 | notify-send "Invalid option '$1'! The only valid option is 'cp'." && 19 | exit 1 20 | 21 | # shellcheck disable=SC2015 22 | [ -z "$1" ] && less -S "$report" || 23 | data="$(curl -sfm 5 "${WTTRURL:-wttr.in}/$1")" && echo "$data" | less -S || 24 | notify-send 'Failed to get weather forecast!' 'Check your internet connection and the supplied location.' 25 | fi 26 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-internet: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Show wifi 📶 and percent strength or 📡 if none. 4 | # Show 🌐 if connected to ethernet or ❎ if none. 5 | # Show 🔒 if a vpn connection is active 6 | 7 | case $BLOCK_BUTTON in 8 | 1) 9 | "$TERMINAL" -e nmtui 10 | pkill -RTMIN+4 "${STATUSBAR:-i3blocks}" 11 | ;; 12 | 3) 13 | notify-send "🌐 Internet module" "\- Click to connect 14 | ❌: wifi disabled 15 | 📡: no wifi connection 16 | 📶: wifi connection with quality 17 | ❎: no ethernet 18 | 🌐: ethernet working 19 | 🔒: vpn is active 20 | " & 21 | ;; 22 | 6) 23 | setsid -f "$TERMINAL" -e "$EDITOR" "$0" 24 | ;; 25 | esac 26 | 27 | wifi_status() { 28 | if [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'up' ] ; then 29 | awk '/^\s*w/ { printf " %d%\n", int($3 * 10 / 7) }' /proc/net/wireless 30 | elif [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'down' ] ; then 31 | if [ "$(cat /sys/class/net/w*/flags 2>/dev/null)" = '0x1003' ];then 32 | echo 📡 33 | else 34 | echo ❌ 35 | fi 36 | fi 37 | } 38 | 39 | ethernet_status() { 40 | if [ "$(cat /sys/class/net/e*/operstate 2>/dev/null)" = 'up' ]; then 41 | echo 🌐 42 | else 43 | echo ❎ 44 | fi 45 | } 46 | 47 | vpn_status() { 48 | if [ -n "$(cat /sys/class/net/tun*/operstate 2>/dev/null)" ];then 49 | echo 🔒 50 | fi 51 | } 52 | 53 | printf -- '%s%s%s\n' \ 54 | "$(wifi_status)" \ 55 | "$(ethernet_status)" \ 56 | "$(vpn_status)" | 57 | sed 's/^ *\| *$//g' 58 | -------------------------------------------------------------------------------- /.local/bin/rotdir: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # When I open an image from the file manager in nsxiv (the image viewer), I want 4 | # to be able to press the next/previous keys to key through the rest of the 5 | # images in the same directory. This script "rotates" the content of a 6 | # directory based on the first chosen file, so that if I open the 15th image, 7 | # if I press next, it will go to the 16th etc. Autistic, I know, but this is 8 | # one of the reasons that nsxiv is great for being able to read standard input. 9 | 10 | import os 11 | import re 12 | import sys 13 | 14 | if len(sys.argv) < 2: 15 | sys.exit('usage: rotdir filename') 16 | 17 | 18 | def as_numeric(text: str) -> int | str: 19 | return int(text) if text.isdigit() else text.lower() 20 | 21 | 22 | def alphanum_key(text: str) -> tuple[str | int, ...]: 23 | return tuple(as_numeric(c) for c in re.split('([0-9]+)', text)) 24 | 25 | 26 | def natural_sort(file_list: list[str]) -> list[str]: 27 | return sorted(file_list, key=alphanum_key) 28 | 29 | 30 | def selected_file_name() -> str: 31 | return os.path.basename(''.join(sys.argv[1:])) 32 | 33 | 34 | def list_current_dir() -> list[str]: 35 | return os.listdir(os.getcwd()) 36 | 37 | 38 | def main(): 39 | ls = natural_sort(list_current_dir()) 40 | base_index = ls.index(selected_file_name()) 41 | result = ls[base_index:] + ls[:base_index] 42 | print('\n'.join(result)) 43 | 44 | 45 | if __name__ == '__main__': 46 | main() 47 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-pulsevol: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Prints the current volume. 4 | # 5 | # Pamixer options: 6 | # --list-sinks list the sinks 7 | # --list-sources list the sources 8 | # "instance" field of the block should be "sink 0", "source 1", etc. 9 | 10 | { pidof -x sb-headphone-plug || setsid -f sb-headphone-plug; } >/dev/null 2>&1 & 11 | 12 | instance() { 13 | pamixer "${DEVICE[@]}" "$@" 14 | } 15 | 16 | mixer() { 17 | if command -v pavucontrol &>/dev/null; then 18 | i3-msg -q exec pavucontrol 19 | else 20 | i3-msg -q exec 'i3-sensible-terminal -e pulsemixer' 21 | fi 22 | } 23 | 24 | if [[ -n "$BLOCK_INSTANCE" ]]; then 25 | read -r -a DEVICE <<<"--$BLOCK_INSTANCE" 26 | fi 27 | 28 | if [[ $BLOCK_INSTANCE == *source* ]]; then 29 | readonly block_icon='' 30 | readonly block_icon_mute='' 31 | else 32 | readonly block_icon='' 33 | readonly block_icon_mute='' 34 | fi 35 | 36 | # Handle mouse actions 37 | case $BLOCK_BUTTON in 38 | 1) mixer ;; # left click, run pavucontrol 39 | 3) instance --toggle-mute ;; # right click, mute/unmute 40 | 4) instance --unmute -i 5 ;; # scroll up, increase 41 | 5) instance --unmute -d 5 ;; # scroll down, decrease 42 | esac 43 | 44 | # Output status 45 | case $(instance --get-mute) in 46 | "0" | "false") 47 | echo "$block_icon $(instance --get-volume | cut -d' ' -f1)%" 48 | ;; 49 | "1" | "true") 50 | echo "$block_icon_mute MUTE" 51 | echo "$block_icon_mute" 52 | echo "#aaaaaa" 53 | ;; 54 | *) 55 | echo ERROR 56 | echo E 57 | echo "#ff0000" 58 | ;; 59 | esac 60 | -------------------------------------------------------------------------------- /.config/i3blocks/config: -------------------------------------------------------------------------------- 1 | ## i3blocks config file 2 | 3 | # Global properties 4 | command=~/.local/bin/statusbar/$BLOCK_NAME 5 | separator_block_width=10 6 | markup=none 7 | full_text=  8 | align=left 9 | color=#f3f4f5 10 | separator=true 11 | interval=5 12 | 13 | [sb-music] 14 | interval=10 15 | signal=11 16 | markup=pango 17 | 18 | [sb-memory] 19 | separator=false 20 | interval=10 21 | 22 | [sb-memory] 23 | instance=swap 24 | interval=15 25 | 26 | [sb-disk] 27 | instance=/home 28 | interval=30 29 | 30 | [sb-nettraf] 31 | interval=5 32 | 33 | [sb-cpu_usage] 34 | LABEL=CPU 35 | interval=2 36 | separator=false 37 | 38 | [sb-cpu_freq] 39 | interval=5 40 | 41 | [sb-load_average] 42 | interval=3 43 | 44 | [sb-chip_temp] 45 | chip_label=CPU 46 | query=sensors coretemp-isa-0000 | awk '/^Package/ {print $4}' 47 | interval=5 48 | 49 | #[chip_temp] 50 | #chip_label=GPU 51 | #query=sensors amdgpu-pci-0300 | awk '/^junction/ {print $2}' 52 | #interval=7 53 | 54 | [sb-pacpackages] 55 | interval=3600 56 | signal=8 57 | 58 | [sb-pulsevol] 59 | signal=10 60 | interval=10 61 | separator=false 62 | 63 | [sb-pulsevol] 64 | signal=10 65 | interval=10 66 | instance=default-source 67 | 68 | [sb-weather] 69 | interval=1800 70 | command=curlwttr "$LOCATION?format=1" || echo '±?°C' 71 | 72 | [sb-calendar] 73 | interval=30 74 | separator=false 75 | 76 | [sb-time] 77 | command=date '+%H:%M' 78 | interval=4 79 | separator=false 80 | separator_block_width=5 81 | 82 | [sb-record] 83 | command=cat /tmp/recordingicon 2>/dev/null || echo 84 | interval=once 85 | signal=9 86 | background=#6d3d39 87 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-nettraf: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Module showing network traffic. Shows how much data has been received (RX) or 4 | # transmitted (TX) since the previous time this script ran. So if run every 5 | # second, gives network traffic per second. 6 | 7 | readonly cache_fol="/tmp/${0##*/}" 8 | mkdir -p "$cache_fol" 9 | 10 | local_info() { 11 | sb-local_ipaddr | head -1 12 | } 13 | 14 | public_info() { 15 | curl -s 'https://ifconfig.co/json' | sed -n \ 16 | -e 's/\"//g;' \ 17 | -e 's/,$//g;' \ 18 | -e 's/^ *//g;' \ 19 | -e '2s/ip/Public/p;' \ 20 | -e '4s/^c/C/p;' \ 21 | -e '7s/region_name/City/p;' 22 | } 23 | 24 | update() { 25 | local sum=0 old=0 26 | local -r cache_file="${cache_fol}/${1##*/}" 27 | for arg; do 28 | read -r i <"$arg" 29 | sum=$((sum + i)) 30 | done 31 | unset arg 32 | [ -f "$cache_file" ] && read -r old <"$cache_file" || old=0 33 | printf -- '%d\n' "$sum" >"$cache_file" 34 | printf -- '%d\n' "$(((sum - old) / ${interval:-1}))" 35 | } 36 | 37 | case "$BLOCK_BUTTON" in 38 | 1) 39 | notify-send " Connection info" "$(local_info)\\n$(public_info)" & 40 | ;; 41 | 2) 42 | setsid -f "$TERMINAL" -e bmon & 43 | ;; 44 | 6) 45 | setsid -f "$TERMINAL" -e "$EDITOR" "$0" 46 | ;; 47 | esac 48 | 49 | readonly rx=$(update /sys/class/net/[ew]*/statistics/rx_bytes) 50 | readonly tx=$(update /sys/class/net/[ew]*/statistics/tx_bytes) 51 | readonly in=$(numfmt --to=iec "$rx") 52 | readonly out=$(numfmt --to=iec "$tx") 53 | 54 | if [ "$rx" -ge 0 ] && [ "$tx" -ge 0 ]; then 55 | printf -- 'IN %s OUT %s\n %s  %s\n' "$in" "$out" "$in" "$out" 56 | fi 57 | -------------------------------------------------------------------------------- /.local/bin/tag: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | err() { echo "Usage: 4 | tag [OPTIONS] file 5 | Options: 6 | -a: artist/author 7 | -t: song/chapter title 8 | -A: album/book title 9 | -n: track/chapter number 10 | -N: total number of tracks/chapters 11 | -d: year of publication 12 | -g: genre 13 | -c: comment 14 | You will be prompted for title, artist, album and track if not given." && exit 1 ;} 15 | 16 | while getopts "a:t:A:n:N:d:g:c:" o; do case "${o}" in 17 | a) artist="${OPTARG}" ;; 18 | t) title="${OPTARG}" ;; 19 | A) album="${OPTARG}" ;; 20 | n) track="${OPTARG}" ;; 21 | N) total="${OPTARG}" ;; 22 | d) date="${OPTARG}" ;; 23 | g) genre="${OPTARG}" ;; 24 | c) comment="${OPTARG}" ;; 25 | *) printf "Invalid option: -%s\\n" "$OPTARG" && err ;; 26 | esac done 27 | 28 | shift $((OPTIND - 1)) 29 | 30 | file="$1" 31 | 32 | temp="$(mktemp -p "$(dirname "$file")")" 33 | trap 'rm -f $temp' HUP INT QUIT TERM PWR EXIT 34 | 35 | [ ! -f "$file" ] && echo 'Provide file to tag.' && err 36 | 37 | [ -z "$title" ] && echo 'Enter a title.' && read -r title 38 | [ -z "$artist" ] && echo 'Enter an artist.' && read -r artist 39 | [ -z "$album" ] && echo 'Enter an album.' && read -r album 40 | [ -z "$track" ] && echo 'Enter a track number.' && read -r track 41 | 42 | cp -f "$file" "$temp" && ffmpeg -i "$temp" -map 0 -y -codec copy \ 43 | -metadata title="$title" \ 44 | -metadata album="$album" \ 45 | -metadata artist="$artist" \ 46 | -metadata track="${track}${total:+/"$total"}" \ 47 | ${date:+-metadata date="$date"} \ 48 | ${genre:+-metadata genre="$genre"} \ 49 | ${comment:+-metadata comment="$comment"} "$file" 50 | -------------------------------------------------------------------------------- /.local/bin/termcolors: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # ANSI color scheme script for testing terminal colors 4 | # 5 | # Original: http://crunchbang.org/forums/viewtopic.php?pid=126921%23p126921#p126921 6 | # Modified by lolilolicon 7 | # 8 | # shellcheck disable=SC2154 9 | # shellcheck disable=SC2034 10 | 11 | f=3 b=4 12 | for j in f b; do 13 | for i in {0..7}; do 14 | printf -v $j$i %b "\e[${!j}${i}m" 15 | done 16 | done 17 | bld=$'\e[1m' 18 | rst=$'\e[0m' 19 | 20 | cat << EOF 21 | 22 | $f1 ▀▄ ▄▀ $f2 ▄▄▄████▄▄▄ $f3 ▄██▄ $f4 ▀▄ ▄▀ $f5 ▄▄▄████▄▄▄ $f6 ▄██▄ $rst 23 | $f1 ▄█▀███▀█▄ $f2███▀▀██▀▀███ $f3▄█▀██▀█▄ $f4 ▄█▀███▀█▄ $f5███▀▀██▀▀███ $f6▄█▀██▀█▄$rst 24 | $f1█▀███████▀█ $f2▀▀███▀▀███▀▀ $f3▀█▀██▀█▀ $f4█▀███████▀█ $f5▀▀███▀▀███▀▀ $f6▀█▀██▀█▀$rst 25 | $f1▀ ▀▄▄ ▄▄▀ ▀ $f2 ▀█▄ ▀▀ ▄█▀ $f3▀▄ ▄▀ $f4▀ ▀▄▄ ▄▄▀ ▀ $f5 ▀█▄ ▀▀ ▄█▀ $f6▀▄ ▄▀$rst 26 | 27 | $bld$f1▄ ▀▄ ▄▀ ▄ $f2 ▄▄▄████▄▄▄ $f3 ▄██▄ $f4▄ ▀▄ ▄▀ ▄ $f5 ▄▄▄████▄▄▄ $f6 ▄██▄ $rst 28 | $bld$f1█▄█▀███▀█▄█ $f2███▀▀██▀▀███ $f3▄█▀██▀█▄ $f4█▄█▀███▀█▄█ $f5███▀▀██▀▀███ $f6▄█▀██▀█▄$rst 29 | $bld$f1▀█████████▀ $f2▀▀▀██▀▀██▀▀▀ $f3▀▀█▀▀█▀▀ $f4▀█████████▀ $f5▀▀▀██▀▀██▀▀▀ $f6▀▀█▀▀█▀▀$rst 30 | $bld$f1 ▄▀ ▀▄ $f2▄▄▀▀ ▀▀ ▀▀▄▄ $f3▄▀▄▀▀▄▀▄ $f4 ▄▀ ▀▄ $f5▄▄▀▀ ▀▀ ▀▀▄▄ $f6▄▀▄▀▀▄▀▄$rst 31 | 32 | 33 | $f7▌$rst 34 | 35 | $f7▌$rst 36 | 37 | $f7 ▄█▄ $rst 38 | $f7▄█████████▄$rst 39 | $f7▀▀▀▀▀▀▀▀▀▀▀$rst 40 | 41 | EOF 42 | -------------------------------------------------------------------------------- /.local/bin/dmenuhandler: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Feed this script a link and it will give dmenu 4 | # some choice programs to use to open it. 5 | feed="${1:-$(true | dmenu -p 'Paste URL or file path')}" 6 | 7 | case "$(printf "copy url\\nnsxiv\\nsetbg\\nPDF\\nbrowser\\nlynx\\nvim\\nmpv\\nmpv loop\\nmpv float\\nqueue download\\nqueue yt-dlp\\nqueue yt-dlp audio" | dmenu -i -p "Open it with?")" in 8 | "copy url") echo "$feed" | xclip -selection clipboard ;; 9 | mpv) setsid -f mpv -quiet "$feed" >/dev/null 2>&1 ;; 10 | "mpv loop") setsid -f mpv -quiet --loop "$feed" >/dev/null 2>&1 ;; 11 | "mpv float") setsid -f "$TERMINAL" -e mpv --geometry=+0-0 --autofit=30% --title="mpvfloat" "$feed" >/dev/null 2>&1 ;; 12 | "queue yt-dlp") qndl "$feed" >/dev/null 2>&1 ;; 13 | "queue yt-dlp audio") qndl "$feed" 'yt-dlp -o "%(title)s.%(ext)s" -f bestaudio --embed-metadata --restrict-filenames' ;; 14 | "queue download") qndl "$feed" 'curl -LO' >/dev/null 2>&1 ;; 15 | PDF) curl -sL "$feed" > "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" && zathura "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" >/dev/null 2>&1 ;; 16 | nsxiv) curl -sL "$feed" > "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" && nsxiv -a "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" >/dev/null 2>&1 ;; 17 | vim) curl -sL "$feed" > "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" && setsid -f "$TERMINAL" -e "$EDITOR" "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" >/dev/null 2>&1 ;; 18 | setbg) curl -L "$feed" > $XDG_CACHE_HOME/pic ; xwallpaper --zoom $XDG_CACHE_HOME/pic >/dev/null 2>&1 ;; 19 | browser) setsid -f "$BROWSER" "$feed" >/dev/null 2>&1 ;; 20 | lynx) lynx "$feed" >/dev/null 2>&1 ;; 21 | esac 22 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-memory: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | list_memory_hogs() { 4 | ps axch -o cmd,%mem | 5 | awk '{cmd[$1]+=$2} END {for (i in cmd) print i, cmd[i]}' | 6 | sort -nrk2 | 7 | head 8 | } 9 | 10 | case $BLOCK_BUTTON in 11 | 1) notify-send "Memory hogs" "$(list_memory_hogs)" ;; 12 | 2) notify-send "Memory module" "\- Shows Memory Used/Total. 13 | - Click to show memory hogs. 14 | - Middle click to open htop." &;; 15 | 3) setsid -f "$TERMINAL" -e htop ;; 16 | 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; 17 | esac 18 | 19 | TYPE="${BLOCK_INSTANCE:-mem}" 20 | 21 | awk -v type="$TYPE" ' 22 | /^MemTotal:/ { 23 | mem_total=$2 24 | } 25 | /^MemFree:/ { 26 | mem_free=$2 27 | } 28 | /^Buffers:/ { 29 | mem_free+=$2 30 | } 31 | /^Cached:/ { 32 | mem_free+=$2 33 | } 34 | /^SwapTotal:/ { 35 | swap_total=$2 36 | } 37 | /^SwapFree:/ { 38 | swap_free=$2 39 | } 40 | END { 41 | if (type == "swap") { 42 | free=swap_free/1024/1024 43 | used=(swap_total-swap_free)/1024/1024 44 | total=swap_total/1024/1024 45 | } else { 46 | free=mem_free/1024/1024 47 | used=(mem_total-mem_free)/1024/1024 48 | total=mem_total/1024/1024 49 | } 50 | pct=0 51 | if (total > 0) { 52 | pct=used/total*100 53 | } 54 | if (pct < 50) { 55 | printf("%s %.f%%\n",toupper(type), pct) 56 | printf("\n") 57 | exit 58 | } 59 | # full text 60 | printf("%s %.1fG/%.1fG (%.f%%)\n", toupper(type), used, total, pct) 61 | # short text 62 | printf("%s%.f%%\n", substr(toupper(type),1,1), pct) 63 | # color 64 | if (pct > 90) { 65 | print("#FF0000") 66 | } else if (pct > 80) { 67 | print("#FFAE00") 68 | } else if (pct > 70) { 69 | print("#FFF600") 70 | } 71 | } 72 | ' /proc/meminfo 73 | -------------------------------------------------------------------------------- /.config/x11/xprofile: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This file runs when a DM logs you into a graphical session. 4 | # If you use startx/xinit like a Chad, this file will also be sourced. 5 | 6 | # Keyboard layouts 7 | # If fcitx is installed, it will be used. 8 | . "${XDG_CONFIG_HOME:-$HOME/.config}/x11/keyboard_layouts" 9 | 10 | # Fix Gnome Apps Slow Start due to failing services 11 | # Add this when you include flatpak in your system 12 | dbus-update-activation-environment --systemd DBUS_SESSION_BUS_ADDRESS DISPLAY XAUTHORITY 13 | # Set DPI. User may want to use a larger number for larger screens. 14 | xrandr --dpi 96 15 | # Set the background with the `setbg` script 16 | setbg & 17 | # File synchronization 18 | syncthing serve --no-browser & 19 | # Backups. Install deja-dup. 20 | /usr/lib/deja-dup/deja-dup-monitor & 21 | # Podboat automatic queue and download. Requires entr. 22 | podentr & 23 | # Run mailsync periodically 24 | { command -v mailsync && while :; do mailsync; sleep 15m; done; } & 25 | # Use Xresources colors/settings on startup 26 | xrdb -merge "${XDG_CONFIG_HOME:-$HOME/.config}/x11/xresources" 27 | # Start a polkit agent to run software like gparted. 28 | lxqt-policykit-agent & 29 | # Map right Super key to Menu 30 | xmodmap -e "keysym Super_R = Menu" 31 | 32 | # Autostart 33 | for program in mpd xcompmgr dunst unclutter pipewire remapd; do 34 | if ! pidof -sx "$program" && command -v "$program"; then 35 | "$program" & 36 | fi 37 | done 38 | 39 | if command -v gnome-keyring-daemon; then 40 | gnome-keyring-daemon --start --components=ssh 41 | fi 42 | 43 | # Ensure that xrdb has finished running before moving on to start the WM/DE. 44 | [ -n "$xrdbpid" ] && wait "$xrdbpid" 45 | -------------------------------------------------------------------------------- /.config/x11/xresources: -------------------------------------------------------------------------------- 1 | ! vim: ft=xdefaults 2 | ! To make changes take effect run xrdb -load $xresouces_path 3 | ! Type xrdb -q to make sure the settings are loaded properly. 4 | ! It is possible to import colors using #include "/path/to/file" 5 | ! * If using gdm, edit the /etc/gdm/Xsession file and remove the -nocpp option 6 | ! from the command that loads .Xresources ($userresources section) 7 | ! * If using gnome on wayland, uncomment the WaylandEnable=false in 8 | ! /etc/gdm/custom.conf and then the resources will be loaded. 9 | 10 | ! Colors 11 | ! Clone https://github.com/chriskempson/base16-xresources.git to get more schemes 12 | ! *background: #222d32 13 | *background: #2f343f 14 | *foreground: #ebdbb2 15 | *cursorColor: #f1fcf9 16 | 17 | ! Black + DarkGrey 18 | *color0: #2f343f 19 | *color8: #928374 20 | ! DarkRed + Red 21 | *color1: #cc241d 22 | *color9: #fb4934 23 | ! DarkGreen + Green 24 | *color2: #98971a 25 | *color10: #b8bb26 26 | ! DarkYellow + Yellow 27 | *color3: #d79921 28 | *color11: #fabd2f 29 | ! DarkBlue + Blue 30 | *color4: #458588 31 | *color12: #83a598 32 | ! DarkMagenta + Magenta 33 | *color5: #b16286 34 | *color13: #d3869b 35 | ! DarkCyan + Cyan 36 | *color6: #689d6a 37 | *color14: #8ec07c 38 | ! LightGrey + White 39 | *color7: #a89984 40 | *color15: #ebdbb2 41 | 42 | Xcursor.theme: Adwaita 43 | Xcursor.size: 24 44 | 45 | ! https://wiki.archlinux.org/index.php/Font_configuration 46 | ! Some applications like URxvt ignore fontconfig settings. 47 | ! You can work around this by using ~/.Xresources. 48 | Xft.antialias: 1 49 | Xft.autohint: 0 50 | Xft.dpi: 96 51 | Xft.hinting: 1 52 | Xft.hintstyle: hintslight 53 | Xft.lcdfilter: lcddefault 54 | Xft.rgba: none 55 | -------------------------------------------------------------------------------- /.config/git/config: -------------------------------------------------------------------------------- 1 | # Git configuration file 2 | 3 | [user] 4 | # User name and email 5 | name = 6 | email = 7 | 8 | [alias] 9 | co = checkout 10 | sw = switch 11 | ci = commit 12 | st = status 13 | s = status -s 14 | br = branch 15 | dfs = diff --staged 16 | dwc = diff --word-diff=color 17 | type = cat-file -t 18 | dump = cat-file -p 19 | last = log -1 HEAD 20 | hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short 21 | lg = log --graph \ 22 | --pretty='%Cred%h%Creset \ 23 | -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' \ 24 | --abbrev-commit 25 | contributors = shortlog -n -s 26 | remotes = remote -v 27 | 28 | [core] 29 | editor = nvim 30 | autocrlf = false 31 | quotePath = false 32 | 33 | [push] 34 | default = simple 35 | 36 | [color] 37 | ui = always 38 | 39 | [color "diff"] 40 | meta = yellow bold 41 | commit = cyan bold 42 | frag = magenta bold 43 | old = red bold 44 | new = green bold 45 | whitespace = red reverse 46 | 47 | [color "diff-highlight"] 48 | oldNormal = red bold 49 | oldHighlight = red bold 52 50 | newNormal = green bold 51 | newHighlight = green bold 22 52 | 53 | [color "branch"] 54 | current = yellow reverse 55 | local = yellow 56 | remote = green 57 | 58 | [color "status"] 59 | added = green 60 | changed = yellow 61 | untracked = red 62 | [rerere] 63 | enabled = 1 64 | [pull] 65 | rebase = false 66 | [diff] 67 | submodule = log 68 | tool = vimdiff 69 | [status] 70 | submodulesummary = 1 71 | [init] 72 | defaultBranch = main 73 | [commit] 74 | gpgsign = false 75 | [pager] 76 | status = true 77 | [tag] 78 | gpgSign = true 79 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-battery: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Prints all batteries, their percentage remaining and an emoji corresponding 4 | # to charge status (🔌 for plugged up, 🔋 for discharging on battery, etc.). 5 | 6 | get_discharging_status() { 7 | local -r battery=$1 8 | local -r capacity=$(cat -- "$battery/capacity" 2>&1) 9 | if ((capacity >= 90)); then 10 | echo  11 | elif ((capacity >= 60)); then 12 | echo  13 | elif ((capacity >= 40)); then 14 | echo  15 | elif ((capacity >= 10)); then 16 | echo  17 | elif ((capacity >= 0)); then 18 | echo  19 | else 20 | echo ERR 21 | fi 22 | } 23 | 24 | get_status() { 25 | local -r battery=$1 26 | case $(cat -- "$battery/status" 2>&1) in 27 | "Full") echo  ;; 28 | "Charging") echo  ;; 29 | "Not charging") echo  ;; 30 | "Unknown") echo ♻️ ;; 31 | "Discharging") get_discharging_status "$battery" ;; 32 | *) echo ERR ;; 33 | esac 34 | } 35 | 36 | screen_brightness() { 37 | xbacklight -get | awk '{printf "%.1f",$0}' 38 | } 39 | 40 | case $BLOCK_BUTTON in 41 | 1) notify-send "Screen brightness" "$(screen_brightness)%" &;; 42 | 3) notify-send "Battery module" "🔋: discharging 43 | 🛑: not charging 44 | ♻: stagnant charge 45 | 🔌: charging 46 | ⚡: charged 47 | ❗: battery very low! 48 | - Scroll to change adjust xbacklight." &;; 49 | 4) xbacklight -inc 10 ;; 50 | 5) xbacklight -dec 10 ;; 51 | 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; 52 | esac 53 | 54 | # Loop through all attached batteries and format the info 55 | for battery in /sys/class/power_supply/BAT?*; do 56 | if [[ -d $battery ]]; then 57 | printf -- '%s %d%% ' \ 58 | "$(get_status "$battery")" \ 59 | "$(cat -- "$battery/capacity" 2>&1)" 60 | fi 61 | done | sed 's/ *$/\n/' 62 | -------------------------------------------------------------------------------- /.local/bin/bookmarkctl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # bookmark ctl - add, remove and select bookmarks. 3 | 4 | set -euo pipefail 5 | 6 | # symlink the actual bookmark file to this location. 7 | bookmark_file=$(readlink -f -- "${BOOKMARK_FILE:-$HOME/.local/share/larbs/snippets}") 8 | readonly bookmark_file 9 | 10 | new_bookmark() { 11 | if ! grep -Fqsx "$*" -- "$bookmark_file"; then 12 | echo "${*//$'\n'/
}" >>"$bookmark_file" 13 | notify-send "${0##*/} - ${FUNCNAME[0]//_/ }" "✅ Bookmark added." & 14 | else 15 | notify-send "${0##*/} - ${FUNCNAME[0]//_/ }" "❌ Bookmark already exists." & 16 | fi 17 | } 18 | 19 | consume_bookmark() { 20 | local -r text=${*//
/$'\n'} 21 | 22 | if [[ $text == http?://* ]]; then 23 | "${BROWSER:-xdg-open}" "$text" 24 | else 25 | echo -n "$text" | xclip -sel c 26 | fi 27 | } 28 | 29 | select_bookmark() { 30 | grep -v '^#' -- "$bookmark_file" | 31 | tac | 32 | dmenu -i -l 50 -p "${1:-Select} bookmark" 33 | } 34 | 35 | remove_line() { 36 | local -r file=$1 line=$2 37 | local -r tmpstr=$(awk "-vLINE=$line" '{ 38 | if ($0 != LINE && length($0) > 0 && match($0, "^[[:space:]]*$") == 0) { 39 | print $0 40 | } 41 | }' "$file") 42 | echo "$tmpstr" >"$bookmark_file" 43 | } 44 | 45 | pop_bookmark() { 46 | if [[ -n ${bookmark:=$(select_bookmark Pop)} ]]; then 47 | echo "$bookmark" 48 | remove_line "$bookmark_file" "$bookmark" 49 | notify-send "${0##*/} - ${FUNCNAME[0]//_/ }" "✅ Bookmark removed." & 50 | fi 51 | } 52 | 53 | main() { 54 | case $1 in 55 | new | add) 56 | new_bookmark "${@:2}" 57 | ;; 58 | pull | pop) 59 | consume_bookmark "$(pop_bookmark)" 60 | ;; 61 | select | type) 62 | consume_bookmark "$(select_bookmark Select)" 63 | ;; 64 | esac 65 | } 66 | 67 | main "$@" 68 | -------------------------------------------------------------------------------- /.config/firefox/larbs.js: -------------------------------------------------------------------------------- 1 | // These are changes made on top of the Arkenfox JS file to tweak it as 2 | // desired. Any of these settings can be overridden by the user. 3 | 4 | // Disable the Twitter/R*ddit/Faceberg ads in the URL bar: 5 | user_pref("browser.urlbar.quicksuggest.enabled", false); 6 | user_pref("browser.urlbar.suggest.topsites", false); // [FF78+] 7 | 8 | // Do not suggest web history in the URL bar: 9 | user_pref("browser.urlbar.suggest.history", false); 10 | 11 | // Do not prefil forms: 12 | user_pref("signon.prefillForms", false); 13 | 14 | // Do not autocomplete in the URL bar: 15 | user_pref("browser.urlbar.autoFill", false); 16 | 17 | // Enable the addition of search keywords: 18 | user_pref("keyword.enabled", true); 19 | 20 | // Allow access to http (i.e. not https) sites: 21 | user_pref("dom.security.https_only_mode", false); 22 | 23 | // Keep cookies until expiration or user deletion: 24 | user_pref("network.cookie.lifetimePolicy", 0); 25 | 26 | user_pref("dom.webnotifications.serviceworker.enabled", false); 27 | 28 | // Disable push notifications: 29 | user_pref("dom.push.enabled", false); 30 | 31 | // Disable the pocket antifeature: 32 | user_pref("extensions.pocket.enabled", false); 33 | 34 | // Don't autodelete cookies on shutdown: 35 | user_pref("privacy.clearOnShutdown.cookies", false); 36 | 37 | // Enable custom userChrome.js: 38 | user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true); 39 | 40 | // This could otherwise cause some issues on bank logins and other annoying sites: 41 | user_pref("network.http.referer.XOriginPolicy", 0); 42 | 43 | // Disable Firefox sync and its menu entries 44 | user_pref("identity.fxaccounts.enabled", false); 45 | 46 | // Fix the issue where right mouse button instantly clicks 47 | user_pref("ui.context_menus.after_mouseup", true); 48 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-ticker: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Usage 4 | # sb-ticker 5 | # Sample output 6 | # ^DJI: 0.09% 7 | # CL=F: -1.88% 8 | # Description 9 | # displays/retrieves the latest percent-change in stock market quotes listed in $XDG_CONFIG_HOME/tickers. 10 | # defaults to S&P 500, Dow Jones Industrial, and the Nasdaq 11 | # 12 | # intended to be used in the statusbar, which will display the first quote price in the output 13 | 14 | url="terminal-stocks.dev" 15 | pricefile="${XDG_CACHE_HOME:-$HOME/.cache}/stock-prices" 16 | tickerfile="${XDG_CONFIG_HOME:-$HOME/.config}/tickers" 17 | 18 | [ -f "$tickerfile" ] && tickers="$(cat "$tickerfile")" || tickers="^GSPC,^DJI,^IXIC"; 19 | 20 | checkprice() { 21 | [ -s "$pricefile" ] && [ "$(stat -c %y "$pricefile" 2>/dev/null | 22 | cut -d':' -f1)" != "$(date '+%Y-%m-%d %H')" ] 23 | } 24 | 25 | getchange() { 26 | mapfile -t changes < <(sed -e 's/ / /g' "$pricefile" | grep -oe '[m-]\+[0-9]\+\.[0-9]\+' | sed 's/[m ]/;/g') 27 | IFS=',' read -ra TICKER <<< "$tickers" 28 | for idx in "${!TICKER[@]}"; do 29 | printf "%s: %s%%\n" "${TICKER[$idx]}" "${changes[$idx]//;/}" 30 | done 31 | } 32 | 33 | updateprice() { curl -sfm 10 "$url/$tickers" --output "$pricefile" || rm -f "$pricefile" ; } 34 | 35 | case $BLOCK_BUTTON in 36 | 1) setsid "$TERMINAL" -e less -Srf "$pricefile" ;; 37 | 2) notify-send -u low "Updating..." "Updating prices" ; updateme="1" ;; 38 | 3) notify-send "Current prices:" "Current stock prices:\n$(getchange) 39 | 40 | LEFT MOUSE BUTTON: show price file 41 | MIDDLE MOUSE BUTTON: update stock prices 42 | RIGHT MOUSE BUTTON: Get stock overview" ;; 43 | 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; 44 | esac 45 | 46 | [ -n "$updateme" ] && updateprice 47 | 48 | [ -f "$pricefile" ] && getchange 49 | 50 | checkprice && updateprice 51 | -------------------------------------------------------------------------------- /.config/redshift.conf: -------------------------------------------------------------------------------- 1 | ; Global settings for redshift 2 | ; http://jonls.dk/redshift/ 3 | ; https://wiki.archlinux.org/index.php/Redshift 4 | [redshift] 5 | ; Set the day and night screen temperatures (Neutral is 6500K) 6 | temp-day=5700 7 | temp-night=3500 8 | 9 | ; Enable/Disable a smooth transition between day and night 10 | ; 0 will cause a direct change from day to night screen temperature. 11 | ; 1 will gradually increase or decrease the screen temperature. 12 | transition=1 13 | 14 | ; Set the screen brightness. Default is 1.0. 15 | ;brightness=0.9 16 | ; It is also possible to use different settings for day and night 17 | ; since version 1.8. 18 | ;brightness-day=0.7 19 | ;brightness-night=0.4 20 | ; Set the screen gamma (for all colors, or each color channel 21 | ; individually) 22 | gamma=1.0 23 | ;gamma=0.8:0.7:0.8 24 | ; This can also be set individually for day and night since 25 | ; version 1.10. 26 | gamma-day=1.0 27 | gamma-night=0.8 28 | 29 | ; Set the location-provider: 'geoclue2' or 'manual' 30 | ; type 'redshift -l list' to see possible values. 31 | ; The location provider settings are in a different section. 32 | location-provider=manual 33 | 34 | ; Set the adjustment-method: 'randr', 'vidmode' 35 | ; type 'redshift -m list' to see all possible values. 36 | ; 'randr' is the preferred method, 'vidmode' is an older API. 37 | ; but works in some cases when 'randr' does not. 38 | ; The adjustment method settings are in a different section. 39 | adjustment-method=randr 40 | 41 | ; Configuration of the adjustment-method 42 | ; type 'redshift -m METHOD:help' to see the settings. 43 | ; ex: 'redshift -m randr:help' 44 | ; In this example, randr is configured to adjust screen 1. 45 | ; Note that the numbering starts from 0, so this is actually the 46 | ; second screen. If this option is not specified, Redshift will try 47 | ; to adjust _all_ screens. 48 | [randr] 49 | screen=0 50 | -------------------------------------------------------------------------------- /.local/bin/booksplit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Requires ffmpeg 4 | 5 | [ ! -f "$2" ] && printf "The first file should be the audio, the second should be the timecodes.\\n" && exit 6 | 7 | echo "Enter the album/book title:"; read -r booktitle 8 | echo "Enter the artist/author:"; read -r author 9 | echo "Enter the publication year:"; read -r year 10 | 11 | inputaudio="$1" 12 | ext="${1##*.}" 13 | 14 | # Get a safe file name from the book. 15 | escbook="$(echo "$booktitle" | iconv -c -f UTF-8 -t ASCII//TRANSLIT | tr -d '[:punct:]' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | sed "s/-\+/-/g;s/\(^-\|-\$\)//g")" 16 | 17 | ! mkdir -p "$escbook" && 18 | echo "Do you have write access in this directory?" && 19 | exit 1 20 | 21 | # Get the total number of tracks from the number of lines. 22 | total="$(wc -l < "$2")" 23 | 24 | cmd="ffmpeg -i \"$inputaudio\" -nostdin -y" 25 | 26 | while read -r x; 27 | do 28 | end="$(echo "$x" | cut -d' ' -f1)" 29 | file="$escbook/$(printf "%.2d" "$track")-$esctitle.$ext" 30 | if [ -n "$start" ]; then 31 | cmd="$cmd -metadata artist=\"$author\" -metadata title=\"$title\" -metadata album=\"$booktitle\" -metadata year=\"$year\" -metadata track=\"$track\" -metadata total=\"$total\" -ss \"$start\" -to \"$end\" -vn -c:a copy \"$file\" " 32 | fi 33 | title="$(echo "$x" | cut -d' ' -f2-)" 34 | esctitle="$(echo "$title" | iconv -c -f UTF-8 -t ASCII//TRANSLIT | tr -d '[:punct:]' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | sed "s/-\+/-/g;s/\(^-\|-\$\)//g")" 35 | track="$((track+1))" 36 | start="$end" 37 | done < "$2" 38 | 39 | # Last track must be added out of the loop. 40 | file="$escbook/$(printf "%.2d" "$track")-$esctitle.$ext" 41 | cmd="$cmd -metadata artist=\"$author\" -metadata title=\"$title\" -metadata album=\"$booktitle\" -metadata year=\"$year\" -metadata track=\"$track\" -ss \"$start\" -vn -c copy \"$file\"" 42 | 43 | eval "$cmd" 44 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-cpu_usage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # Copyright 2014 Pierre Mavro 4 | # Copyright 2014 Vivien Didelot 5 | # Copyright 2014 Andreas Guldstrand 6 | # 7 | # Licensed under the terms of the GNU GPL v3, or any later version. 8 | 9 | use strict; 10 | use warnings; 11 | use utf8; 12 | use Getopt::Long; 13 | 14 | # default values 15 | my $t_warn = $ENV{T_WARN} // 50; 16 | my $t_crit = $ENV{T_CRIT} // 80; 17 | my $cpu_usage = -1; 18 | my $decimals = $ENV{DECIMALS} // 2; 19 | my $label = $ENV{LABEL} // ""; 20 | 21 | sub help { 22 | print "Usage: cpu_usage [-w ] [-c ] [-d ]\n"; 23 | print "-w : warning threshold to become yellow\n"; 24 | print "-c : critical threshold to become red\n"; 25 | print "-d : Use decimals for percentage (default is $decimals) \n"; 26 | exit 0; 27 | } 28 | 29 | GetOptions("help|h" => \&help, 30 | "w=i" => \$t_warn, 31 | "c=i" => \$t_crit, 32 | "d=i" => \$decimals, 33 | ); 34 | 35 | # Get CPU usage 36 | $ENV{LC_ALL}="en_US"; # if mpstat is not run under en_US locale, things may break, so make sure it is 37 | open (MPSTAT, 'mpstat 1 1 |') or die; 38 | while () { 39 | if (/^.*\s+(\d+\.\d+)[\s\x00]?$/) { 40 | $cpu_usage = 100 - $1; # 100% - %idle 41 | last; 42 | } 43 | } 44 | close(MPSTAT); 45 | 46 | $cpu_usage eq -1 and die 'Can\'t find CPU information'; 47 | 48 | # Print short_text, full_text 49 | print "${label} "; 50 | printf "%.${decimals}f%%\n", $cpu_usage; 51 | print "${label} "; 52 | printf "%.${decimals}f%%\n", $cpu_usage; 53 | 54 | # Print color, if needed 55 | if ($cpu_usage >= $t_crit) { 56 | print "#FF0000\n"; 57 | exit 33; 58 | } elsif ($cpu_usage >= $t_warn) { 59 | print "#FFFC00\n"; 60 | } 61 | 62 | exit 0; 63 | -------------------------------------------------------------------------------- /.local/bin/otp: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Get a one-time password, or add a OTP secret to your pass-otp store. 4 | 5 | # The assumption of this script is that all otp passwords are stored with the 6 | # suffix `-otp`. This script automatically appends newly added otps as such. 7 | 8 | # For OTP passwords to be generated properly, it is important for the local 9 | # computer to have its time properly synced. This can be done with the command 10 | # below which requires the package `ntp`. 11 | 12 | ifinstalled pass pass-otp || exit 1 13 | 14 | dir="${PASSWORD_STORE_DIR}" 15 | 16 | choice="$({ echo "🆕add" ; echo "🕙sync-time" ; ls "$dir"/*-otp.gpg ;} | sed "s/.*\///;s/-otp.gpg//" | dmenu -p "Pick a 2FA:")" 17 | 18 | case $choice in 19 | 🆕add ) 20 | ifinstalled maim zbar || exit 1 21 | 22 | temp=$(mktemp -p "$XDG_RUNTIME_DIR" --suffix=.png) 23 | otp="otp-test-script" 24 | trap 'rm -f $temp; pass rm -f $otp' HUP INT QUIT TERM PWR EXIT 25 | 26 | notify-send "Scan the image." "Scan the OTP QR code." 27 | 28 | maim -s "$temp" || exit 1 29 | info="$(zbarimg -q "$temp")" 30 | info="${info#QR-Code:}" 31 | 32 | if echo "$info" | pass otp insert "$otp"; then 33 | while true ; do 34 | export name="$(echo | dmenu -p "Give this One Time Password a one-word name:")" 35 | echo "$name" | grep -q -- "^[A-z0-9-]\+$" && break 36 | done 37 | pass mv "$otp" "$name-otp" 38 | notify-send "Successfully added." "$name-otp has been created." 39 | else 40 | notify-send "No OTP data found." "Try to scan the image again more precisely." 41 | fi 42 | ;; 43 | 🕙sync-time ) 44 | ifinstalled ntp || exit 1 45 | notify-send -u low "🕙 Synchronizing Time..." "Synching time with remote NTP servers..." 46 | updatedata="$(sudo ntpdate pool.ntp.org)" && 47 | notify-send -u low "🕙 Synchronizing Time..." "Done. Time changed by ${updatedata#*offset }" 48 | ;; 49 | *) pass otp -c ${choice}-otp ;; 50 | esac 51 | -------------------------------------------------------------------------------- /.config/shell/bm-files: -------------------------------------------------------------------------------- 1 | # These files automatically update when edited/saved in vim: 2 | # key filename 3 | 4 | # This file, a list of bookmarked files 5 | bf ${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-files 6 | # A list of bookmarked directories similar to this file 7 | bd ${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-dirs 8 | # Colors, themes and variables for X11 9 | cfx ${XDG_CONFIG_HOME:-$HOME/.config}/x11/xresources 10 | 11 | # These do not update automatically, but on the next new instance of a program: 12 | 13 | # vim/neovim config 14 | cfv ${XDG_CONFIG_HOME:-$HOME/.config}/nvim/init.vim 15 | # zsh (shell) config 16 | cfz $ZDOTDIR/.zshrc 17 | # aliases used by zsh (and potentially other shells) 18 | cfa ${XDG_CONFIG_HOME:-$HOME/.config}/shell/aliasrc 19 | # profile file for login settings for zsh 20 | cfp ${XDG_CONFIG_HOME:-$HOME/.config}/shell/profile 21 | # mutt (email client) config 22 | cfm ${XDG_CONFIG_HOME:-$HOME/.config}/mutt/muttrc 23 | # newsboat (RSS reader) 24 | cfn ${XDG_CONFIG_HOME:-$HOME/.config}/newsboat/config 25 | # RSS urls for newsboat 26 | cfu ${XDG_CONFIG_HOME:-$HOME/.config}/newsboat/urls 27 | # ncmpcpp (music player) keybinds file 28 | cfmb ${XDG_CONFIG_HOME:-$HOME/.config}/ncmpcpp/bindings 29 | # ncmpcpp (music player) config 30 | cfmc ${XDG_CONFIG_HOME:-$HOME/.config}/ncmpcpp/config 31 | # lf (file browser) config 32 | cfl ${XDG_CONFIG_HOME:-$HOME/.config}/lf/lfrc 33 | # lf's scope/preview file 34 | cfL ${XDG_CONFIG_HOME:-$HOME/.config}/lf/scope 35 | # nsxiv (image viewer) key/script handler 36 | cfX ${XDG_CONFIG_HOME:-$HOME/.config}/nsxiv/exec/key-handler 37 | 38 | cfx ${XDG_CONFIG_HOME:-$HOME/.config}/x11/xresources 39 | cfxp ${XDG_CONFIG_HOME:-$HOME/.config}/x11/xprofile 40 | cfi ${XDG_CONFIG_HOME:-$HOME/.config}/i3/config 41 | cfb ${XDG_CONFIG_HOME:-$HOME/.config}/i3blocks/config 42 | cft ${XDG_CONFIG_HOME:-$HOME/.config}/termite/config 43 | cff ${XDG_CONFIG_HOME:-$HOME/.config}/shell/functionrc 44 | cfal ${XDG_CONFIG_HOME:-$HOME/.config}/alacritty/alacritty.yml 45 | 46 | snippets ~/.local/share/larbs/snippets 47 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-price: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Usage: 4 | # price 5 | # price bat-btc "Basic Attention Token" 🦁 24 6 | # This will give the price of BAT denominated in BTC and will update on 7 | # signal 24. 8 | # When the name of the currency is multi-word, put it in quotes. 9 | 10 | [ -z "$1" ] && exit 1 11 | 12 | url="${CRYPTOURL:-rate.sx}" 13 | target="${1%%-*}" 14 | denom="${1##*-}" 15 | name="${2:-$1}" 16 | icon="${3:-💰}" 17 | case "$denom" in 18 | "$target"|usd) denom="usd"; symb="$" ;; 19 | gbp) symb="£" ;; 20 | eur) symb="€" ;; 21 | btc) symb="" ;; 22 | esac 23 | interval="@14d" # History contained in chart preceded by '@' (7d = 7 days) 24 | dir="${XDG_CACHE_HOME:-$HOME/.cache}/crypto-prices" 25 | pricefile="$dir/$target-$denom" 26 | chartfile="$dir/$target-$denom-chart" 27 | filestat="$(stat -c %x "$pricefile" 2>/dev/null)" 28 | 29 | [ -d "$dir" ] || mkdir -p "$dir" 30 | 31 | updateprice() { curl -sf \ 32 | --fail-early "${denom}.${url}/1${target}" "${denom}.${url}/${target}${interval}" \ 33 | --output "$pricefile" --output "$chartfile" || 34 | rm -f "$pricefile" "$chartfile" ;} 35 | 36 | [ "${filestat%% *}" != "$(date '+%Y-%m-%d')" ] && 37 | updateme="1" 38 | 39 | case $BLOCK_BUTTON in 40 | 1) setsid "$TERMINAL" -e less -Srf "$chartfile" ;; 41 | 2) notify-send -u low "$icon Updating..." "Updating $name price..." ; updateme="1" ; showupdate="1" ;; 42 | 3) uptime="$(date -d "$filestat" '+%D at %T' | sed "s|$(date '+%D')|Today|")" 43 | notify-send "$icon $name module" "\- Exact price: \$$(cat "$pricefile") 44 | - Left click for chart of changes. 45 | - Middle click to update. 46 | - Shows 🔃 if updating prices. 47 | - Last updated: 48 | $uptime" ;; 49 | 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; 50 | esac 51 | 52 | [ -n "$updateme" ] && 53 | updateprice "$target" && 54 | [ -n "$showupdate" ] && 55 | notify-send "$icon Update complete." "$name price is now 56 | \$$(cat "$pricefile")" 57 | 58 | [ -f "$pricefile" ] && printf "%s%s%0.2f" "$icon" "$symb" "$(cat "$pricefile")" 59 | -------------------------------------------------------------------------------- /.local/bin/sysact: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # A dmenu wrapper script for system functions. 4 | 5 | ctl() { 6 | case $(readlink -f /sbin/init) in 7 | *systemd*) echo systemctl ;; 8 | *) echo loginctl ;; 9 | esac 10 | } 11 | 12 | silence_all() { 13 | mpc pause || true 14 | pauseallmpv 15 | lmc mute 16 | lmc mute-mic 17 | } 18 | 19 | ask_action() { 20 | cat <<-EOF | dmenu -l 30 -i -p "Action:" 21 | 🔒 lock screen 22 | 🚪 leave ${WM:-i3} 23 | ♻️ renew ${WM:-i3} 24 | 🔃 reboot 25 | 🖥️ shutdown 26 | 💤 sleep 27 | 🐻 hibernate 28 | 📺 display off 29 | EOF 30 | } 31 | 32 | background_color() { 33 | { 34 | xrdb -query -all | awk -F'#' '/background:|color0:/{print $2; exit;}' 35 | echo 1d2021 # fallback 36 | } | head -1 37 | } 38 | 39 | display_off() { 40 | xset dpms force off 41 | } 42 | 43 | lock_screen() { 44 | fcitx-remote -s fcitx-keyboard-us-altgr-intl 45 | silence_all 46 | i3lock -e -f -c "${1:-$(background_color)}" 47 | } 48 | 49 | cleanup() { 50 | dmenurecord kill 51 | fcitx-remote -e 52 | ibus exit 53 | local -ra apps=( 54 | qbittorrent goldendict keepassxc telegram-desktop Throne 55 | ) 56 | for app in "${apps[@]}"; do 57 | killall "$app" 58 | done 59 | sleep '0.33s' 60 | } 61 | 62 | main() { 63 | sync 64 | case ${*:-$(ask_action)} in 65 | *lock*) 66 | lock_screen 67 | silence_all 68 | ;; 69 | *leave*) 70 | cleanup 71 | i3-msg -q exit || kill -TERM "$(pgrep -u "$USER" "\bdwm$")" 72 | ;; 73 | *renew*) 74 | i3-msg -q restart || kill -HUP "$(pgrep -u "$USER" "\bdwm$")" 75 | ;; 76 | *hibernate*) 77 | lock_screen ee4b2b 78 | $(ctl) hibernate 79 | ;; 80 | *sleep* | *suspend*) 81 | lock_screen ee4b2b 82 | $(ctl) suspend 83 | ;; 84 | *reboot*) 85 | cleanup 86 | $(ctl) reboot -i 87 | ;; 88 | *shutdown* | *poweroff*) 89 | cleanup 90 | $(ctl) poweroff -i 91 | ;; 92 | *'display off'*) 93 | display_off 94 | ;; 95 | *silence*) 96 | silence_all 97 | ;; 98 | *) 99 | exit 1 100 | ;; 101 | esac 102 | } 103 | 104 | main "$@" 105 | -------------------------------------------------------------------------------- /.local/bin/getbib: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BIB_FILE="${HOME}/latex/uni.bib" 4 | [ -f "${BIB_FILE}" ] || BIB_FILE="${2:-$(find "${HOME}" -path "${HOME}/.*" \ 5 | -prune -o -type "f" -name "*.bib" -print -quit)}" 6 | 7 | { [ -f "${BIB_FILE}" ] || [ "${2}" ]; } || { 8 | printf "%s\n" "Create a .bib file or provide as \$2." && exit "1" 9 | } 10 | 11 | filter() { 12 | sed -n -E 's/.*((DOI|doi)((\.(org))?\/?|:? *))([^: ]+[^ .]).*/\6/p; T; q' 13 | } 14 | 15 | fpdf() { 16 | pdf="${1}" 17 | doi="$(pdfinfo "${pdf}" 2> "/dev/null" | filter)" 18 | 19 | [ "${doi}" ] || doi="$(pdftotext -q -l "2" "${pdf}" - 2> "/dev/null" | filter)" 20 | 21 | [ "${doi}" ] || printf "%s\n" "No DOI found for PDF: ${pdf}" >&2 22 | 23 | printf "%s\n" "${doi}" 24 | } 25 | 26 | arrange() { 27 | sed 's/\}, /\},\n /g 28 | s/, /,\n / 29 | s/ }/\n}/ 30 | s/,\s*pages=/,\n\tpages=/' | 31 | sed '1s/^ *// 32 | 1s/[0-9]*\([0-9]\{2\}\)/\1/ 33 | 1s/_// 34 | 1s/.*/\L&/ 35 | s/.*=/\L&/ 36 | s/=/ = /' 37 | } 38 | 39 | doi2bib() { 40 | doi="${1#doi:}" 41 | url="https://api.crossref.org/works/${doi}/transform/application/x-bibtex" 42 | entry="$(curl -kLsS --no-fail "${url}" | arrange)" 43 | red='\033[0;31m' 44 | reset='\033[0m' 45 | 46 | printf "${red}%s${reset}\n" "${entry}" 47 | 48 | [ "${entry%"${entry#?}"}" != "@" ] && { 49 | printf "%s\n" "Failed to fetch bibtex entry for DOI: ${doi}" 50 | return "1" 51 | } 52 | 53 | grep -iFq "doi = {${doi}}" "${BIB_FILE}" 2> "/dev/null" && { 54 | printf "%s\n" "Bibtex entry for DOI: ${doi} already exists in the file." 55 | } || { 56 | [ -s "${BIB_FILE}" ] && printf "\n" >> "${BIB_FILE}" 57 | printf "%s\n" "${entry}" >> "${BIB_FILE}" 58 | printf "%s\n" "Added bibtex entry for DOI: ${doi}" 59 | } 60 | } 61 | 62 | [ "${1}" ] || { 63 | printf "%s\n" "Give either a pdf file or a DOI or a directory path that has PDFs as an argument." 64 | exit "1" 65 | } 66 | 67 | [ -f "${1}" ] && doi="$(fpdf "${1}")" && doi2bib "${doi}" && exit "0" 68 | 69 | [ -d "${1}" ] && for i in "${1}"/*.pdf; do doi="$(fpdf "${i}")" && doi2bib "${doi}"; done && exit "0" 70 | 71 | doi="$(printf "%s\n" "${1}" | filter)" && doi2bib "${doi}" 72 | -------------------------------------------------------------------------------- /.local/bin/linkhandler: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | # Feed script a url or file location. 6 | # If an image, it will view in nsxiv, 7 | # if a video or gif, it will view in mpv 8 | # if a music file or pdf, it will download, 9 | # otherwise it opens link in browser. 10 | 11 | # Add this to ~/.config/mimeapps.list 12 | # x-scheme-handler/chrome=linkhandler.desktop; 13 | # x-scheme-handler/http=linkhandler.desktop; 14 | # x-scheme-handler/https=linkhandler.desktop; 15 | 16 | if [ -z "${1-}" ]; then 17 | url="$(xclip -o)" 18 | else 19 | url="$1" 20 | fi 21 | 22 | cd -- ~/Downloads || true 23 | 24 | case "${url:?}" in 25 | "https://t.me/"*|"t.me/") 26 | domain=${url##"https://t.me/"} 27 | domain=${domain##"t.me/"} 28 | post="" 29 | if [[ $domain == */* ]]; then 30 | post="${domain##*/}" 31 | fi 32 | domain="${domain%%/*}" 33 | url="tg://resolve?domain=${domain}${post:+"&post="}${post}" 34 | echo "opening with xdg-open: $url" 35 | setsid -f xdg-open "$url" 36 | ;; 37 | #http*youtube.com* | http*youtu.be*) 38 | # ifinstalled jq || exit 1 39 | # inv=$( curl -s 'https://api.invidious.io/instances.json?sort_by=type,users' | 40 | # jq -r '.[0][1].uri' ) 41 | # get_params=${url##*/} 42 | # setsid -f "$BROWSER" -- "${inv}/${get_params}" >/dev/null 2>&1 & 43 | # ;; 44 | *.mkv | *.webm | *.mp4 | \ 45 | *hooktube.com* | *bitchute.com/video* | *instagram.com* | *twitter.com* | \ 46 | *odysee.com* | \ 47 | *videos.lukesmith.xyz* | \ 48 | *tiktok.com/* | *streamable.com/* | \ 49 | *worldstar.com/web/video*) 50 | setsid -f trympv "$url" >/dev/null 2>&1 & 51 | ;; 52 | *.png | *.jpg | *.jpe | *.jpeg | *.gif | \ 53 | *.pdf | *.cbz | *.cbr | *.webp | \ 54 | *matrix/media/*/download/*) 55 | filename=$(echo "$url" | sed 's|.*/||; s|%20| |g') 56 | dl_file_path=$HOME/Downloads/$(mktemp -- "${filename%.*}.XXXXXX") 57 | curl --max-time 180 -sL -o "$dl_file_path" -- "$url" 58 | new_file_path="${dl_file_path%.*}.$(file --mime-type --brief "$dl_file_path" | cut -d/ -f2)" 59 | mv -n -- "$dl_file_path" "$new_file_path" 60 | setsid -f xdg-open "$new_file_path" >/dev/null 2>&1 & 61 | ;; 62 | *.mp3 | *.flac | *.opus | *.mp3?source*) 63 | qndl "$1" 'curl -LO' >/dev/null 2>&1 64 | ;; 65 | *) 66 | if [ -f "$url" ]; then 67 | setsid -f "$TERMINAL" -e "$EDITOR -- $url" 68 | else 69 | setsid -f "$BROWSER" -- "$url" >/dev/null 2>&1 & 70 | fi 71 | ;; 72 | esac 73 | -------------------------------------------------------------------------------- /.local/bin/noisereduce: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh 2 | 3 | usage () 4 | { 5 | printf "Usage : noisereduce \n" 6 | exit 7 | } 8 | 9 | # Tests for requirements 10 | ifinstalled ffmpeg || { echo >&2 "We require 'ffmpeg' but it's not installed."; exit 1; } 11 | ifinstalled sox || { echo >&2 "We require 'ffmpeg' but it's not installed."; exit 1; } 12 | 13 | if [ "$#" -ne 2 ] 14 | then 15 | usage 16 | fi 17 | 18 | if [ ! -e "$1" ] 19 | then 20 | printf "File not found: %s\n" "$1" 21 | exit 22 | fi 23 | 24 | if [ -e "$2" ] 25 | then 26 | printf "File %s already exists, overwrite? [y/N]\n: " "$2" 27 | read -r yn 28 | case $yn in 29 | [Yy]* ) ;; 30 | * ) exit;; 31 | esac 32 | fi 33 | 34 | inBasename=$(basename "$1") 35 | inExt="${inBasename##*.}" 36 | 37 | isVideoStr=$(ffprobe -v warning -show_streams "$1" | grep codec_type=video) 38 | if [ -n "$isVideoStr" ] 39 | then 40 | isVideo=1 41 | printf "Detected %s as a video file\n" "$inBasename" 42 | else 43 | isVideo=0 44 | printf "Detected %s as an audio file\n" "$inBasename" 45 | fi 46 | 47 | printf "Sample noise start time [00:00:00]: " 48 | read -r sampleStart 49 | if [ -z "$sampleStart" ] ; then sampleStart="00:00:00"; fi 50 | printf "Sample noise end time [00:00:00.900]: " 51 | read -r sampleEnd 52 | if [ -z "$sampleEnd" ] ; then sampleEnd="00:00:00.900"; fi 53 | printf "Noise reduction amount [0.21]: " 54 | read -r sensitivity 55 | if [ -z "$sensitivity" ] ; then sensitivity="0.21"; fi 56 | 57 | 58 | tmpVidFile="/tmp/noiseclean_tmpvid.$inExt" 59 | tmpAudFile="/tmp/noiseclean_tmpaud.wav" 60 | noiseAudFile="/tmp/noiseclean_noiseaud.wav" 61 | noiseProfFile="/tmp/noiseclean_noise.prof" 62 | tmpAudCleanFile="/tmp/noiseclean_tmpaud-clean.wav" 63 | 64 | printf "Cleaning noise on %s...\n" "$1" 65 | 66 | if [ $isVideo -eq "1" ]; then 67 | ffmpeg -v warning -y -i "$1" -qscale:v 0 -vcodec copy -an "$tmpVidFile" 68 | ffmpeg -v warning -y -i "$1" -qscale:a 0 "$tmpAudFile" 69 | else 70 | cp "$1" "$tmpAudFile" 71 | fi 72 | ffmpeg -v warning -y -i "$1" -vn -ss "$sampleStart" -t "$sampleEnd" "$noiseAudFile" 73 | sox "$noiseAudFile" -n noiseprof "$noiseProfFile" 74 | sox "$tmpAudFile" "$tmpAudCleanFile" noisered "$noiseProfFile" "$sensitivity" 75 | if [ $isVideo -eq "1" ]; then 76 | ffmpeg -v warning -y -i "$tmpAudCleanFile" -i "$tmpVidFile" -vcodec copy -qscale:v 0 -qscale:a 0 "$2" 77 | else 78 | cp "$tmpAudCleanFile" "$2" 79 | fi 80 | 81 | printf "Done" 82 | -------------------------------------------------------------------------------- /.local/bin/statusbar/sb-local_ipaddr: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (C) 2014 Julien Bonjean 3 | # Copyright (C) 2014 Alexander Keller 4 | 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | #------------------------------------------------------------------------ 19 | 20 | # Use the provided interface, otherwise the device used for the default route. 21 | IF="${IFACE:-$BLOCK_INSTANCE}" 22 | IF="${IF:-$(ip route | awk '/^default/ { print $5 ; exit }')}" 23 | 24 | # Exit if there is no default route 25 | [[ -z "$IF" ]] && exit 26 | 27 | #------------------------------------------------------------------------ 28 | 29 | # As per #36 -- It is transparent: e.g. if the machine has no battery or wireless 30 | # connection (think desktop), the corresponding block should not be displayed. 31 | [[ ! -d /sys/class/net/${IF} ]] && exit 32 | 33 | #------------------------------------------------------------------------ 34 | 35 | AF=${ADDRESS_FAMILY:-inet6?} 36 | LABEL="${LABEL:-}" 37 | 38 | for flag in "$1" "$2"; do 39 | case "$flag" in 40 | -4) 41 | AF=inet 42 | ;; 43 | -6) 44 | AF=inet6 45 | ;; 46 | -L) 47 | if [[ "$IF" = "" ]]; then 48 | LABEL="iface " 49 | else 50 | LABEL="$IF: " 51 | fi 52 | ;; 53 | esac 54 | done 55 | 56 | if [[ "$IF" = "" ]] || [[ "$(cat "/sys/class/net/$IF/operstate")" = 'down' ]]; then 57 | echo "${LABEL}down" # full text 58 | echo "${LABEL}down" # short text 59 | echo \#FF0000 # color 60 | exit 61 | fi 62 | 63 | # if no interface is found, use the first device with a global scope 64 | IPADDR=$(ip addr show "$IF" | perl -n -e "/$AF ([^ \/]+).* scope global/ && print \$1 and exit") 65 | 66 | case $BLOCK_BUTTON in 67 | 3) echo -n "$IPADDR" | xclip -q -se c ;; 68 | esac 69 | 70 | #------------------------------------------------------------------------ 71 | 72 | echo "$LABEL$IPADDR" # full text 73 | echo "$LABEL$IPADDR" # short text 74 | -------------------------------------------------------------------------------- /.local/bin/compiler: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script will compile or run another finishing operation on a document. I 4 | # have this script run via vim. 5 | 6 | # Compiles .tex. groff (.mom, .ms), .rmd, .md, .org. Opens .sent files as sent 7 | # presentations. Runs scripts based on extension or shebang. 8 | 9 | file=$(readlink -f -- "${1}") 10 | ext="${file##*.}" 11 | dir=${file%/*} 12 | base="${file%.*}" 13 | 14 | cd -- "${dir}" || exit "1" 15 | 16 | _md2html() { 17 | if [[ -x $(command -v md2html) ]]; then 18 | md2html -f --github "$file" | 19 | sed '/^$/a ' > "${base}.html" 20 | elif [[ -x $(command -v mkd2html) ]]; then 21 | mkd2html "$file" "${base}.html" 22 | else 23 | echo "Install md2html (md4c) or mkd2html (discount)." >&2 24 | exit 1 25 | fi 26 | } 27 | 28 | case "${ext}" in 29 | # Try to keep these cases in alphabetical order. 30 | [0-9]) preconv "${file}" | refer -PS -e | groff -mandoc -T pdf > "${base}.pdf" ;; 31 | mom|ms) preconv "${file}" | refer -PS -e | groff -T pdf -m"${ext}" > "${base}.pdf" ;; 32 | c) cc "${file}" -o "${base}" && "./${base}" ;; 33 | cob) cobc -x -o "$base" "$file" && "$base" ;; 34 | cpp) g++ "${file}" -o "${base}" && "./${base}" ;; 35 | cs) mcs "${file}" && mono "${base}.exe" ;; 36 | go) go run "${file}" ;; 37 | h) sudo make install ;; 38 | java) javac -d classes "${file}" && java -cp classes "${base}" ;; 39 | m) octave "${file}" ;; 40 | md) 41 | if [ -x "$(command -v wkhtmltopdf)" ]; then 42 | _md2html 43 | # note: image files can be placed in the 'img' directory on in the same directory as $file 44 | wkhtmltopdf --allow "${dir}" --allow "${dir}/img" "${base}.html" "${base}.pdf" 45 | elif [ -x "$(command -v groffdown)" ]; then 46 | groffdown -i "${file}" | groff -T pdf > "${base}.pdf" 47 | elif [ -x "$(command -v lowdown)" ]; then 48 | lowdown --parse-no-intraemph "${file}" -Tms | groff -mpdfmark -ms -kept -T pdf > "${base}.pdf" 49 | else 50 | pandoc -t ms --highlight-style="kate" -s -o "${base}.pdf" "${file}" 51 | fi ; ;; 52 | org) emacs "${file}" --batch -u "${USER}" -f org-latex-export-to-pdf ;; 53 | py) python "${file}" ;; 54 | rink) rink -f "${file}" ;; 55 | [rR]md) Rscript -e "rmarkdown::render('${file}', quiet=TRUE)" ;; 56 | rs) cargo build ;; 57 | sass) sassc -a "${file}" "${base}.css" ;; 58 | scad) openscad -o "${base}.stl" "${file}" ;; 59 | sent) setsid -f sent "${file}" 2> "/dev/null" ;; 60 | lua) lua "$file" ;; 61 | tex) latexmk ;; 62 | typ) 63 | typst compile "$file" "${base}.pdf" 64 | ;; 65 | *) sed -n '/^#!/s/^#!//p; q' "${file}" | xargs -r -I % "${file}" ;; 66 | esac 67 | 68 | echo -n "Press any key to continue..." 69 | read -r 70 | -------------------------------------------------------------------------------- /.local/bin/rankspellings: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Ranks passed Japanese words by frequency 4 | # by searching each word on Japanese versions of Google or Yahoo 5 | # and counting the number of results. 6 | # Used to find the most common spelling of a word. 7 | # 8 | # Search Google: rankspellings -g 蝲蛄 蜊蛄 躄蟹 9 | # Search Yahoo: rankspellings -y 蝲蛄 蜊蛄 躄蟹 10 | 11 | set -euo pipefail 12 | 13 | fv=$(pacman -Si firefox | grep -Po '^Version[^:]*: *\K\d+') 14 | readonly fv 15 | 16 | fetch_google() { 17 | # Additional headers reduce the probability of Google thinking this is a bot and rejecting it. 18 | curl -s \ 19 | -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:$fv.0) Gecko/20100101 Firefox/$fv.0" \ 20 | -H 'Host: www.google.co.jp' \ 21 | -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' \ 22 | -H 'Accept-Language: ja-JP,ja;q=0.5' \ 23 | -H 'Accept-Encoding: gzip' \ 24 | -H 'Alt-Used: www.google.co.jp' \ 25 | -H 'Upgrade-Insecure-Requests: 1' \ 26 | -H 'Sec-Fetch-Dest: document' \ 27 | -H 'Sec-Fetch-Mode: navigate' \ 28 | -H 'Sec-Fetch-Site: same-origin' \ 29 | -H 'Sec-Fetch-User: ?1' \ 30 | -H 'Referer: https://www.google.co.jp/' \ 31 | --get \ 32 | --data-urlencode "q=\"$1\"" \ 33 | --data-urlencode "hl=ja" \ 34 | --data-urlencode "lr=lang_ja" \ 35 | 'https://www.google.co.jp/search' | 36 | gzip -d | 37 | grep -Po '約 *\K[0-9,]+(?= *件)' | 38 | tr -d ',' 39 | } 40 | 41 | fetch_yahoo() { 42 | # Additional headers reduce the probability of Yahoo thinking this is a bot and rejecting it. 43 | curl -s \ 44 | -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:$fv.0) Gecko/20100101 Firefox/$fv.0" \ 45 | -H 'Host: search.yahoo.co.jp' \ 46 | -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' \ 47 | -H 'Accept-Language: ja-JP,ja;q=0.5' \ 48 | -H 'Accept-Encoding: gzip' \ 49 | -H 'Upgrade-Insecure-Requests: 1' \ 50 | -H 'Sec-Fetch-Dest: document' \ 51 | -H 'Sec-Fetch-Mode: navigate' \ 52 | -H 'Sec-Fetch-Site: same-site' \ 53 | -H 'Sec-Fetch-User: ?1' \ 54 | -H 'Referer: https://www.yahoo.co.jp/' \ 55 | --get \ 56 | --data-urlencode "p=\"$1\"" \ 57 | --data-urlencode "fl=2" \ 58 | 'https://search.yahoo.co.jp/search' | 59 | gzip -d | 60 | grep -Po '約()?\K[0-9,]+(?=()?件)' | 61 | tr -d ',' 62 | } 63 | 64 | for arg; do 65 | case $arg in 66 | -g | --google) readonly fetch_freq=fetch_google ;; 67 | -y | --yahoo) readonly fetch_freq=fetch_yahoo ;; 68 | *) words+=("$arg") ;; 69 | esac 70 | done 71 | 72 | if [[ -n $fetch_freq ]]; then 73 | for word in "${words[@]}"; do 74 | printf -- '%s\t%s\n' "$word" "$("$fetch_freq" "$word")" & 75 | done 76 | wait 77 | fi | sort -r -t $'\t' -g -k 2 78 | -------------------------------------------------------------------------------- /.local/bin/shortcuts: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | bmdirs="${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-dirs" 4 | bmfiles="${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-files" 5 | 6 | # Output locations. Unactivated progs should go to /dev/null. 7 | shell_shortcuts="${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutrc" 8 | shell_env_shortcuts="${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutenvrc" 9 | zsh_named_dirs="${XDG_CONFIG_HOME:-$HOME/.config}/shell/zshnameddirrc" 10 | lf_shortcuts="${XDG_CONFIG_HOME:-$HOME/.config}/lf/shortcutrc" 11 | vim_shortcuts="${XDG_CONFIG_HOME:-$HOME/.config}/nvim/shortcuts.vim" 12 | qute_shortcuts="/dev/null" 13 | fish_shortcuts="/dev/null" 14 | vifm_shortcuts="/dev/null" 15 | 16 | # Remove, prepare files 17 | rm -f "$lf_shortcuts" "$qute_shortcuts" "$zsh_named_dirs" "$vim_shortcuts" 2>/dev/null 18 | printf "# vim: filetype=sh\\n" > "$fish_shortcuts" 19 | printf "# vim: filetype=sh\\nalias " > "$shell_shortcuts" 20 | printf "# vim: filetype=sh\\n" > "$shell_env_shortcuts" 21 | printf "\" vim: filetype=vim\\n" > "$vifm_shortcuts" 22 | 23 | # Format the `directories` file in the correct syntax and sent it to all three configs. 24 | eval "echo \"$(cat "$bmdirs")\"" | \ 25 | awk "!/^\s*#/ && !/^\s*\$/ {gsub(\"\\\s*#.*$\",\"\"); 26 | printf(\"%s=\42cd -- %s\42 \\\\\n\",\$1,\$2) >> \"$shell_shortcuts\" ; 27 | printf(\"[ -n \42%s\42 ] && export %s=\42%s\42 \n\",\$1,\$1,\$2) >> \"$shell_env_shortcuts\" ; 28 | printf(\"hash -d %s=%s \n\",\$1,\$2) >> \"$zsh_named_dirs\" ; 29 | printf(\"abbr %s \42cd %s;\42\n\",\$1,\$2) >> \"$fish_shortcuts\" ; 30 | printf(\"map g%s :cd %s\nmap t%s :cd %s\nmap M%s :cd %s:mo\nmap Y%s :cd %s:co \n\",\$1,\$2, \$1, \$2, \$1, \$2, \$1, \$2) >> \"$vifm_shortcuts\" ; 31 | printf(\"config.bind(';%s', \42set downloads.location.directory %s ;; hint links download\42) \n\",\$1,\$2) >> \"$qute_shortcuts\" ; 32 | printf(\"map C%s cd \42%s\42 \n\",\$1,\$2) >> \"$lf_shortcuts\" ; 33 | printf(\"cmap ;%s %s\n\",\$1,\$2) >> \"$vim_shortcuts\" }" 34 | 35 | # Format the `files` file in the correct syntax and sent it to both configs. 36 | eval "echo \"$(cat "$bmfiles")\"" | \ 37 | awk "!/^\s*#/ && !/^\s*\$/ {gsub(\"\\\s*#.*$\",\"\"); 38 | printf(\"%s=\42\$EDITOR %s\42 \\\\\n\",\$1,\$2) >> \"$shell_shortcuts\" ; 39 | printf(\"[ -n \42%s\42 ] && export %s=\42%s\42 \n\",\$1,\$1,\$2) >> \"$shell_env_shortcuts\" ; 40 | printf(\"hash -d %s=%s \n\",\$1,\$2) >> \"$zsh_named_dirs\" ; 41 | printf(\"abbr %s \42\$EDITOR %s\42 \n\",\$1,\$2) >> \"$fish_shortcuts\" ; 42 | printf(\"map %s :e %s \n\",\$1,\$2) >> \"$vifm_shortcuts\" ; 43 | printf(\"map E%s \$\$EDITOR \42%s\42 \n\",\$1,\$2) >> \"$lf_shortcuts\" ; 44 | printf(\"cmap ;%s %s\n\",\$1,\$2) >> \"$vim_shortcuts\" }" 45 | -------------------------------------------------------------------------------- /.local/bin/maimocr: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | readonly TESSDATA_PREFIX=$HOME/.local/share/tessdata 6 | declare eng_mode=false 7 | 8 | notify() { 9 | echo "$*" 10 | notify-send "Maim OCR" "$*" & 11 | } 12 | 13 | if_installed() { 14 | for x in "$@"; do 15 | if ! which "$x" >/dev/null 2>&1 && ! pacman -Qq "$x" >/dev/null 2>&1; then 16 | notify "$x must be installed for this function." 17 | return 1 18 | fi 19 | done 20 | } 21 | 22 | download_tessdata() { 23 | # note: file uploaded with 'curl -F "file=@tessdata.zip" https://depot.4d2.org/' 24 | local -r \ 25 | zip_url='https://dl.depot.4d2.org/FQFrV7A7mWhf.zip' \ 26 | zip_path=$(mktemp /tmp/tesseract_data.XXXXXX) \ 27 | osd_path=/usr/share/tessdata/osd.traineddata 28 | 29 | curl "$zip_url" --output "$zip_path" 30 | mkdir -p -- "$TESSDATA_PREFIX" 31 | unzip -o -j "$zip_path" -d "$TESSDATA_PREFIX" 32 | rm -- "$zip_path" 33 | if [[ -f $osd_path ]] && ! [[ -f $TESSDATA_PREFIX/${osd_path##*/} ]]; then 34 | cp -- "$osd_path" "$TESSDATA_PREFIX" 35 | fi 36 | } 37 | 38 | installed_languages() { 39 | find "$TESSDATA_PREFIX" -type f -name '*.traineddata' -printf '%f+' | sed 's|\.traineddata||g; s|\+$||' 40 | } 41 | 42 | take_screenshot() { 43 | # https://tesseract-ocr.github.io/tessdoc/ImproveQuality.html#missing-borders 44 | maim --select --hidecursor --format=png --quality 1 | 45 | magick \ 46 | png:- \ 47 | -modulate 100,0 \ 48 | -resize 400% \ 49 | -alpha off \ 50 | -bordercolor White \ 51 | -border 10x10 \ 52 | png:- 53 | } 54 | 55 | tesseract_recognize() { 56 | # https://tesseract-ocr.github.io/tessdoc/Command-Line-Usage.html 57 | local lang=$(installed_languages) 58 | result=$( 59 | tesseract stdin stdout \ 60 | --tessdata-dir "$TESSDATA_PREFIX" \ 61 | -l "$lang" \ 62 | --psm 1 63 | ) 64 | if ! $eng_mode; then 65 | result=$( 66 | echo "$result" | 67 | tr -d ' ' | 68 | tr -d '\n' | 69 | grep -P '[ヲ-゚ァ-ヶぁ-ゞA-z0-9ァ-ン゙゚ァ-ンぁ-ん一-龯]+' 70 | ) 71 | fi 72 | } 73 | 74 | run_ocr() { 75 | local -r result=$(take_screenshot | tesseract_recognize) 76 | if [[ -n $result ]]; then 77 | xclip -selection clipboard <<<"$result" 78 | notify "Copied $result." 79 | else 80 | notify "Failed." 81 | return 1 82 | fi 83 | } 84 | 85 | main() { 86 | if_installed curl unzip maim magick tesseract xclip || exit 1 87 | 88 | while (($# > 0)); do 89 | case $1 in 90 | --eng) 91 | eng_mode=true 92 | ;; 93 | *) 94 | ;; 95 | esac 96 | shift 97 | done 98 | readonly eng_mode 99 | 100 | if [[ -d $TESSDATA_PREFIX ]]; then 101 | run_ocr 102 | else 103 | notify "Couldn't find Tesseract data files. Downloading..." 104 | download_tessdata 105 | notify "Downloaded Tesseract data. Run this script again to recognize Japanese text." 106 | fi 107 | } 108 | 109 | main "$@" 110 | -------------------------------------------------------------------------------- /.local/bin/rank-nitter-instances: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import asyncio 3 | import os 4 | import re 5 | import sys 6 | import time 7 | from typing import NamedTuple 8 | 9 | import httpx 10 | 11 | CACHE = '/tmp/nitter_instances' 12 | RE_MD_URL = re.compile(r'\[([^]\[]+)]\(([^)(\[\]]+)\)') 13 | 14 | 15 | def md_url(): 16 | return 'https://raw.githubusercontent.com/wiki/zedeus/nitter/Instances.md' 17 | 18 | 19 | def example_tweet(instance_url: str) -> str: 20 | return instance_url.rstrip('/') + "/elonmusk/status/1686050455468621831" 21 | 22 | 23 | async def get_urls(s: httpx.AsyncClient) -> list[str]: 24 | lines = [] 25 | try: 26 | response = await s.get(md_url()) 27 | except httpx.ConnectTimeout as e: 28 | print("Connect timeout!") 29 | else: 30 | for line in response.text.splitlines(): 31 | if "### Tor" in line: 32 | break 33 | if m := re.search(RE_MD_URL, line): 34 | if '@' in m.group(2): 35 | continue 36 | lines.append(m.group(2)) 37 | return lines 38 | 39 | 40 | def file_exists(file_path: str) -> bool: 41 | return os.path.isfile(file_path) and os.stat(file_path).st_size > 0 42 | 43 | 44 | class TweetResponse(NamedTuple): 45 | r: httpx.Response 46 | instance_url: str 47 | elapsed: float 48 | 49 | 50 | async def get_example_tweet(s: httpx.AsyncClient, instance_url: str) -> TweetResponse: 51 | start_time = time.perf_counter() 52 | r = await s.get(example_tweet(instance_url)) 53 | end_time = time.perf_counter() 54 | return TweetResponse(r, instance_url, end_time-start_time) 55 | 56 | 57 | async def rank_urls(s: httpx.AsyncClient, instance_urls: list[str]): 58 | responses = await asyncio.gather(*[get_example_tweet(s, url) for url in instance_urls], return_exceptions=True) 59 | results = [] 60 | for response in responses: 61 | if isinstance(response, Exception): 62 | continue 63 | response: TweetResponse 64 | if response.r.status_code != 200: 65 | continue 66 | if "Elon Musk" not in response.r.text or "Canada" not in response.r.text: 67 | continue 68 | results.append(response) 69 | return results 70 | 71 | 72 | async def main(): 73 | if file_exists(CACHE) and '--recalc' not in sys.argv[1:]: 74 | with open(CACHE) as f: 75 | return print(f.read()) 76 | 77 | async with httpx.AsyncClient(timeout=5) as s: 78 | urls: list[str] = await get_urls(s) 79 | instances: list[TweetResponse] = await rank_urls(s, urls) 80 | 81 | with open(CACHE, 'w') as of: 82 | for instance in sorted(instances, key=lambda r: r.elapsed): 83 | print(instance.instance_url, instance.elapsed, sep='\t', file=of) 84 | print(instance.instance_url, instance.elapsed, sep='\t') 85 | 86 | 87 | if __name__ == '__main__': 88 | asyncio.run(main()) 89 | -------------------------------------------------------------------------------- /.config/newsboat/config: -------------------------------------------------------------------------------- 1 | show-read-feeds no 2 | auto-reload yes 3 | reload-time 30 4 | reload-threads 4 5 | refresh-on-startup yes 6 | notify-program "/usr/bin/notify-send" 7 | 8 | #html-renderer "w3m -dump -T text/html" 9 | #external-url-viewer "urlscan -dc -r 'linkhandler {}'" 10 | 11 | # You can also fetch your rss feeds over tor 12 | #proxy localhost:9050 13 | #proxy-type socks5 14 | 15 | bind-key j down 16 | bind-key k up 17 | bind-key j next articlelist 18 | bind-key k prev articlelist 19 | bind-key J next-feed articlelist 20 | bind-key K prev-feed articlelist 21 | bind-key G end 22 | bind-key g home 23 | bind-key d pagedown 24 | bind-key u pageup 25 | bind-key l open 26 | bind-key h quit 27 | bind-key a toggle-article-read 28 | bind-key n next-unread 29 | bind-key N prev-unread 30 | bind-key D pb-download 31 | bind-key U show-urls 32 | bind-key x pb-delete 33 | 34 | color listnormal cyan default 35 | color listfocus black yellow standout bold 36 | color listnormal_unread blue default 37 | color listfocus_unread yellow default bold 38 | color info red black bold 39 | color article white default bold 40 | 41 | browser linkhandler 42 | # Descriptions are shown when you press "?". 43 | macro , open-in-browser -- "Open in browser" 44 | macro i set browser "tsp impd add" ; open-in-browser ; set browser linkhandler -- "Add to Immersion pod" 45 | macro t set browser "qndl" ; open-in-browser ; set browser linkhandler 46 | macro a set browser "tsp yt-dlp --embed-metadata -xic -f bestaudio/best" ; open-in-browser ; set browser linkhandler 47 | macro y set browser "tsp yt-dlp --embed-metadata -ic" ; open-in-browser ; set browser linkhandler 48 | macro v set browser "setsid -f mpv %u >/dev/null 2>&1 &" ; open-in-browser ; set browser linkhandler 49 | macro w set browser "lynx" ; open-in-browser ; set browser linkhandler 50 | macro d set browser "dmenuhandler" ; open-in-browser ; set browser linkhandler 51 | macro c set browser "echo %u | xclip -r -sel c" ; open-in-browser ; set browser linkhandler 52 | macro C set browser "youtube-viewer --comments=%u" ; open-in-browser ; set browser linkhandler 53 | macro p set browser "peertubetorrent %u 480" ; open-in-browser ; set browser linkhandler 54 | macro P set browser "peertubetorrent %u 1080" ; open-in-browser ; set browser linkhandler 55 | 56 | highlight all "---.*---" yellow 57 | highlight feedlist ".*(0/0))" black 58 | highlight article "(^Feed:.*|^Title:.*|^Author:.*)" cyan default bold 59 | highlight article "(^Link:.*|^Date:.*)" default default 60 | highlight article "https?://[^ ]+" green default 61 | highlight article "^(Title):.*$" blue default 62 | highlight article "\\[[0-9][0-9]*\\]" magenta default bold 63 | highlight article "\\[image\\ [0-9]+\\]" green default bold 64 | highlight article "\\[embedded flash: [0-9][0-9]*\\]" green default bold 65 | highlight article ":.*\\(link\\)$" cyan default 66 | highlight article ":.*\\(image\\)$" blue default 67 | highlight article ":.*\\(embedded flash\\)$" magenta default 68 | -------------------------------------------------------------------------------- /.local/bin/rank-invidious-instances: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import asyncio 4 | import os.path 5 | import sys 6 | from typing import NamedTuple, Collection 7 | 8 | import httpx 9 | 10 | CACHE = '/tmp/inv_instances' 11 | 12 | 13 | class Instance(NamedTuple): 14 | url: str 15 | health_percent: float 16 | active_month: int 17 | 18 | @staticmethod 19 | def get_active_users(d: list) -> int: 20 | try: 21 | return int(d[1]['stats']['usage']['users']['activeMonth']) 22 | except (ValueError, TypeError, KeyError): 23 | return 0 24 | 25 | @classmethod 26 | def get_health(cls, d: list) -> float: 27 | try: 28 | return float(d[1]['monitor']['uptime']) 29 | except (ValueError, TypeError, KeyError): 30 | return 0 31 | 32 | @staticmethod 33 | def get_uri(d: list) -> str: 34 | return str(d[1]['uri']).rstrip('/') 35 | 36 | @classmethod 37 | def from_json(cls, d: list): 38 | return cls( 39 | url=cls.get_uri(d), 40 | health_percent=cls.get_health(d), 41 | active_month=cls.get_active_users(d), 42 | ) 43 | 44 | 45 | class InstanceAlive(NamedTuple): 46 | instance: Instance 47 | alive: bool 48 | 49 | 50 | def test_video_url(instance_url: str): 51 | return '%s/watch?v=%s' % (instance_url, "AO_UNZ13_6E") 52 | 53 | 54 | def json_url() -> str: 55 | return 'https://api.invidious.io/instances.json' 56 | 57 | 58 | async def parse_instances(client: httpx.AsyncClient) -> list[Instance]: 59 | response = await client.get(json_url()) 60 | return [ 61 | Instance.from_json(entry) 62 | for entry in response.json() 63 | ] 64 | 65 | 66 | async def test_instance(client: httpx.AsyncClient, instance: Instance) -> InstanceAlive: 67 | try: 68 | response = await client.get(test_video_url(instance.url)) 69 | except (httpx.ConnectTimeout, httpx.ReadTimeout): 70 | return InstanceAlive(instance, False, ) 71 | else: 72 | return InstanceAlive(instance, response.status_code == 200 and 'Invidious' in response.text, ) 73 | 74 | 75 | async def filter_alive(client: httpx.AsyncClient, instances: list[Instance]) -> list[Instance]: 76 | result: Collection[InstanceAlive] = await asyncio.gather( 77 | *(test_instance(client, instance) for instance in instances), 78 | return_exceptions=True 79 | ) 80 | return [ 81 | response.instance 82 | for response in result 83 | if isinstance(response, InstanceAlive) and response.alive 84 | ] 85 | 86 | 87 | def sorted_instances(instances: list[Instance]) -> list[Instance]: 88 | return sorted(instances, key=lambda ins: (-ins.health_percent, ins.active_month)) 89 | 90 | 91 | def file_exists(file_path): 92 | return os.path.isfile(file_path) and os.stat(file_path).st_size > 0 93 | 94 | 95 | async def main(): 96 | if file_exists(CACHE) and '--recalc' not in sys.argv[1:]: 97 | with open(CACHE) as f: 98 | return print(f.read()) 99 | 100 | async with httpx.AsyncClient(timeout=5) as client: 101 | instances = await filter_alive(client, await parse_instances(client)) 102 | 103 | with open(CACHE, 'w') as of: 104 | for instance in sorted_instances(instances): 105 | print(*instance, sep='\t', file=of) 106 | print(*instance, sep='\t') 107 | 108 | 109 | if __name__ == '__main__': 110 | asyncio.run(main()) 111 | -------------------------------------------------------------------------------- /.config/rofi/config.rasi: -------------------------------------------------------------------------------- 1 | configuration { 2 | show-icons: true; 3 | sidebar-mode: true; 4 | font: "Hack Nerd Font Mono 10"; 5 | modi: "drun,run,combi,window"; 6 | combi-modi: "drun,run,ssh"; 7 | terminal: "termite"; 8 | matching: "fuzzy"; 9 | icon-theme: "Papirus"; 10 | 11 | /* Unbind keys that are going to be used in the next section */ 12 | kb-remove-char-back: "BackSpace,Shift+BackSpace"; 13 | kb-accept-entry: "Control+m,Return,KP_Enter"; 14 | kb-remove-to-eol: ""; 15 | kb-mode-complete: ""; 16 | 17 | /* Vim-like bindings */ 18 | kb-row-up: "Control+k,Up,Control+p"; 19 | kb-row-down: "Control+j,Down,Control+n"; 20 | kb-mode-next: "Control+l,Shift+Right,Control+Tab"; 21 | kb-mode-previous: "Control+h,Shift+Left"; 22 | } 23 | 24 | * { 25 | background-color: #222d32; 26 | text-color: #ffffff; 27 | 28 | accent-color: #83a598; 29 | hover-color: #39454b; 30 | urgent-color: #ff5252; 31 | window-color: #ffffff; 32 | 33 | selected-normal-foreground: @window-color; 34 | normal-foreground: @text-color; 35 | selected-normal-background: @hover-color; 36 | normal-background: @background-color; 37 | 38 | selected-urgent-foreground: @background-color; 39 | urgent-foreground: @text-color; 40 | selected-urgent-background: @urgent-color; 41 | urgent-background: @background-color; 42 | 43 | selected-active-foreground: @window-color; 44 | active-foreground: @text-color; 45 | selected-active-background: @hover-color; 46 | active-background: @accent-color; 47 | } 48 | 49 | window { 50 | anchor: west; 51 | location: west; 52 | width: 450px; 53 | height: 100%; 54 | padding: 0px; 55 | } 56 | 57 | scrollbar { 58 | width: 4px; 59 | handle-width: 4px; 60 | handle-color: @accent-color; 61 | } 62 | 63 | mainbox { 64 | children: [ horibox, listview, mode-switcher ]; 65 | } 66 | 67 | horibox { 68 | expand: false; 69 | orientation: horizontal; 70 | children: [ prompt, entry ]; 71 | } 72 | 73 | prompt { 74 | padding: 8px; 75 | background-color: @accent-color; 76 | text-color: @background-color; 77 | } 78 | 79 | entry { 80 | margin: 8px; 81 | } 82 | 83 | element { 84 | padding: 8px; 85 | margin: 0; 86 | } 87 | 88 | element normal.normal { 89 | background-color: @normal-background; 90 | text-color: @normal-foreground; 91 | } 92 | 93 | element normal.urgent { 94 | background-color: @urgent-background; 95 | text-color: @urgent-foreground; 96 | } 97 | 98 | element normal.active { 99 | background-color: @active-background; 100 | text-color: @active-foreground; 101 | } 102 | 103 | element selected.normal { 104 | background-color: @selected-normal-background; 105 | text-color: @selected-normal-foreground; 106 | } 107 | 108 | element selected.urgent { 109 | background-color: @selected-urgent-background; 110 | text-color: @selected-urgent-foreground; 111 | } 112 | 113 | element selected.active { 114 | background-color: @selected-active-background; 115 | text-color: @selected-active-foreground; 116 | } 117 | 118 | element alternate.normal { 119 | background-color: @normal-background; 120 | text-color: @normal-foreground; 121 | } 122 | 123 | element alternate.urgent { 124 | background-color: @urgent-background; 125 | text-color: @urgent-foreground; 126 | } 127 | 128 | element alternate.active { 129 | background-color: @active-background; 130 | text-color: @active-foreground; 131 | } 132 | 133 | button { 134 | padding: 8px; 135 | } 136 | 137 | button selected { 138 | background-color: @active-background; 139 | text-color: @background-color; 140 | } 141 | 142 | /* vim:ft=css 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dotfiles for ajatters 2 | 3 | > https://tatsumoto.neocities.org/ 4 | 5 | Configuration files and scripts I use in my computing. 6 | 7 | ![screenshot](https://user-images.githubusercontent.com/69171671/151655369-699b6e83-e0ef-47e0-986e-be786717c917.png) 8 | 9 | ## Programs used 10 | 11 | * Distro - [Arch Linux](https://archlinux.org/) 12 | * Shell - zsh + [zsh-theme-powerlevel10k](https://archlinux.org/packages/community/x86_64/zsh-theme-powerlevel10k/) 13 | * Terminal - [Alacritty](https://wiki.archlinux.org/title/Alacritty) 14 | * Fonts: 15 | - [Hack Nerd Font Mono](https://archlinux.org/packages/extra/any/ttf-hack-nerd/) 16 | - [FontAwesome](https://archlinux.org/packages/extra/any/awesome-terminal-fonts/) 17 | - `fonts-noto`: 18 | [Ubuntu](https://launchpad.net/ubuntu/+source/fonts-noto), 19 | [Arch](https://archlinux.org/packages/extra/any/noto-fonts/) 20 | * WM - [i3-wm](https://archlinux.org/packages/community/x86_64/i3-wm/). 21 | * Status bar - [i3blocks](https://archlinux.org/packages/community/x86_64/i3blocks/) 22 | * Launcher - [rofi](https://archlinux.org/packages/community/x86_64/rofi/) 23 | * File Manager - [lf](https://github.com/gokcehan/lf) 24 | ([Tutorial](https://github.com/gokcehan/lf/wiki/Tutorial)) 25 | * Fuzzy finder - [fzf](https://wiki.archlinux.org/title/Fzf) 26 | * Image viewer and manga reader - [nsxiv](https://wiki.archlinux.org/title/Sxiv) 27 | * Volume - 28 | [pulsemixer](https://archlinux.org/packages/extra/any/pulsemixer/), 29 | [pamixer](https://archlinux.org/packages/extra/x86_64/pamixer/), 30 | [pavucontrol](https://archlinux.org/packages/extra/x86_64/pavucontrol/) 31 | * X utils - 32 | [hsetroot](https://archlinux.org/packages/extra/x86_64/hsetroot/), 33 | [xwallpaper](https://archlinux.org/packages/extra/x86_64/xwallpaper/), 34 | [xdotool](https://archlinux.org/packages/extra/x86_64/xdotool/), 35 | [xbacklight](https://archlinux.org/packages/extra/x86_64/xorg-xbacklight/) 36 | * brightness - brightnessctl. 37 | To use without sudo, add yourself to the video group: `sudo usermod -a -G video $USER` 38 | * Manga OCR - [transformers-ocr](https://github.com/Ajatt-Tools/transformers_ocr) 39 | * Video player - [mpv](https://wiki.archlinux.org/title/Mpv) + [scripts](https://github.com/search?q=topic%3Ampv+org%3AAjatt-Tools+fork%3Atrue&type=repositories) 40 | * Renaming files - [vidir](https://aur.archlinux.org/packages/vidir) 41 | * Music - [mpd](https://wiki.archlinux.org/title/Music_Player_Daemon)+[ncmpcpp](https://wiki.archlinux.org/title/Ncmpcpp) 42 | * Passive immersion - [impd](https://github.com/Ajatt-Tools/impd) 43 | * Preview images in terminal: 44 | - [ueberzug](https://archlinux.org/packages/?name=ueberzug) or ueberzugpp 45 | - Ubuntu: [ueberzug](https://packages.ubuntu.com/noble/ueberzug) 46 | * RSS reader - [newsboat](https://wiki.archlinux.org/title/Newsboat) 47 | * Archives - atool 48 | * Various scripts in [~/.local/bin/](.local/bin) 49 | * Handy [aliases](.config/shell/aliasrc) and [functions](.config/shell/functionrc) 50 | 51 | ## Installation 52 | 53 | I assume you run a distro based on Arch Linux. 54 | If not, I can't guarantee all the scripts and configs will work. 55 | You can still fork this repo and adjust them for your needs, if necessary. 56 | 57 | Run the following commands in order. 58 | 59 | ``` 60 | git clone --depth 1 --recurse-submodules "https://github.com/tatsumoto-ren/dotfiles.git" ~/dots 61 | cp -rfT ~/dots ~/ 62 | cp -rf ~/.git ~/.config/dotfiles 63 | rm -rf -- ~/dots ~/.git 64 | echo '*' >> ~/.config/dotfiles/info/exclude 65 | ``` 66 | 67 | Then relogin. 68 | 69 | ## Usage 70 | 71 | Use the [dot](.config/shell/aliasrc#L56) command to manage your dotfiles. 72 | For example, `dot status` or `dot add `. 73 | For more information, see 74 | [Tracking dotfiles with Git](https://wiki.archlinux.org/title/Dotfiles#Tracking_dotfiles_directly_with_Git). 75 | 76 | ## Credits 77 | 78 | Certain config files, parts of files and scripts are based on 79 | [voidrice](https://github.com/LukeSmithxyz/voidrice). 80 | -------------------------------------------------------------------------------- /.config/nsxiv/exec/key-handler: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | delete_file() { 4 | if gio trash -- "$file" || trash-put -- "$file"; then 5 | echo "🗑️ '${file##*/}' moved to trash." 6 | elif [ -f "$file" ] && [ "$(printf -- 'No\nYes' | dmenu -i -p "Really delete '$file'?")" = "Yes" ]; then 7 | if rm -- "$file"; then 8 | echo "☑️ '${file##*/}' deleted." & 9 | else 10 | echo "❌ '${file##*/}' wasn't deleted." 11 | fi 12 | fi 13 | } 14 | 15 | copy_file() { 16 | if cp -- "$file" "$destdir"; then 17 | echo "✅ '${file##*/}' copied to $destdir." 18 | else 19 | echo "❌ '${file##*/}' wasn't copied to $destdir." 20 | fi 21 | } 22 | 23 | move_file() { 24 | if mv -- "$file" "$destdir"; then 25 | echo "✅ '${file##*/}' moved to $destdir." 26 | else 27 | echo "❌ '${file##*/}' wasn't moved to $destdir." 28 | fi 29 | } 30 | 31 | ask_dir() { 32 | destdir="$(listmarks dirs | dmenu -l 20 -i -p "$1 file(s) to where?")" 33 | [ -z "$destdir" ] && notify-send "${0##*/}" "Nothing selected, cancelled." && exit 34 | [ ! -d "$destdir" ] && notify-send "${0##*/}" "'$destdir' is not a directory, cancelled." && exit 35 | } 36 | 37 | notify_do() { 38 | result=$( 39 | while read -r file; do 40 | if [ -f "$file" ]; then 41 | "$@" 42 | else 43 | echo "🔥 '${file##*/}' does not exist." 44 | fi 45 | done 46 | ) 47 | notify-send "${0##*/} processed $(echo "$result" | wc -l) files" "$result" & 48 | } 49 | 50 | first_file() { 51 | while read -r file; do echo "$file"; return; done 52 | } 53 | 54 | case "$1" in 55 | "d") 56 | # Trash or remove all selected files. 57 | notify_do delete_file 58 | ;; 59 | "c") 60 | # Copy all selected files to a selected directory. 61 | ask_dir Copy 62 | notify_do copy_file 63 | ;; 64 | "m") 65 | # Move all selected files to a selected directory. 66 | ask_dir Move 67 | notify_do move_file 68 | ;; 69 | "i") 70 | # Display detailed media info for the current image. 71 | notify-send -t 9999 "File information" "$(mediainfo -- "$(first_file)" | sed "s/[ ]\+:/:/g;s/: /: /;s/$/<\/b>/" | grep "")" 72 | ;; 73 | "w") 74 | # Set the current file as a desktop background image. 75 | setbg "$(first_file)" 76 | ;; 77 | "W") 78 | # Convert the current file to webp. 79 | file=$(first_file) 80 | cwebp "$file" -sns 100 -sharp_yuv -f 100 -pass 10 -af -mt -m 6 -o "${file%.*}.webp" & 81 | ;; 82 | "r") 83 | # Rotate the current file by 90 degrees. 84 | file=$(first_file) 85 | magick "$file" -rotate 90 "$file" 86 | ;; 87 | "R") 88 | # Rotate the current file by -90 degrees. 89 | file=$(first_file) 90 | magick "$file" -rotate -90 "$file" 91 | ;; 92 | "f") 93 | # Flop the current file. 94 | file=$(first_file) 95 | magick "$file" -flop "$file" 96 | ;; 97 | "F") 98 | # Copy file path to the clipboard. 99 | file=$( readlink -f -- "$( first_file )" ) 100 | lf-file-op --uri "$file" && 101 | notify-send -i "$file" "${0##*/}" "$file URI copied to clipboard" & 102 | ;; 103 | "I") 104 | # Negate the current file. 105 | file=$(first_file) 106 | magick "$file" -channel RGB -negate "$file" 107 | ;; 108 | "y") 109 | # Copy file name to the clipboard. 110 | file=$( readlink -f -- "$( first_file )" ) 111 | lf-file-op --name "$file" && 112 | notify-send -i "$file" "$file name copied to clipboard" & 113 | ;; 114 | "Y") 115 | # Copy file path to the clipboard. 116 | file=$( readlink -f -- "$( first_file )" ) 117 | lf-file-op --path "$file" && 118 | notify-send -i "$file" "${0##*/}" "$file path copied to clipboard" & 119 | ;; 120 | "g") 121 | # Edit the current file in gimp. 122 | ifinstalled gimp && setsid -f gimp "$(first_file)" 123 | ;; 124 | "t") 125 | # Tag the current file using lf. E.g, the last read manga page. 126 | # When sxiv is launched as a child of lf, the 'id' vairable must be set. 127 | if [ -n "$id" ] && ifinstalled lf; then 128 | lf -remote "send $id select \"$(first_file)\" " 129 | lf -remote "send $id tag x" 130 | fi 131 | ;; 132 | *) 133 | notify-send "${0##*/}" "$1 is not bound." & 134 | ;; 135 | esac 136 | -------------------------------------------------------------------------------- /.config/lf/scope: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # https://github.com/jstkdng/ueberzugpp/blob/master/scripts/lf/preview 4 | 5 | # File preview handler for lf. 6 | 7 | [[ ${1} == *'.!qB' ]] && exit 8 | 9 | 10 | set -C -f 11 | IFS="$(printf '%b_' '\n')"; IFS="${IFS%_}" 12 | 13 | printf '{"action": "remove", "identifier": "PREVIEW"}\n' > "$FIFO_UEBERZUG" 14 | 15 | image() { 16 | if [ -f "$1" ] && [ -n "$DISPLAY" ] && [ -z "$WAYLAND_DISPLAY" ] && command -V ueberzug >/dev/null 2>&1; then 17 | printf '{"action": "add", "identifier": "PREVIEW", "x": "%s", "y": "%s", "width": "%s", "height": "%s", "scaler": "contain", "path": "%s"}\n' "$4" "$5" "$(($2-1))" "$(($3-1))" "$1" > "$FIFO_UEBERZUG" 18 | else 19 | mediainfo "$6" 20 | fi 21 | } 22 | 23 | if command -v batcat >/dev/null 2>&1; then 24 | # Ubuntu workaround 25 | bat() { 26 | batcat "$@" 27 | } 28 | fi 29 | 30 | batorcat() { 31 | file="$1" 32 | shift 33 | if command -v bat >/dev/null 2>&1; then 34 | bat --color=always --style=plain --pager=never "$file" "$@" 35 | else 36 | cat "$file" 37 | fi 38 | } 39 | 40 | # Note that the cache file name is a function of file information, meaning if 41 | # an image appears in multiple places across the machine, it will not have to 42 | # be regenerated once seen. 43 | 44 | case "$(file --dereference --brief --mime-type -- "$1")" in 45 | image/avif) 46 | CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/lf/thumb.$(stat --printf '%n\0%i\0%F\0%s\0%W\0%Y' -- "$(readlink -f "$1")" | sha256sum | cut -d' ' -f1)" 47 | [ ! -f "$CACHE" ] && magick "$1" "$CACHE.jpg" 48 | image "$CACHE.jpg" "$2" "$3" "$4" "$5" "$1" ;; 49 | image/vnd.djvu) 50 | CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/lf/thumb.$(stat --printf '%n\0%i\0%F\0%s\0%W\0%Y' -- "$(readlink -f "$1")" | sha256sum | cut -d' ' -f1)" 51 | [ ! -f "$CACHE" ] && djvused "$1" -e 'select 1; save-page-with /dev/stdout' | magick -density 200 - "$CACHE.jpg" > /dev/null 2>&1 52 | image "$CACHE.jpg" "$2" "$3" "$4" "$5" "$1" ;; 53 | image/svg+xml) 54 | CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/lf/thumb.$(stat --printf '%n\0%i\0%F\0%s\0%W\0%Y' -- "$(readlink -f "$1")" | sha256sum | cut -d' ' -f1)" 55 | [ ! -f "$CACHE" ] && inkscape --convert-dpi-method=none -o "$CACHE.png" --export-overwrite -D --export-png-color-mode=RGBA_16 "$1" 56 | image "$CACHE.png" "$2" "$3" "$4" "$5" "$1" 57 | ;; 58 | image/x-xcf) 59 | CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/lf/thumb.$(stat --printf '%n\0%i\0%F\0%s\0%W\0%Y' -- "$(readlink -f "$1")" | sha256sum | awk '{print $1}')" 60 | [ ! -f "$CACHE.jpg" ] && magick "$1[0]" "$CACHE.jpg" 61 | image "$CACHE.jpg" "$2" "$3" "$4" "$5" "$1" 62 | ;; 63 | image/*) 64 | image "$1" "$2" "$3" "$4" "$5" "$1" ;; 65 | text/html) 66 | lynx -width="$4" -display_charset=utf-8 -dump "$1" ;; 67 | text/troff) 68 | man ./ "$1" | col -b ;; 69 | text/* | */xml | application/json | application/x-ndjson) 70 | bat -p --theme ansi --terminal-width "$(($4-2))" -f "$1" ;; 71 | audio/* | application/octet-stream | *djvu) 72 | killall mediainfo 73 | mediainfo "$1" || exit 1 74 | ;; 75 | video/* ) 76 | CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/lf/thumb.$(stat --printf '%n\0%i\0%F\0%s\0%W\0%Y' -- "$(readlink -f "$1")" | sha256sum | cut -d' ' -f1)" 77 | [ ! -f "$CACHE" ] && ffmpegthumbnailer -i "$1" -o "$CACHE" -s 0 78 | image "$CACHE" "$2" "$3" "$4" "$5" "$1" 79 | ;; 80 | */pdf) 81 | CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/lf/thumb.$(stat --printf '%n\0%i\0%F\0%s\0%W\0%Y' -- "$(readlink -f "$1")" | sha256sum | cut -d' ' -f1)" 82 | [ ! -f "$CACHE.jpg" ] && pdftoppm -jpeg -f 1 -singlefile "$1" "$CACHE" 83 | image "$CACHE.jpg" "$2" "$3" "$4" "$5" "$1" 84 | ;; 85 | */epub+zip|*/mobi*) 86 | CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/lf/thumb.$(stat --printf '%n\0%i\0%F\0%s\0%W\0%Y' -- "$(readlink -f "$1")" | sha256sum | cut -d' ' -f1)" 87 | [ ! -f "$CACHE.jpg" ] && gnome-epub-thumbnailer "$1" "$CACHE.jpg" 88 | image "$CACHE.jpg" "$2" "$3" "$4" "$5" "$1" 89 | ;; 90 | application/*zip | application/*tar) 91 | atool --list -- "$1" ;; 92 | *opendocument*) 93 | odt2txt "$1" ;; 94 | application/pgp-encrypted) 95 | gpg -d -- "$1" ;; 96 | *) 97 | batorcat "$1" 98 | ;; 99 | esac 100 | exit 1 101 | -------------------------------------------------------------------------------- /.config/shell/aliasrc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Use neovim for vim if present. 4 | [ -x "$(command -v nvim)" ] && alias vim="nvim" vimdiff="nvim -d" 5 | 6 | # Use $XINITRC variable if file exists. 7 | [ -f "$XINITRC" ] && alias startx='startx $XINITRC' 8 | 9 | [ -f "$MBSYNCRC" ] && alias mbsync='mbsync -c $MBSYNCRC' 10 | 11 | # Verbosity and settings that you pretty much just always are going to want. 12 | alias \ 13 | cp="cp -iv" \ 14 | mv="mv -iv" \ 15 | rm="rm -vI" \ 16 | bc="bc -ql" \ 17 | rsync="rsync -vrPlu" \ 18 | mkd="mkdir -pv" \ 19 | ffmpeg="ffmpeg -hide_banner" \ 20 | :q="exit" \ 21 | help="man" \ 22 | chd='cd -- "$(choose_from_cwds)" && ls -a' \ 23 | rclone="rclone -v" \ 24 | 25 | # Youtube 26 | alias \ 27 | ytd="yt-dlp --embed-metadata -i" \ 28 | ytautosub="ytd --write-auto-sub --sub-lang ja" \ 29 | yta="ytd -x -f bestaudio/best" \ 30 | mp3dl="yta --audio-quality 1 --audio-format mp3" \ 31 | ytv="youtube-viewer" \ 32 | ytt="ytd --skip-download --write-thumbnail" \ 33 | ytw="ytd --merge-output-format webm -f 'bestvideo[ext=webm]+bestaudio/best[ext=webm]'" \ 34 | 35 | # Colorize commands when possible. 36 | alias \ 37 | ls="ls -hN --color=auto --group-directories-first" \ 38 | grep="grep --color=auto" \ 39 | ggrep="grep --exclude-dir='.git' --exclude-dir='.mypy_cache'" \ 40 | diff="diff --color=auto" \ 41 | ccat="highlight --out-format=ansi" \ 42 | ip="ip -color=auto" \ 43 | 44 | # Other stuff 45 | alias \ 46 | lf="lfub" \ 47 | magit="nvim -c MagitOnly" \ 48 | tmux="tmux -f \${XDG_CONFIG_HOME}/tmux/tmux.conf" \ 49 | timer='echo "Timer started. Stop with Ctrl-D." && date "+%a, %d %b %H:%M:%S" && time cat && date "+%a, %d %b %H:%M:%S"' \ 50 | updxrdb="xrdb -merge \${XDG_CONFIG_HOME}/Xresources" \ 51 | genpasswd="openssl rand -base64 21" \ 52 | update-grub="sudo grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB --recheck ; sudo grub-mkconfig -o /boot/grub/grub.cfg" \ 53 | trim="sudo fstrim -v / && sudo fstrim -v /home" \ 54 | showpath="echo \$PATH | sed 's/:/\n/g'" \ 55 | visoodoo="sudo visudo -f /etc/sudoers.d/01_sudoers" \ 56 | res_screencast="xrandr --output DP1 --primary --mode 1920x1080" \ 57 | res_normal="xrandr --output DP1 --primary --mode 1920x1200" \ 58 | charm="setsid -f pycharm . ; sleep 3s ; exit" \ 59 | 60 | # dotfiles in git 61 | # https://wiki.archlinux.org/index.php/Dotfiles 62 | # or use ~/.git/info/exclude 63 | alias dot='git --git-dir=${XDG_CONFIG_HOME}/dotfiles/ --work-tree=$HOME' 64 | 65 | # Journal 66 | alias \ 67 | journal="journalctl --since '3 day ago'" \ 68 | errors="journalctl -p err..alert -b -e" \ 69 | 70 | # Applications 71 | alias \ 72 | clock="ncmpcpp -s clock" \ 73 | visualizer="ncmpcpp -s visualizer" \ 74 | nb="newsboat" \ 75 | getmail="offlineimap && notmuch new" \ 76 | gm="offlineimap && notmuch new" \ 77 | nf="clear && neofetch" \ 78 | kakasi_reading="kakasi -i utf8 -o utf8 -u -JH -KH" \ 79 | 80 | # Morphological analysis 81 | 82 | alias \ 83 | mecabfurigana="my_mecab '--node-format=%m[%f[7]] ' '--eos-format=\n' '--unk-format=%m '" \ 84 | mecabanalyze="my_mecab '--node-format=%m,%f[6],%f[7],%f[0],%f[5]\n' '--unk-format=%m\n' '--eos-format=\n'" \ 85 | 86 | # Pacman / system 87 | 88 | alias \ 89 | lsp="pacman -Qett --color=always | less" \ 90 | notify-pacman-block="pkill -RTMIN+8 i3blocks" \ 91 | upd="sb-popupgrade --no-wait" \ 92 | trimlogs='sudo journalctl --vacuum-size=150M' \ 93 | pacclean="remorphans && sudo pacman -Sc && trimlogs" \ 94 | whathaveidone="tail -500 /var/log/pacman.log | grep -i 'installed\|removed\|graded' --color=never" \ 95 | refl='sudo reflector --protocol https --download-timeout 60 --verbose --age 6 --latest 100 --fastest 10 --sort rate --country "$(curl -Ls "ifconfig.co/country")" --save /etc/pacman.d/mirrorlist' \ 96 | reflp='sudo reflector --url "https://www.parabola.nu/mirrors/status/json" --protocol https --download-timeout 60 --verbose --age 12 --latest 100 --fastest 10 --sort rate --save /etc/pacman.d/parabola-mirrorlist' \ 97 | printsrcinfo="makepkg --printsrcinfo > .SRCINFO" \ 98 | unlockme='faillock --user "$USER" --reset' \ 99 | listkernels='ls -1 /boot/vmli*' \ 100 | egit='sudo etckeeper vcs' \ 101 | te='gio trash --empty' \ 102 | ref='shortcuts >/dev/null; source ${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutrc ; source ${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutenvrc ; source ${XDG_CONFIG_HOME:-$HOME/.config}/shell/zshnameddirrc' 103 | hogs='ps axch -o cmd:15,%mem --sort=-%mem | head -20' \ 104 | -------------------------------------------------------------------------------- /.local/bin/rssget: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Searches the website for RSS feeds and adds them to newsboat url list. Can 4 | # also find hidden RSS feeds on various websites, namely Youtube, Reddit, 5 | # Vimeo, Github, Gitlab and Medium. Gets site url as $1 or (if not present) 6 | # from X clipboard. Gets tags as $2. If it finds more than one feed, calls 7 | # dmenu for the user to choose which one to add. I have bound it to a keyboard 8 | # shortcut so i copy a site link and easily add its feed to the reader. 9 | 10 | # Inspired by and based on the logic of this extension: 11 | # https://github.com/shevabam/get-rss-feed-url-extension 12 | 13 | # This script requires rssadd to add feeds to the list. 14 | 15 | getlink () { 16 | local url="$1" 17 | feeds="$(curl -s "$url" | grep -Ex '.*type=.*(rss|rdf|atom).*' | sed 's/ //g')" 18 | url="$(echo $url | sed 's|^\(https://[^/]*/\).*|\1|')" 19 | 20 | for rsspath in $feeds; do 21 | rsspath="$(echo $rsspath | sed -n "s|.*href=['\"]\([^'\"]*\)['\"].*|\1|p")" 22 | if echo "$rsspath" | grep "http" > /dev/null; then 23 | link="$rsspath" 24 | elif echo "$rsspath" | grep -E "^/" > /dev/null; then 25 | link="$url$(echo $rsspath | sed 's|^/||')" 26 | else 27 | link="$url$rsspath" 28 | fi 29 | echo $link 30 | done 31 | } 32 | 33 | getRedditRss() { 34 | echo "${1%/}.rss" 35 | } 36 | 37 | getYoutubeRss() { 38 | local url="$1" 39 | path=$(echo "$url" | sed -e 's|^http[s]*://||') 40 | case "$path" in 41 | *"/channel/"*) channel_id="$(echo $path | sed -r 's|.*channel/([^/]*).*|\1|')" && feed="https://www.youtube.com/feeds/videos.xml?channel_id=${channel_id}" ;; 42 | *"/c/"*|*"/user/"*) 43 | feed=$(wget -q "$url" -O tmp_rssget_yt \ 44 | && sed -n 's|.*\("rssUrl":"[^"]*\).*|\1|; p' tmp_rssget_yt \ 45 | | grep rssUrl \ 46 | | sed 's|"rssUrl":"||') ;; 47 | esac 48 | echo "$feed" 49 | } 50 | 51 | getVimeoRss() { 52 | local url="$1" 53 | if echo "$url" | grep -q "/videos$"; then 54 | feed_url=$(echo "$url" | sed 's/\/videos$//' | sed 's/\/$/\/rss/') 55 | else 56 | feed_url="${url}/videos/rss" 57 | fi 58 | echo "$feed_url" 59 | } 60 | 61 | getGithubRss () { 62 | local url="${1%/}" 63 | if echo $url | grep -E "github.com/[^/]*/[a-zA-Z0-9].*" >/dev/null ; then 64 | echo "${url}/commits.atom" 65 | echo "${url}/releases.atom" 66 | echo "${url}/tags.atom" 67 | elif echo $url | grep -E "github.com/[^/]*(/)" >/dev/null ; then 68 | echo "${url}.atom" 69 | fi 70 | } 71 | 72 | getGitlabRss () { 73 | local url="${1%/}" 74 | echo "${url}.atom" 75 | } 76 | 77 | getMediumRss () { 78 | echo $1 | sed 's|/tag/|/feed/|' 79 | } 80 | 81 | 82 | if [ -n "$1" ] ; then 83 | url="$1" 84 | else 85 | url="$(xclip -selection clipboard -o)" 86 | [ -z "$url" ] && echo "usage: $0 url 'tag1 tag2 tag3'" && exit 1 87 | fi 88 | 89 | declare -a list=() 90 | 91 | yt_regex="^(http(s)?://)?((w){3}\.)?(youtube\.com|invidio\.us|invidious\.flokinet\.to|invidious\.materialio\.us|iv\.datura\.network|invidious\.perennialte\.ch|invidious\.fdn\.fr|invidious\.private\.coffee|invidious\.protokolla\.fi|invidious\.privacyredirect\.com|yt\.artemislena\.eu|yt\.drgnz\.club|invidious\.incogniweb\.net|yewtu\.be|inv\.tux\.pizza|invidious\.reallyaweso\.me|iv\.melmac\.space|inv\.us\.projectsegfau\.lt|inv\.nadeko\.net|invidious\.darkness\.services|invidious\.jing\.rocks|invidious\.privacydev\.net|inv\.in\.projectsegfau\.lt|invidious\.drgns\.space)/(channel|user|c).+" 92 | reddit_regex="^(http(s)?://)?((w){3}\.)?reddit\.com.*" 93 | vimeo_regex="^(http(s)?://)?((w){3}.)?vimeo\.com.*" 94 | if echo $url | grep -Ex "$yt_regex" >/dev/null ; then 95 | list="$(getYoutubeRss "$url")" 96 | elif echo $url | grep -Ex "$reddit_regex" >/dev/null ; then 97 | list="$(getRedditRss "$url")" 98 | # vimeo actually works with getlink 99 | elif echo $url | grep -E "$vimeo_regex" >/dev/null ; then 100 | list="$(getVimeoRss "$url")" 101 | elif echo $url | grep -E "github.com" >/dev/null ; then 102 | list="$(getGithubRss "$url")" 103 | # gitlab also works with getlink 104 | elif echo $url | grep -E "gitlab.com/[a-zA-Z0-9].*" >/dev/null ; then 105 | list="$(getGitlabRss "$url")" 106 | elif echo $url | grep -E "medium.com/tag" >/dev/null ; then 107 | list="$(getMediumRss "$url")" 108 | else 109 | list="$(getlink "$url")" 110 | fi 111 | 112 | [ "$(echo "$list" | wc -l)" -eq 1 ] && chosen_link="$list" || chosen_link=$(printf '%s\n' "${list[@]}" | dmenu -p "Choose a feed:") 113 | tags="$2" 114 | ifinstalled rssadd && rssadd "$chosen_link" "$tags" 115 | echo "$chosen_link" "$tags" 116 | -------------------------------------------------------------------------------- /.config/alacritty/alacritty.toml: -------------------------------------------------------------------------------- 1 | [general] 2 | live_config_reload = true 3 | import = [ 4 | "~/.config/alacritty/themes/themes/gruvbox_dark.toml" 5 | ] 6 | 7 | [colors] 8 | draw_bold_text_with_bright_colors = true 9 | 10 | [colors.bright] 11 | black = "#928374" 12 | red = "#fb4934" 13 | green = "#b8bb26" 14 | yellow = "#fabd2f" 15 | blue = "#83a598" 16 | magenta = "#d3869b" 17 | cyan = "#8ec07c" 18 | white = "#ebdbb2" 19 | 20 | [colors.cursor] 21 | cursor = "#4ced4c" 22 | # style = "Block" 23 | 24 | [colors.normal] 25 | black = "0x222d32" 26 | red = "0xfb4934" 27 | green = "0x98971a" 28 | yellow = "0xd79921" 29 | blue = "0x83a598" 30 | magenta = "0xb16286" 31 | cyan = "0x689d6a" 32 | white = "0xfbf1c7" 33 | 34 | [colors.primary] 35 | #background = "#222d32" 36 | background = "#2f343f" 37 | foreground = "#f1fcf9" 38 | 39 | [env] 40 | #TERM = "xterm-256color" 41 | TERM = "alacritty" 42 | 43 | [font] 44 | size = 10.5 45 | 46 | [font.normal] 47 | family = "Hack" 48 | 49 | [font.bold] 50 | family = "Hack" 51 | style = "Bold" 52 | 53 | [font.italic] 54 | family = "Hack" 55 | style = "Italic" 56 | 57 | [[hints.enabled]] 58 | command = "linkhandler" 59 | post_processing = true 60 | regex = "(ipfs:|ipns:|magnet:|mailto:|gemini:|gopher:|https:|http:|news:|file:|git:|ssh:|ftp:)[^\u0000-\u001F\u007F-Ÿ<>\"\\s{-}\\^⟨⟩`]+" 61 | 62 | [hints.enabled.binding] 63 | key = "L" 64 | mods = "Control|Shift" 65 | 66 | [hints.enabled.mouse] 67 | enabled = true 68 | mods = "None" 69 | 70 | [[hints.enabled]] 71 | action = "Copy" 72 | post_processing = false 73 | regex = '([0-9a-f]{7,128})|([[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3})|(i-[0-9a-f]{17})' 74 | 75 | [hints.enabled.binding] 76 | key = "U" 77 | mods = "Control|Shift" 78 | 79 | [[keyboard.bindings]] 80 | chars = "\u0011:" 81 | key = "Semicolon" 82 | mods = "Command" 83 | 84 | [[keyboard.bindings]] 85 | chars = "\u0011:" 86 | key = "Semicolon" 87 | mods = "Command|Shift" 88 | 89 | [[keyboard.bindings]] 90 | chars = "\u0011\"" 91 | key = "D" 92 | mods = "Command|Shift" 93 | 94 | [[keyboard.bindings]] 95 | chars = "\u0011%" 96 | key = "D" 97 | mods = "Command" 98 | 99 | [[keyboard.bindings]] 100 | chars = "\u0011c" 101 | key = "T" 102 | mods = "Command" 103 | 104 | [[keyboard.bindings]] 105 | chars = "\u0011X" 106 | key = "W" 107 | mods = "Command" 108 | 109 | [[keyboard.bindings]] 110 | chars = "\u0011o" 111 | key = "O" 112 | mods = "Command" 113 | 114 | [[keyboard.bindings]] 115 | chars = "\u0011\u000F" 116 | key = "O" 117 | mods = "Command|Shift" 118 | 119 | [[keyboard.bindings]] 120 | chars = "\u00111" 121 | key = "Key1" 122 | mods = "Command" 123 | 124 | [[keyboard.bindings]] 125 | chars = "\u00112" 126 | key = "Key2" 127 | mods = "Command" 128 | 129 | [[keyboard.bindings]] 130 | chars = "\u00113" 131 | key = "Key3" 132 | mods = "Command" 133 | 134 | [[keyboard.bindings]] 135 | chars = "\u00114" 136 | key = "Key4" 137 | mods = "Command" 138 | 139 | [[keyboard.bindings]] 140 | chars = "\u00115" 141 | key = "Key5" 142 | mods = "Command" 143 | 144 | [[keyboard.bindings]] 145 | chars = "\u00116" 146 | key = "Key6" 147 | mods = "Command" 148 | 149 | [[keyboard.bindings]] 150 | chars = "\u00116" 151 | key = "Key7" 152 | mods = "Command" 153 | 154 | [[keyboard.bindings]] 155 | chars = "\u00117" 156 | key = "Key8" 157 | mods = "Command" 158 | 159 | [[keyboard.bindings]] 160 | chars = "\u00119" 161 | key = "Key9" 162 | mods = "Command" 163 | 164 | [[keyboard.bindings]] 165 | chars = "\u0011p" 166 | key = "PageUp" 167 | mods = "Control" 168 | 169 | [[keyboard.bindings]] 170 | chars = "\u0011n" 171 | key = "PageDown" 172 | mods = "Control" 173 | 174 | [[keyboard.bindings]] 175 | chars = "\u0011w" 176 | key = "E" 177 | mods = "Command" 178 | 179 | [[keyboard.bindings]] 180 | chars = "\u0011H" 181 | key = "Left" 182 | mods = "Command" 183 | 184 | [[keyboard.bindings]] 185 | chars = "\u0011J" 186 | key = "Down" 187 | mods = "Command" 188 | 189 | [[keyboard.bindings]] 190 | chars = "\u0011K" 191 | key = "Up" 192 | mods = "Command" 193 | 194 | [[keyboard.bindings]] 195 | chars = "\u0011L" 196 | key = "Right" 197 | mods = "Command" 198 | 199 | [[keyboard.bindings]] 200 | chars = "\u0011\b" 201 | key = "Comma" 202 | mods = "Command|Shift" 203 | 204 | [[keyboard.bindings]] 205 | chars = "\u0011\f" 206 | key = "Period" 207 | mods = "Command|Shift" 208 | 209 | [[keyboard.bindings]] 210 | chars = "\u0011[" 211 | key = "LBracket" 212 | mods = "Command" 213 | 214 | [window] 215 | #decorations = "none" 216 | dynamic_title = true 217 | opacity = 1.0 218 | 219 | [window.padding] 220 | x = 2 221 | y = 0 222 | -------------------------------------------------------------------------------- /.local/bin/mounter: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Mounts Android Phones and USB drives (encrypted or not). This script will 4 | # replace the older `dmenumount` which had extra steps and couldn't handle 5 | # encrypted drives. 6 | # TODO: Try decrypt for drives in crtypttab 7 | # TODO: Add some support for connecting iPhones (although they are annoying). 8 | 9 | IFS=' 10 | ' 11 | # Function for escaping cell-phone names. 12 | escape(){ echo "$@" | iconv -cf UTF-8 -t ASCII//TRANSLIT | tr -d '[:punct:]' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | sed "s/-\+/-/g;s/\(^-\|-\$\)//g" ;} 13 | 14 | # Check for phones. 15 | phones="$(simple-mtpfs -l 2>/dev/null | sed "s/^/📱/")" 16 | mountedphones="$(grep "simple-mtpfs" /etc/mtab)" 17 | # If there are already mounted phones, remove them from the list of mountables. 18 | [ -n "$mountedphones" ] && phones="$(for phone in $phones; do 19 | for mounted in $mountedphones; do 20 | escphone="$(escape "$phone")" 21 | [[ "$mounted" =~ "$escphone" ]] && break 1 22 | done && continue 1 23 | echo "$phone" 24 | done)" 25 | 26 | # Check for drives. 27 | lsblkoutput="$(lsblk -rpo "uuid,name,type,size,label,mountpoint,fstype")" 28 | # Get all LUKS drives 29 | allluks="$(echo "$lsblkoutput" | grep crypto_LUKS)" 30 | # Get a list of the LUKS drive UUIDs already decrypted. 31 | decrypted="$(find /dev/disk/by-id/dm-uuid-CRYPT-LUKS2-* | sed "s|.*LUKS2-||;s|-.*||")" 32 | # Functioning for formatting drives correctly for dmenu: 33 | filter() { sed "s/ /:/g" | awk -F':' '$7==""{printf "%s%s (%s) %s\n",$1,$3,$5,$6}' ; } 34 | 35 | # Get only LUKS drives that are not decrypted. 36 | unopenedluks="$(for drive in $allluks; do 37 | uuid="${drive%% *}" 38 | uuid="${uuid//-}" # This is a bashism. 39 | [ -n "$decrypted" ] && for open in $decrypted; do 40 | [ "$uuid" = "$open" ] && break 1 41 | done && continue 1 42 | echo "🔒 $drive" 43 | done | filter)" 44 | 45 | # Get all normal, non-encrypted or decrypted partitions that are not mounted. 46 | normalparts="$(echo "$lsblkoutput"| grep -v crypto_LUKS | grep 'part\|rom\|crypt' | sed "s/^/💾 /" | filter )" 47 | 48 | # Add all to one variable. If no mountable drives found, exit. 49 | alldrives="$(echo "$phones 50 | $unopenedluks 51 | $normalparts" | sed "/^$/d;s/ *$//")" 52 | 53 | # Quit the script if a sequential command fails. 54 | set -e 55 | 56 | test -n "$alldrives" 57 | 58 | # Feed all found drives to dmenu and get user choice. 59 | chosen="$(echo "$alldrives" | dmenu -p "Mount which drive?" -i)" 60 | 61 | # Function for prompting user for a mountpoint. 62 | getmount(){ 63 | mp="$(find /mnt /media /mount /home -maxdepth 1 -type d 2>/dev/null | dmenu -i -p "Mount this drive where?")" 64 | test -n "$mp" 65 | if [ ! -d "$mp" ]; then 66 | mkdiryn=$(printf "No\\nYes" | dmenu -i -p "$mp does not exist. Create it?") 67 | [ "$mkdiryn" = "Yes" ] && (mkdir -p "$mp" || sudo -A mkdir -p "$mp") 68 | fi 69 | } 70 | 71 | attemptmount(){ 72 | # Attempt to mount without a mountpoint, to see if drive is in fstab. 73 | sudo -A mount "$chosen" || return 1 74 | notify-send "💾Drive Mounted." "$chosen mounted." 75 | exit 76 | } 77 | 78 | case "$chosen" in 79 | 💾*) 80 | chosen="${chosen%% *}" 81 | chosen="${chosen:1}" # This is a bashism. 82 | parttype="$(echo "$lsblkoutput" | grep "$chosen")" 83 | attemptmount || getmount 84 | case "${parttype##* }" in 85 | vfat) sudo -A mount -t vfat "$chosen" "$mp" -o rw,umask=0000 ;; 86 | btrfs) sudo -A mount "$chosen" "$mp" ;; 87 | *) sudo -A mount "$chosen" "$mp" -o uid="$(id -u)",gid="$(id -g)" ;; 88 | esac 89 | notify-send "💾Drive Mounted." "$chosen mounted to $mp." 90 | ;; 91 | 92 | 🔒*) 93 | chosen="${chosen%% *}" 94 | chosen="${chosen:1}" # This is a bashism. 95 | # Number the drive. 96 | while true; do 97 | [ -f "/dev/mapper/usb$num" ] || break 98 | num="$(printf "%02d" "$((num +1))")" 99 | done 100 | 101 | # Decrypt in a terminal window 102 | ${TERMINAL:-st} -n floatterm -g 60x1 -e sudo cryptsetup open "$chosen" "usb$num" 103 | # Check if now decrypted. 104 | test -b "/dev/mapper/usb$num" 105 | 106 | attemptmount || getmount 107 | sudo -A mount "/dev/mapper/usb$num" "$mp" -o uid="$(id -u)",gid="$(id -g)" 108 | notify-send "🔓Decrypted drive Mounted." "$chosen decrypted and mounted to $mp." 109 | ;; 110 | 111 | 📱*) 112 | notify-send "❗Note" "Remember to allow file access on your phone now." 113 | getmount 114 | number="${chosen%%:*}" 115 | number="${chosen:1}" # This is a bashism. 116 | sudo -A simple-mtpfs -o allow_other -o fsname="simple-mtpfs-$(escape "$chosen")" --device "$number" "$mp" 117 | notify-send "🤖 Android Mounted." "Android device mounted to $mp." 118 | ;; 119 | esac 120 | -------------------------------------------------------------------------------- /.config/fontconfig/conf.d/10-powerline-symbols.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 33 | 34 | 35 | 36 | monospace 37 | PowerlineSymbols 38 | 39 | 40 | Droid Sans Mono 41 | PowerlineSymbols 42 | 43 | 44 | Droid Sans Mono Slashed 45 | PowerlineSymbols 46 | 47 | 48 | Droid Sans Mono Dotted 49 | PowerlineSymbols 50 | 51 | 52 | DejaVu Sans Mono 53 | PowerlineSymbols 54 | 55 | 56 | DejaVu Sans Mono 57 | PowerlineSymbols 58 | 59 | 60 | Envy Code R 61 | PowerlineSymbols 62 | 63 | 64 | Inconsolata 65 | PowerlineSymbols 66 | 67 | 68 | Lucida Console 69 | PowerlineSymbols 70 | 71 | 72 | Monaco 73 | PowerlineSymbols 74 | 75 | 76 | Pragmata 77 | PowerlineSymbols 78 | 79 | 80 | PragmataPro 81 | PowerlineSymbols 82 | 83 | 84 | Menlo 85 | PowerlineSymbols 86 | 87 | 88 | Source Code Pro 89 | PowerlineSymbols 90 | 91 | 92 | Consolas 93 | PowerlineSymbols 94 | 95 | 96 | Anonymous pro 97 | PowerlineSymbols 98 | 99 | 100 | Bitstream Vera Sans Mono 101 | PowerlineSymbols 102 | 103 | 104 | Liberation Mono 105 | PowerlineSymbols 106 | 107 | 108 | Ubuntu Mono 109 | PowerlineSymbols 110 | 111 | 112 | Meslo LG L 113 | PowerlineSymbols 114 | 115 | 116 | Meslo LG L DZ 117 | PowerlineSymbols 118 | 119 | 120 | Meslo LG M 121 | PowerlineSymbols 122 | 123 | 124 | Meslo LG M DZ 125 | PowerlineSymbols 126 | 127 | 128 | Meslo LG S 129 | PowerlineSymbols 130 | 131 | 132 | Meslo LG S DZ 133 | PowerlineSymbols 134 | 135 | 136 | Hack 137 | PowerlineSymbols 138 | 139 | 140 | -------------------------------------------------------------------------------- /.local/bin/slider: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Give a file with images and timecodes and creates a video slideshow of them. 4 | # 5 | # Timecodes must be in format 00:00:00. 6 | # 7 | # Imagemagick and ffmpeg required. 8 | 9 | # Application cache if not stated elsewhere. 10 | cache="${XDG_CACHE_HOME:-$HOME/.cache}/slider" 11 | 12 | while getopts "hvrpi:c:a:o:d:f:t:e:x:s:" o; do case "${o}" in 13 | c) bgc="$OPTARG" ;; 14 | t) fgc="$OPTARG" ;; 15 | f) font="$OPTARG" ;; 16 | i) file="$OPTARG" ;; 17 | a) audio="$OPTARG" ;; 18 | o) outfile="$OPTARG" ;; 19 | d) prepdir="$OPTARG" ;; 20 | r) redo="$OPTARG" ;; 21 | s) ppt="$OPTARG" ;; 22 | e) endtime="$OPTARG" ;; 23 | x) res="$OPTARG" 24 | echo "$res" | grep -qv "^[0-9]\+x[0-9]\+$" && 25 | echo "Resolution must be dimensions separated by a 'x': 1280x720, etc." && 26 | exit 1 ;; 27 | p) echo "Purge old build files in $cache? [y/N]" 28 | read -r confirm 29 | echo "$confirm" | grep -iq "^y$" && rm -rf "$cache" && echo "Done." 30 | exit ;; 31 | v) verbose=True ;; 32 | *) echo "$(basename "$0") usage: 33 | -i input timecode list (required) 34 | -a audio file 35 | -c color of background (use html names, black is default) 36 | -t text color for text slides (white is default) 37 | -s text font size for text slides (150 is default) 38 | -f text font for text slides (sans serif is default) 39 | -o output video file 40 | -e if no audio given, the time in seconds that the last slide will be shown (5 is default) 41 | -x resolution (1920x1080 is default) 42 | -d tmp directory 43 | -r rerun imagemagick commands even if done previously (in case files or background has changed) 44 | -p purge old build files instead of running 45 | -v be verbose" && exit 1 46 | 47 | esac done 48 | 49 | # Check that the input file looks like it should. 50 | { head -n 1 "$file" 2>/dev/null | grep -q "^00:00:00 " ;} || { 51 | echo "Give an input file with -i." && 52 | echo "The file should look as this example: 53 | 54 | 00:00:00 first_image.jpg 55 | 00:00:03 otherdirectory/next_image.jpg 56 | 00:00:09 this_image_starts_at_9_seconds.jpg 57 | etc... 58 | 59 | Timecodes and filenames must be separated by Tabs." && 60 | exit 1 61 | } 62 | 63 | if [ -n "${audio+x}" ]; then 64 | # Check that the audio file looks like an actual audio file. 65 | case "$(file --dereference --brief --mime-type -- "$audio")" in 66 | audio/*) ;; 67 | *) echo "That doesn't look like an audio file."; exit 1 ;; 68 | esac 69 | totseconds="$(date '+%s' -d $(ffmpeg -i "$audio" 2>&1 | awk '/Duration/ {print $2}' | sed s/,//))" 70 | fi 71 | 72 | prepdir="${prepdir:-$cache/$file}" 73 | outfile="${outfile:-$file.mp4}" 74 | prepfile="$prepdir/$file.prep" 75 | 76 | [ -n "${verbose+x}" ] && echo "Preparing images... May take a while depending on the number of files." 77 | mkdir -p "$prepdir" 78 | 79 | { 80 | while read -r x; 81 | do 82 | # Get the time from the first column. 83 | time="${x%% *}" 84 | seconds="$(date '+%s' -d "$time")" 85 | # Duration is not used on the first looped item. 86 | duration="$((seconds - prevseconds))" 87 | 88 | # Get the filename/text content from the rest. 89 | content="${x#* }" 90 | base="$(basename "$content")" 91 | base="${base%.*}.jpg" 92 | 93 | if [ -f "$content" ]; then 94 | # If images have already been made in a previous run, do not recreate 95 | # them unless -r was given. 96 | { [ ! -f "$prepdir/$base" ] || [ -n "${redo+x}" ] ;} && 97 | magick -size "${res:-1920x1080}" canvas:"${bgc:-black}" -gravity center "$content" -resize 1920x1080 -composite "$prepdir/$base" 98 | else 99 | { [ ! -f "$prepdir/$base" ] || [ -n "${redo+x}" ] ;} && 100 | magick -size "${res:-1920x1080}" -background "${bgc:-black}" -fill "${fgc:-white}" -font "${font:-Sans}" -pointsize "${ppt:-150}" -gravity center label:"$content" "$prepdir/$base" 101 | fi 102 | 103 | # If the first line, do not write yet. 104 | [ "$time" = "00:00:00" ] || echo "file '$prevbase' 105 | duration $duration" 106 | 107 | # Keep the information required for the next file. 108 | prevbase="$base" 109 | prevtime="$time" 110 | prevseconds="$(date '+%s' -d "$prevtime")" 111 | done < "$file" 112 | # Do last file which must be given twice as follows 113 | endtime="$((totseconds-seconds))" 114 | echo "file '$base' 115 | duration ${endtime:-5} 116 | file '$base'" 117 | } > "$prepfile" 118 | if [ -n "${audio+x}" ]; then 119 | ffmpeg -hide_banner -y -f concat -safe 0 -i "$prepfile" -i "$audio" -c:a aac -vsync vfr -c:v libx264 -pix_fmt yuv420p "$outfile" 120 | else 121 | ffmpeg -hide_banner -y -f concat -safe 0 -i "$prepfile" -vsync vfr -c:v libx264 -pix_fmt yuv420p "$outfile" 122 | fi 123 | 124 | # Might also try: 125 | # -vf "fps=${fps:-24},format=yuv420p" "$outfile" 126 | # but has given some problems. 127 | -------------------------------------------------------------------------------- /.config/mimeapps.list: -------------------------------------------------------------------------------- 1 | [Added Associations] 2 | application/epub+zip=org.pwmt.zathura.desktop; 3 | application/json=nvim.desktop;vscodium.desktop;geany.desktop;codium.desktop; 4 | application/ogg=mpv.desktop; 5 | application/pdf=libreoffice-draw.desktop;gimp.desktop;org.inkscape.Inkscape.desktop;org.pwmt.zathura.desktop; 6 | application/postscript=org.pwmt.zathura.desktop;geany.desktop; 7 | application/rss+xml=geany.desktop;newsboat-rss-add.desktop;codium.desktop; 8 | application/vnd.sqlite3=libreoffice-base.desktop; 9 | application/x-bittorrent=transmission-gtk.desktop;org.qbittorrent.qBittorrent.desktop; 10 | application/x-extension-html=linkhandler.desktop;geany.desktop; 11 | application/x-extension-htm=linkhandler.desktop; 12 | application/x-extension-shtml=linkhandler.desktop; 13 | application/x-extension-xht=linkhandler.desktop; 14 | application/x-extension-xhtml=linkhandler.desktop; 15 | application/x-extension-xhtml=linkhandler.desktop;geany.desktop; 16 | application/xhtml+xml=linkhandler.desktop;geany.desktop;linkhandler.desktop; 17 | application/xml=geany.desktop;org.kde.kdenlive.desktop; 18 | application/x-shellscript=nvim.desktop;geany.desktop;org.gnome.gedit.desktop; 19 | application/x-xdg-protocol-tg=telegramdesktop.desktop; 20 | application/x-xpinstall=org.gnome.FileRoller.desktop;firefoxdeveloperedition.desktop;firefox-developer-edition.desktop; 21 | audio/aac=mpv.desktop; 22 | audio/flac=mpv.desktop; 23 | audio/mp4=mpv.desktop;audacity.desktop; 24 | audio/mpeg=mpv.desktop;audacity.desktop; 25 | audio/x-opus+ogg=mpv.desktop;audacity.desktop; 26 | audio/x-wav=audacity.desktop;mpv.desktop; 27 | image/avif=firefox.desktop;gimp.desktop;sxiv.desktop; 28 | image/gif=sxiv.desktop;gimp.desktop;mpv.desktop; 29 | image/jpeg=gimp.desktop;nsxiv.desktop;sxiv.desktop; 30 | image/png=gimp.desktop;sxiv.desktop;nsxiv.desktop; 31 | image/svg+xml=geany.desktop;firefox.desktop;gimp.desktop;nvim.desktop; 32 | image/webp=gimp.desktop;firefox.desktop;sxiv.desktop;vwebp.desktop;nsxiv.desktop; 33 | inode/directory=lf.desktop;thunar.desktop; 34 | inode/mount-point=lf.desktop;thunar.desktop; 35 | text/css=geany.desktop;codium.desktop;nvim.desktop; 36 | text/csv=geany.desktop;codium.desktop;nvim.desktop;libreoffice-calc.desktop; 37 | text/html=firefox.desktop;geany.desktop;codium.desktop;linkhandler.desktop; 38 | text/markdown=geany.desktop;nvim.desktop; 39 | text/plain=org.gnome.gedit.desktop;geany.desktop;nvim.desktop; 40 | text/tab-separated-values=libreoffice-calc.desktop;geany.desktop; 41 | text/x-log=geany.desktop; 42 | text/x-python=nvim.desktop;geany.desktop;pycharm.desktop; 43 | text/x-shellscript=nvim.desktop; 44 | video/mp4=audacity.desktop;org.kde.kdenlive.desktop;firefox.desktop;Alacritty.desktop;mpv.desktop; 45 | video/webm=mpv.desktop; 46 | video/x-matroska=mpv.desktop;audacity.desktop; 47 | x-scheme-handler/chrome=linkhandler.desktop; 48 | x-scheme-handler/http=linkhandler.desktop; 49 | x-scheme-handler/https=linkhandler.desktop; 50 | x-scheme-handler/magnet=org.qbittorrent.qBittorrent.desktop; 51 | x-scheme-handler/mailto=neomutt.desktop;thunderbird.desktop; 52 | x-scheme-handler/tg=telegramdesktop.desktop; 53 | audio/x-ms-wma=mpv.desktop; 54 | application/zip=anki-desktop_anki-desktop.desktop;cr3.desktop;org.gnome.FileRoller.desktop;xarchiver.desktop; 55 | application/rtf=libreoffice-writer.desktop; 56 | application/msword=libreoffice-writer.desktop; 57 | application/vnd.openxmlformats-officedocument.wordprocessingml.document=libreoffice-writer.desktop; 58 | application/vnd.oasis.opendocument.text=libreoffice-writer.desktop; 59 | application/vnd.amazon.mobi8-ebook=org.pwmt.zathura.desktop; 60 | audio/vnd.wave=mpv.desktop; 61 | application/x-chrome-extension=chromium.desktop; 62 | x-scheme-handler/tonsite=org.telegram.desktop.desktop; 63 | text/x-c++src=vscodium.desktop; 64 | font/ttf=com.github.FontManager.FontViewer.desktop; 65 | application/x-desktop=org.gnome.gedit.desktop; 66 | video/quicktime=mpv.desktop; 67 | application/vnd.debian.binary-package=snap-store_snap-store.desktop; 68 | 69 | [Default Applications] 70 | inode/directory=lf.desktop; 71 | inode/mount-point=lf.desktop; 72 | x-scheme-handler/chrome=linkhandler.desktop; 73 | x-scheme-handler/http=linkhandler.desktop; 74 | x-scheme-handler/https=linkhandler.desktop; 75 | application/x-extension-htm=linkhandler.desktop; 76 | application/x-extension-html=linkhandler.desktop; 77 | application/x-extension-shtml=linkhandler.desktop; 78 | application/x-extension-xht=linkhandler.desktop; 79 | application/x-extension-xhtml=linkhandler.desktop; 80 | application/x-extension-xhtml=linkhandler.desktop; 81 | application/xhtml+xml=linkhandler.desktop; 82 | text/html=firefox.desktop 83 | application/pdf=org.pwmt.zathura.desktop 84 | image/webp=nsxiv.desktop 85 | text/x-shellscript=nvim.desktop; 86 | x-scheme-handler/magnet=org.qbittorrent.qBittorrent.desktop; 87 | application/x-bittorrent=org.qbittorrent.qBittorrent.desktop; 88 | x-scheme-handler/mailto=neomutt.desktop; 89 | text/plain=nvim.desktop; 90 | application/postscript=org.pwmt.zathura.desktop; 91 | application/pdf=org.pwmt.zathura.desktop; 92 | image/png=nsxiv.desktop 93 | image/jpeg=nsxiv.desktop 94 | image/gif=mpv.desktop; 95 | application/rss+xml=newsboat-rss-add.desktop; 96 | video/x-matroska=mpv.desktop; 97 | audio/x-ms-wma=mpv.desktop 98 | video/mp4=mpv.desktop 99 | application/zip=org.gnome.FileRoller.desktop 100 | application/x-xdg-protocol-tg=telegramdesktop.desktop 101 | x-scheme-handler/tg=telegramdesktop.desktop 102 | audio/mpeg=mpv.desktop 103 | application/json=vscodium.desktop 104 | audio/ogg=mpv.desktop 105 | audio/x-opus+ogg=mpv.desktop 106 | application/msword=libreoffice-writer.desktop 107 | application/vnd.openxmlformats-officedocument.wordprocessingml.document=libreoffice-writer.desktop 108 | application/vnd.oasis.opendocument.text=libreoffice-writer.desktop 109 | application/xml=org.kde.kdenlive.desktop 110 | audio/vnd.wave=mpv.desktop 111 | text/markdown=nvim.desktop 112 | application/x-xpinstall=firefox-developer-edition.desktop 113 | x-scheme-handler/tonsite=org.telegram.desktop.desktop 114 | font/ttf=com.github.FontManager.FontViewer.desktop 115 | application/x-shellscript=org.gnome.gedit.desktop 116 | video/quicktime=mpv.desktop 117 | -------------------------------------------------------------------------------- /.config/shell/profile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC2155 3 | 4 | # https://wiki.archlinux.org/index.php/Zsh 5 | # http://zsh.sourceforge.net/FAQ/ 6 | # The personal initialization file, executed for login shells. 7 | # It is loaded when you login. Read only once. 8 | # shellcheck disable=SC2155 9 | 10 | # ~/.profile: executed by the command interpreter for login shells. 11 | # This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login exists. 12 | # see /usr/share/doc/bash/examples/startup-files for examples. 13 | # the files are located in the bash-doc package. 14 | 15 | # Sway startup function 16 | startsway () { 17 | export GDK_BACKEND=wayland 18 | export CLUTTER_BACKEND=wayland 19 | export XKB_DEFAULT_LAYOUT=us,ru 20 | export XKB_DEFAULT_MODEL=pc104 21 | export XKB_DEFAULT_VARIANT=altgr-intl,winkeys 22 | export XKB_DEFAULT_OPTIONS=grp:win_space_toggle,terminate:ctrl_alt_bksp,caps:escape 23 | exec sway 24 | } 25 | 26 | unsetopt PROMPT_SP 2>/dev/null 27 | 28 | # Default programs: 29 | export WM="i3" 30 | export STATUSBAR="${WM}blocks" 31 | export EDITOR="nvim" 32 | export TERMINAL="alacritty" 33 | export TERMINAL_PROG=$TERMINAL 34 | export BROWSER="fingerbox" 35 | export READER="zathura" 36 | export FILE="lfub" 37 | 38 | # Change the default crypto/weather monitor sites. 39 | # export CRYPTOURL="rate.sx" 40 | # export WTTRURL="wttr.in" 41 | 42 | # ~/ Clean-up: 43 | export XDG_CONFIG_HOME="$HOME/.config" 44 | export XDG_DATA_HOME="$HOME/.local/share" 45 | export XDG_CACHE_HOME="$HOME/.cache" 46 | export XINITRC="$XDG_CONFIG_HOME/x11/xinitrc" 47 | #export XAUTHORITY="$XDG_RUNTIME_DIR/Xauthority" # This line will break some DMs. 48 | export NOTMUCH_CONFIG="$XDG_CONFIG_HOME/notmuch-config" 49 | export GTK2_RC_FILES="$XDG_CONFIG_HOME/gtk-2.0/gtkrc-2.0" 50 | export WGETRC="$XDG_CONFIG_HOME/wget/wgetrc" 51 | export INPUTRC="$XDG_CONFIG_HOME/shell/inputrc" 52 | export ZDOTDIR="$XDG_CONFIG_HOME/zsh" 53 | #export GNUPGHOME="$XDG_DATA_HOME/gnupg" 54 | export WINEPREFIX="$XDG_DATA_HOME/wineprefixes/default" 55 | export KODI_DATA="$XDG_DATA_HOME/kodi" 56 | export PASSWORD_STORE_DIR="$XDG_DATA_HOME/password-store" 57 | export TMUX_TMPDIR="$XDG_RUNTIME_DIR" 58 | export ANDROID_SDK_HOME="$XDG_CONFIG_HOME/android" 59 | export CARGO_HOME="$XDG_DATA_HOME/cargo" 60 | export GOPATH="$XDG_DATA_HOME/go" 61 | export GOMODCACHE="$XDG_CACHE_HOME/go/mod" 62 | export ANSIBLE_CONFIG="$XDG_CONFIG_HOME/ansible/ansible.cfg" 63 | export UNISON="$XDG_DATA_HOME/unison" 64 | export HISTFILE="$XDG_DATA_HOME/history" 65 | export MBSYNCRC="$XDG_CONFIG_HOME/mbsync/config" 66 | export ELECTRUMDIR="$XDG_DATA_HOME/electrum" 67 | export PYTHONSTARTUP="$XDG_CONFIG_HOME/python/pythonrc" 68 | export SQLITE_HISTORY="$XDG_DATA_HOME/sqlite_history" 69 | 70 | # Other program settings: 71 | export GEM_HOME="$(ruby -e 'puts Gem.user_dir' 2>/dev/null)" 72 | export LANG="en_US.UTF-8" 73 | export TERM="xterm-256color" 74 | #export LESS="R" 75 | export LESS='-F -i -J -M -R -W -x4 -X -z-4' # https://www.topbug.net/blog/2016/09/27/make-gnu-less-more-powerful/ 76 | export DICS="/usr/share/stardict/dic/" 77 | export SUDO_ASKPASS="$HOME/.local/bin/dmenupass" 78 | export FZF_DEFAULT_OPTS="--layout=reverse --height 40%" 79 | export LESS_TERMCAP_mb="$(printf '%b' '')" 80 | export LESS_TERMCAP_md="$(printf '%b' '')" 81 | export LESS_TERMCAP_me="$(printf '%b' '')" 82 | export LESS_TERMCAP_so="$(printf '%b' '')" 83 | export LESS_TERMCAP_se="$(printf '%b' '')" 84 | export LESS_TERMCAP_us="$(printf '%b' '')" 85 | export LESS_TERMCAP_ue="$(printf '%b' '')" 86 | export LESSOPEN="| /usr/bin/highlight -O ansi %s 2>/dev/null" 87 | export MOZ_USE_XINPUT2=1 # Mozilla smooth scrolling/touchpads. 88 | export AWT_TOOLKIT="MToolkit wmname LG3D" # May have to install wmname 89 | export _JAVA_AWT_WM_NONREPARENTING=1 # Fix for Java applications in dwm 90 | export TDESKTOP_USE_GTK_FILE_DIALOG=1 91 | 92 | # TSP settings 93 | # https://aur.archlinux.org/packages/task-spooler/ 94 | export TS_SLOTS=10 # the maximum number of jobs running at once with task-spooler. 95 | export TS_ONFINISH=tsp_onfinish # run by the client after the queued job. 96 | 97 | # Compiler 98 | export CC=gcc 99 | export CXX=g++ 100 | 101 | # Speed up compile times 102 | # https://wiki.archlinux.org/index.php/Makepkg#Creating_optimized_packages 103 | MAKEFLAGS="-j$(($(nproc) + 1)) -l$(nproc)"; export MAKEFLAGS 104 | export CFLAGS="-Wall -Wextra -Wpedantic -Wconversion -Wshadow -march=native -O2 -pipe -fstack-protector-strong -fno-plt" 105 | export CXXFLAGS="$CFLAGS" 106 | 107 | # Fix QT themes on GTK Desktops 108 | # https://tatsumoto.neocities.org/blog/setting-up-anki.html#gtk-theme 109 | export QT_QPA_PLATFORMTHEME=qt6ct 110 | 111 | # Fix QT plugin path for pyqt packages installed with pip. 112 | # Note: disabled 113 | # export QT_PLUGIN_PATH=/usr/lib/qt6/plugins:$(find ~/.local/lib/ -type d -wholename '*/python3*/site-packages/PyQt*/plugins' | paste -s -d :) 114 | 115 | # Fix Java programs 116 | # https://wiki.archlinux.org/index.php/Java_Runtime_Environment_fonts 117 | export _JAVA_OPTIONS='-Dawt.useSystemAAFontSettings=gasp' 118 | 119 | if [[ ! -f "$XDG_CONFIG_HOME/shell/shortcutrc" ]]; then 120 | setsid -f shortcuts >/dev/null 2>&1 121 | fi 122 | 123 | # Add all directories in `~/.local/bin` to $PATH 124 | if [[ -d "$HOME/.local/bin/" ]]; then 125 | PATH="$PATH:$(find ~/.local/bin -type d | paste -sd ':' -)" 126 | fi 127 | if [[ -n $GEM_HOME ]] && [[ -d "$GEM_HOME/bin" ]]; then 128 | PATH="$PATH:$GEM_HOME/bin" 129 | fi 130 | if [[ -d "$HOME/.local/share/cargo/bin" ]]; then 131 | PATH="$PATH:$HOME/.local/share/cargo/bin" 132 | fi 133 | if [[ -d /usr/lib/qt6/bin ]]; then 134 | PATH="/usr/lib/qt6/bin:$PATH" 135 | fi 136 | export PATH 137 | 138 | # Start graphical server on tty1 if not already running. 139 | # https://wiki.archlinux.org/index.php/Xinit#Autostart_X_at_login 140 | if [[ -z "${DISPLAY}" ]] && [[ "${XDG_VTNR}" -eq 1 ]]; then 141 | exec startx "$XINITRC" 142 | fi 143 | 144 | if [[ "$(tty)" == "/dev/tty2" ]]; then 145 | exec startsway 146 | fi 147 | 148 | # Switch escape and caps if tty and no passwd required: 149 | sudo -n loadkeys "$XDG_DATA_HOME/larbs/ttymaps.kmap" 2>/dev/null 150 | -------------------------------------------------------------------------------- /.local/bin/local-pronunciations: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import dataclasses 4 | import json 5 | import os 6 | import pickle 7 | import re 8 | import subprocess 9 | import sys 10 | import urllib.request 11 | from typing import AnyStr, NewType 12 | 13 | PROGRAM = 'local-pronunciations' 14 | CACHE_DIR = os.path.join(os.environ['XDG_CACHE_HOME'], PROGRAM) 15 | CONFIG_PATH = os.path.join(os.environ['XDG_CONFIG_HOME'], PROGRAM, 'config.json') 16 | MatchDict = NewType('MatchDict', dict[str, set[str]]) 17 | 18 | 19 | def request(action, **params): 20 | return {'action': action, 'params': params, 'version': 6} 21 | 22 | 23 | def invoke(action, **params): 24 | request_json = json.dumps(request(action, **params)).encode('utf-8') 25 | response = json.load(urllib.request.urlopen(urllib.request.Request('http://127.0.0.1:8765', request_json))) 26 | if len(response) != 2: 27 | raise Exception('response has an unexpected number of fields') 28 | if 'error' not in response: 29 | raise Exception('response is missing required error field') 30 | if 'result' not in response: 31 | raise Exception('response is missing required result field') 32 | if response['error'] is not None: 33 | raise Exception(response['error']) 34 | return response['result'] 35 | 36 | 37 | def store_file(path: AnyStr, stored_name: AnyStr): 38 | invoke('storeMediaFile', filename=stored_name, path=path) 39 | 40 | 41 | def get_pickle_path(source_name: str) -> str: 42 | return os.path.join(CACHE_DIR, source_name) 43 | 44 | 45 | def construct_filename(audio_file_name: str, audio_source_name: str) -> str: 46 | name, ext = os.path.splitext(audio_file_name) 47 | return f'{name}.{audio_source_name}{ext}' 48 | 49 | 50 | def notify_send(title: str, msg: str): 51 | subprocess.Popen( 52 | ['notify-send', title, msg], 53 | shell=False 54 | ) 55 | 56 | 57 | def to_clip(text: str): 58 | subprocess.run( 59 | "xclip -sel c", 60 | shell=True, 61 | universal_newlines=True, 62 | input=text 63 | ) 64 | 65 | 66 | @dataclasses.dataclass(frozen=True) 67 | class AudioSource: 68 | name: str 69 | audio_dir_path: str 70 | pickle_path: str 71 | 72 | 73 | @dataclasses.dataclass() 74 | class Config: 75 | audio_sources: dataclasses.InitVar[dict[str, str]] = dataclasses.field(kw_only=True) 76 | stop_after_first_match: bool = dataclasses.field(kw_only=True) 77 | 78 | def __post_init__(self, audio_sources: dict[str, str]): 79 | self.audio_sources: list[AudioSource] = [ 80 | AudioSource( 81 | source_name, 82 | source_path, 83 | get_pickle_path(source_name), 84 | ) 85 | for source_name, source_path in audio_sources.items() 86 | ] 87 | 88 | 89 | def read_config() -> Config: 90 | if not os.path.isdir(d := os.path.dirname(CONFIG_PATH)): 91 | os.mkdir(d) 92 | 93 | default_config = { 94 | "audio_sources": { 95 | 'audio_1': '/path/to/directory', 96 | 'audio_2': '/path/to/directory', 97 | }, 98 | "stop_after_first_match": False, 99 | } 100 | 101 | if not os.path.isfile(CONFIG_PATH): 102 | with open(CONFIG_PATH, 'w', encoding='utf8') as of: 103 | json.dump(default_config, of, indent=4, ensure_ascii=False) 104 | print(f"Created config file: {CONFIG_PATH}") 105 | print("Edit the file and include your directories with audio.") 106 | 107 | with open(CONFIG_PATH, encoding='utf8') as f: 108 | return Config(**(default_config | json.load(f))) 109 | 110 | 111 | def possible_matches(audio_file_name: str): 112 | # expected format: {kanji}_{reading}.{reserved}.{extension} 113 | name = audio_file_name.split('.')[0] 114 | return re.split(r'[。、・._\b]', name, re.IGNORECASE) 115 | 116 | 117 | def construct_match_dict(audio_dir_path: str) -> MatchDict: 118 | result = {} 119 | for path in os.scandir(audio_dir_path): 120 | path: os.DirEntry 121 | for substr in possible_matches(path.name): 122 | result.setdefault(substr, set()).add(path.path) 123 | return MatchDict(result) 124 | 125 | 126 | def ensure_cache_exists(config: Config): 127 | if not os.path.isdir(CACHE_DIR): 128 | os.mkdir(CACHE_DIR) 129 | for source in config.audio_sources: 130 | if not os.path.isfile(source.pickle_path) and os.path.isdir(source.audio_dir_path): 131 | with open(source.pickle_path, 'wb') as f: 132 | pickle.dump(construct_match_dict(source.audio_dir_path), f, pickle.HIGHEST_PROTOCOL) 133 | 134 | 135 | def get_pickle_content(source_name: str) -> MatchDict: 136 | with open(get_pickle_path(source_name), 'rb') as f: 137 | return MatchDict(pickle.load(f)) 138 | 139 | 140 | def main(search_term: str) -> int: 141 | if not search_term: 142 | print(f"Usage: {os.path.basename(__file__)} SEARCH_TERM") 143 | return 0 144 | 145 | config = read_config() 146 | ensure_cache_exists(config) 147 | added_filenames = [] 148 | 149 | for source in config.audio_sources: 150 | if not os.path.isfile(source.pickle_path): 151 | continue 152 | match_dict = get_pickle_content(source.name) 153 | if search_term in match_dict: 154 | for file_path in match_dict[search_term]: 155 | new_name = construct_filename(os.path.basename(file_path), source.name) 156 | store_file(path=file_path, stored_name=new_name) 157 | added_filenames.append(new_name) 158 | if added_filenames and config.stop_after_first_match: 159 | break 160 | 161 | if added_filenames: 162 | to_clip(''.join(f'[sound:{f}]' for f in added_filenames)) 163 | notify_send( 164 | "Added local pronunciations.", 165 | "File(s) added to Anki collection. Codes are copied to the clipboard.\n\n" + '\n'.join(added_filenames) 166 | ) 167 | else: 168 | notify_send( 169 | "No local pronunciations", 170 | f"Couldn't find anything matching {search_term}." 171 | ) 172 | 173 | return int(not added_filenames) 174 | 175 | 176 | if __name__ == '__main__': 177 | sys.exit(main(search_term=''.join(sys.argv[1:]))) 178 | --------------------------------------------------------------------------------