Compare commits

..

No commits in common. "main" and "89-implement-autocompilation-of-files-with-file-watching" have entirely different histories.

436 changed files with 47650 additions and 31880 deletions

View file

@ -0,0 +1 @@
^/.* # everything

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 KiB

BIN
.assets/gapless.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 KiB

BIN
.assets/gaps.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

View file

@ -1,111 +0,0 @@
[helpers]
# BASE: A base system. Sets up a nice xdg (zsh) shell environment, utility scripts and
# a development environment based on git and nvim.
[base]
depends = ["shell", "vcs", "nvim", "scripts", "ssh", "terminal", "bootstrap"]
[bootstrap.files]
"bootstrap/dotlink.sh" = "~/.config/sh/alias.d/dotlink.sh"
[shell.files]
"sh/README.md" = { target = "~/NOWHERE", type = "symbolic", if = "false" }
sh = "~"
[vcs.files]
"vcs/README.md" = { target = "~/NOWHERE", type = "symbolic", if = "false" }
"vcs/git/config" = "~/.config"
"vcs/jj/config" = "~/.config"
"vcs/gitignore/config" = "~/.config"
"vcs/gitignore/local" = "~/.local"
vcs = "~"
[nvim.files]
"nvim/.config/nvim/spell/de.utf-8.add.spl" = { target = "~/.config/nvim/spell/de.utf-8.add.spl", type = "symbolic" }
"nvim/.config/nvim/spell/en.utf-8.add.spl" = { target = "~/.config/nvim/spell/en.utf-8.add.spl", type = "symbolic" }
nvim = "~"
[scripts.files]
"scripts/README.md" = { target = "~/NOWHERE", type = "symbolic", if = "false" }
scripts = "~"
[ssh.files]
ssh = "~"
[terminal.files]
"terminal/.config/vifm" = "~/.config/vifm"
"terminal/.config/vifm/vifmrc" = { target = "~/.config/vifm/vifmrc", type = "symbolic" }
terminal = "~"
# LINUX: A linux machine, with systemd enabled, auto-mounting set up and a nice productivity suite.
[linux]
depends = ["base", "disks", "pass", "office", "services", "social", "writing"]
[disks.files]
"disks/README.md" = { target = "~/NOWHERE", type = "symbolic", if = "false" }
disks = "~"
[pass.files]
"pass/README.md" = { target = "~/NOWHERE", type = "symbolic", if = "false" }
"pass/.local/share/pass-pick/assets/rofi-menu.gif" = { target = "~/NOWHERE", type = "symbolic", if = "false" }
pass = "~"
[office.files]
"office/README.md" = { target = "~/NOWHERE", type = "symbolic", if = "false" }
"office/.config/glow/email.json" = { target = "~/.config/glow/email.json", type = "symbolic" }
"office/.config/isync/mbsyncrc" = { target = "~/.config/isync/mbsyncrc", type = "template" }
"office/.config/msmtp/config" = { target = "~/.config/msmtp/config", type = "template" }
"office/.config/neomutt/account" = { target = "~/.config/neomutt/account", type = "template" }
"office/.config/neomutt/profile.gmail" = { target = "~/.config/neomutt/profile.gmail", type = "template" }
"office/.config/neomutt/profile.private" = { target = "~/.config/neomutt/profile.private", type = "template" }
office = "~"
[services.files]
"services/README.md" = { target = "~/NOWHERE", type = "symbolic", if = "false" }
services = "~"
[social.files]
social = "~"
[writing.files]
"writing/README.md" = { target = "~/NOWHERE", type = "symbolic", if = "false" }
"writing/jrnl/config" = "~/.config"
"writing/papis/config/papis/papistui.yaml" = { target = "~/.config/papis/papistui.yaml", type = "symbolic" }
"writing/papis/config" = "~/.config"
"writing/sioyek/config/sioyek/prefs_user.config" = { target = "~/.config/sioyek/prefs_user.config", type = "template", prepend = "# TEMPLATED BY DOTTER\n" }
"writing/sioyek/config" = "~/.config"
"writing/zathura/config" = "~/.config"
"writing/zk/config" = "~/.config"
"writing/pandoc/local" = "~/.local"
writing = "~"
# WORKSTATION: A desktop machine, with wayland environment and display attached.
[workstation]
depends = ["linux", "desktop", "multimedia", "qutebrowser"]
[desktop.files]
"desktop/.config/flavours/templates" = { target = "~/.config/flavours/templates", type = "symbolic" }
"desktop/.config/waybar/config" = { target = "~/.config/waybar/config", type = "symbolic" }
"desktop/.config/mako/config" = { target = "~/.config/mako/config", type = "template", prepend = "# TEMPLATED BY DOTTER\n" }
"desktop/README.md" = { target = "~/NOWHERE", type = "symbolic", if = "false" }
desktop = "~"
[multimedia.files]
"multimedia/README.md" = { target = "~/NOWHERE", type = "symbolic", if = "false" }
"multimedia/.config/mpv/scripts" = { target = "~/.config/mpv/scripts", type = "symbolic" }
"multimedia/.config/ncmpcpp/config" = { target = "~/.config/ncmpcpp/config", type = "symbolic" }
"multimedia/.config/mpv/fonts/uosc_icons.otf" = { target = "~/.config/mpv/fonts/uosc_icons.otf", type = "symbolic" }
"multimedia/.config/mpv/fonts/uosc_textures.ttf" = { target = "~/.config/mpv/fonts/uosc_textures.ttf", type = "symbolic" }
"multimedia/.config/vimiv/styles/base16" = { target = "~/.config/vimiv/styles/base16", type = "template" }
multimedia = "~"
[qutebrowser.files]
"qutebrowser/config" = "~/.config/qutebrowser"
"qutebrowser/scripts" = "~/.local/bin"
"qutebrowser/data" = "~/.local/share/qutebrowser"
[system.files]
"bootstrap/system-packages" = { target = "/", type = "symbolic", owner = "root" }

View file

@ -1,13 +0,0 @@
includes = []
packages = ["workstation"]
[files]
[variables]
multimedia_beets_musicbrainz_user = ""
multimedia_beets_musicbrainz_pass = ""
multimedia_mopidy_subidy_url = ""
multimedia_mopidy_subidy_user = ""
multimedia_mopidy_subidy_pass = ""

View file

@ -1,5 +0,0 @@
packages = ["system", "workstation"]
[files]
[variables]

View file

@ -0,0 +1 @@
^/.* # everything

View file

@ -1,27 +1,59 @@
#!/usr/bin/env bash #!/usr/bin/env sh
COMMIT_MSG_FILE="$1" COMMIT_MSG_FILE="$1"
COMMIT_SOURCE="$2" COMMIT_SOURCE="$2"
BOOTSTRAPDIR="bootstrap" BOOTSTRAPDIR="bootstrap"
pkg_committed="$(cat "$(git rev-parse --show-toplevel)"/$BOOTSTRAPDIR/packages*.tsv | grep -v -e '^Name Description Source Target' | cut -f1 | sort)" pkgfileloc="$(git rev-parse --show-toplevel)/$BOOTSTRAPDIR/packages.txt"
pkg_onsystem=$(pacman -Qqett | sort) pkgignoreloc="$(git rev-parse --show-toplevel)/$BOOTSTRAPDIR/packages_ignore.txt"
listgen="yay"
# get files only in repo, and only on machine err() {
only_committed=$(comm -23 <(echo "$pkg_committed") <(echo "$pkg_onsystem")) printf "\x1b[33mCAUTION:\x1b[0m %s\n" "$*"
only_onsystem=$(comm -13 <(echo "$pkg_committed") <(echo "$pkg_onsystem")) exit 1
}
if [ ! -f "$pkgfileloc" ]; then
err "File not found - $pkgfileloc, can not determine package differences!"
fi
if ! type "$listgen" >/dev/null 2>&1; then
err "Yay not installed on machine, can not reliably determine package differences!"
fi
# get commited packages, remove empty lines
# and lines beginning with # to allow comments
pkgcommited=$(mktemp)
sed -e '/^[#$]/d' <"$pkgfileloc" | sort >"$pkgcommited"
# get packages on this machine
# q removes extraneous info
# e only lists explicitly installed
# tt removes those that are depended on, but NOT those optionally depended on
pkgcurrent=$(yay -Qqett | sort)
# remove those listed in package_ignore.txt
if [ -f "$pkgignoreloc" ]; then
pkgcurrent=$(echo "$pkgcurrent" | comm -23 - "$pkgignoreloc")
fi
# compare the lists, list differences
result=$(echo "$pkgcurrent" | comm -3 - "$pkgcommited")
# get files only in repo (field1), and only on machine (field2)
added=$(echo "$result" | cut -f1 | sed -e '/^$/d')
removed=$(echo "$result" | cut -s -f2)
# if we have no changes, do nothing # if we have no changes, do nothing
if [ -n "$only_onsystem" ] || [ -n "$only_committed" ]; then if [ -n "$added" ] || [ -n "$removed" ]; then
text=$(printf "\-- PACKAGE CHANGES --\nPackages on machine but not committed:\n%s\n\nPackages committed but not on machine:\n%s\n" "$only_onsystem" "$only_committed" | sed 's/^/# /gm') text=$(printf "\-- PACKAGE DIFFERENCES TO COMMITED LIST FOUND --\nPackages NOT YET in repo:\n%s\n\nPackages ONLY in repo:%s\n" "$added" "$removed" | sed 's/^/# /gm')
else else
exit 0 exit 0
fi fi
# prepend package changes to message # prepend package changes to message
case $COMMIT_SOURCE in case $COMMIT_SOURCE in
"" | message, | template,) "" | message, | template,)
msg=$(echo "$text" | cat - "$COMMIT_MSG_FILE") msg=$(echo "$text" | cat - "$COMMIT_MSG_FILE")
printf "%s" "$msg" >"$COMMIT_MSG_FILE" printf "%s" "$msg" >"$COMMIT_MSG_FILE"
;; ;;
esac esac

36
.gitignore vendored
View file

@ -1,7 +1,3 @@
# don't move the cache into repo
/.dotter/cache/
/.dotter/cache.toml
# no idea why gopass adds this image to config path # no idea why gopass adds this image to config path
gopass-logo-small.png gopass-logo-small.png
# #
@ -15,35 +11,3 @@ colorscheme.rasi
# do not add massive gutenberg thesaurus to repo # do not add massive gutenberg thesaurus to repo
nvim/.config/nvim/thesaurus nvim/.config/nvim/thesaurus
# if we have a pre-compiled plugin list don't add it
nvim/.config/nvim/plugin/packer_compiled.lua
# mpv sponsorblock api
sponsorblock.db
sponsorblock.db.tmp
sponsorblock.txt
# ignore any just-in-time settings that took place in qutebrowser
/qutebrowser/.config/qutebrowser/autoconfig.yml
/qutebrowser/.config/qutebrowser/bookmarks
/qutebrowser/.config/qutebrowser/qsettings
/qutebrowser/.config/qutebrowser/quickmarks
/qutebrowser/.config/qutebrowser/stylesheets
# ignore the generated readability file for webpages
readability.html
# ignore the adblock file generated by qutebrowser
blocked-hosts
# ignore vifm & ueberzug utility files
vifm-help.txt
vifmimgpdfpage
vifmimgpdffile
vifminfo
vifminfo.json
# styler configs
colorscheme.yml
# taskwarrior
office/.config/task/task-sync.rc
office/.config/task/contexts

37
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,37 @@
---
# install moreutils to enable ifne (if not empty)
# will only run the respective analyzers when files to test
# are acutally found
image: fnichol/check-shell:latest
analyze:
stage: test
before_script:
- apk add moreutils
- shellcheck --version
script:
- echo "--------- CHECKING POSIX SHELLSCRIPTS -------------"
- find . -type f -name '*.sh' | ifne xargs shellcheck -Calways
- echo "--------- CHECKING ZSH SHELLSCRIPTS -------------"
- find . -type f -name '*.zsh' | ifne xargs shellcheck -Calways -s bash -e SC2034
lint:
stage: test
before_script:
- apk add moreutils
- shfmt -version
script:
- echo "--------- CHECKING POSIX SHELLSCRIPTS -------------"
- find . -type f -name '*.sh' | ifne xargs shfmt -d -i 2
- echo "--------- CHECKING ZSH SHELLSCRIPTS -------------"
- find . -type f -name '*.zsh' | ifne xargs shfmt -d -i 2
test:
stage: test
image: alpine
before_script:
- apk add git bash
- git clone https://github.com/bats-core/bats-core.git /bats
- /bats/bin/bats --version
script:
- /bats/bin/bats -r .

9
.gitmodules vendored
View file

@ -1,9 +0,0 @@
[submodule "pass/.local/share/pass-pick"]
path = pass/.local/share/pass-pick
url = https://git.martyoeh.me/Marty/pass-pick.git
[submodule "scripts/.local/share/uoeia"]
path = scripts/.local/share/uoeia
url = https://git.martyoeh.me/Marty/uoeia.git
[submodule "multimedia/.local/share/vimiv/plugins/batchmark"]
path = multimedia/.local/share/vimiv/plugins/batchmark
url = https://github.com/jcjgraf/BatchMark

4
.stowrc Normal file
View file

@ -0,0 +1,4 @@
--target=~
--ignore='^.gitlab-ci.yml$'
--ignore='^.stowrc$'
--ignore='^.githooks$'

View file

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2023 Marty Oehme Copyright (c) 2019 Marty Oehme
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -1,43 +1,34 @@
# `~/🌹` # dotfiles Read-Me and Roadmap
Note that the below screenshots still show the X configuration from [v0.1](https://gitlab.com/marty-oehme/dotfiles/-/tags/v0.1) which is *very* old by now.
The current dotfiles are geared toward wayland for which the setup looks similar but not identical to the previews below.
## What's in these dotfiles ## What's in these dotfiles
* [x] wayland setup using `riverwm` with quick access to many overlays and picking tools for styles, downloads, browsing history, passwords and more * [x] vim configuration for simple programming tasks (especially go/typescript/python/bash) and prose
* [x] vim configuration for simple programming tasks (especially python/bash/lua) and prose (markdown/quarto/latex)
* [x] academic workflow tools, to allow quick citation, pdf compilation, and preview * [x] academic workflow tools, to allow quick citation, pdf compilation, and preview
* [x] simple, efficient waybar with package update notification and mpris integration * [x] simple, efficient polybar with package update notification, and spotify (mpris) integration
* [x] system-wide color management (terminals, vim, qutebrowser, polybar, xresources) through [`flavours`](https://github.com/Misterio77/flavours) application using [base16](http://chriskempson.com/projects/base16/) themes * [x] tmux session management through `tm` and `tl` tools
* [x] quick theme switching by activating `flavours` and fuzzy-searching themes with hot-key (default `<Super>=<Shift>+S`) * [x] tmux fuzzy-searching of terminal sessions to switch to with hot-key (`<C-A><C-j>`)
* [x] quick directory jumping using `z`, with `fzf` integration * [x] system-wide color management (terminals, vim, qutebrowser, polybar, xresources) through `styler` command using [base16](http://chriskempson.com/projects/base16/) themes
* [x] `fzf`-like integrations for bibtex citation, vim buffer management, most recently used switching, shell command history, and more * [x] quick theme switching by activating `styler` and fuzzy-searching themes with hot-key (`<Super>+F8`)
* [x] password management with `pass` and picking it with automatic typing into any window * [x] many vim color-schemes with quick light/dark switching (`F8`) and individual theme switch (`<Space>+F8`)
* [x] quick directory jumping using z, with fzf integration
* [x] fzf integrations for bibtex citation, vim buffer management, most recently used switching, shell command history, and more
[![Styler recoloring demo](https://gitlab.com/marty-oehme/dotfiles/-/wikis/uploads/bde87deda694590a2e08e21552e11309/styler.webp)](https://gitlab.com/marty-oehme/dotfiles/-/wikis/uploads/90894e53eff378db4d7f9f49e7a69fab/styler.mp4) ![Overview](.assets/gaps.png)
## Quick-Start ## Quick-Start
The dotfiles use `dotter` to link themselves in the home directory. You can clone this repository anywhere (though I have mine in `~/.dotfiles` as it seemed most logical for me). The dotfiles use `GNU stow` to link themselves in the home directory. You can clone this repository anywhere (though I have mine in `~/.dotfiles` as it seemed most logical for me).
I would recommend doing an initial `git clone --recursive` for this repository, since it contains git [submodules](https://nering.dev/2016/git-submodules-vs-subtrees/), which will then automatically get pulled in as well.
Of course, you can do it non-recursively and then just pull those modules selectively which you actually want.
Once in the repository directory, when you then run `./install.sh` it will install many of the packages I use (though they are probably slightly out-of-date) and link the dotfiles into the home directory. Once in the repository directory, when you then run `./install.sh` it will install many of the packages I use (though they are probably slightly out-of-date) and link the dotfiles into the home directory.
I would mostly recommend this on fresh machines or a test machine first - it *will* link my personal dotfiles and, if you allow it, *will* install quite a few packages. Since it is based on `stow`, it will not overwrite anything already in the home directory (though you can force it to if you really want, using `stow --override='.*'` -- I do not recommend this).
By default it will ask your consent for some steps -- use `./install.sh -f` to force yes to everything.
The dotfile installation procedure is based on `dotter`, it will generally *not overwrite* anything already in the home directory, but of course be observant when doing ptentially destructive operations. If you do not want to install any packages, but only link the dotfiles run `stow -S */` from the main repository directory.
> **NOTE**
> The same non-destructive installation procedure does *not* apply to the package installation and system setting file linking, where it can potentially overwrite or remove existing files.
After all files are linked and you open a new shell session, the `dotlink` alias will allow you to re-link all dotfiles from anywhere on the system.[^1] After all files are linked and you open a new shell session, the `dotlink` alias will allow you to re-link all dotfiles from anywhere on the system.[^1]
[^1]: This alias only works when the dotfiles are cloned into `~/.dotfiles`, mirroring my setup. [^1]: This alias only works when the dotfiles are cloned into `~/.dotfiles` mirroring my setup.
This is due to a hard-coded cd into this directory. This is due to a hard-coded cd into this directory.
If your dotfiles lie in another directory and you want to use the dotlink alias, simply change the corresponding line in `bootstrap/.config/sh/alias.d/dotlink.sh` If your dotfiles lie in another directory and you want to use the dotlink alias, simply change the corresponding line in `_bootstrap/.config/sh/alias.d/dotlink.sh`]
Both automatic installation paths are presumably somewhat brittle. In any case, I would suggest to manually look through the files for things you want instead of copying and activating everything. Both automatic installation paths are presumably somewhat brittle. In any case, I would suggest to manually look through the files for things you want instead of copying and activating everything.
Dotfiles are too personal to be standardized like that. Dotfiles are too personal to be standardized like that.
@ -46,33 +37,32 @@ Enjoy!
## Main Modules ## Main Modules
![Overview - an older image of the dotfile desktop with gaps, showing git logs, styler logs, duckduckgo in a browser, and a vifm view of the dotfiles themselves](https://gitlab.com/marty-oehme/dotfiles/-/wikis/uploads/aaf0319d575dc192ea0f4bd6eaf83c08/gaps.png) * [`alacritty`](https://github.com/jwilm/alacritty) - Terminal emulator (GPU accelerated and customizable)
* [`wayland`](https://github.com/wayland-project/wayland) - Containing basics for fully functional tiling wayland setup:
* [`river`](https://github.com/riverwm/river) - Tiling window manager for wayland
* [`waybar`](https://github.com/Alexays/Waybar) - Easily customizable statusbar for wayland
* [`bemenu`](https://github.com/Cloudef/bemenu) - Extended dmenu replacement for wayland, X11 and ncurses
* [`fontconfig`] - System-wide font replacements and styling settings
* [`wezterm`](https://wezfurlong.org/wezterm/) - Terminal emulator (fast, understandable and lua configurable)
* [`tmux`](https://github.com/tmux/tmux/) - terminal multiplexer (slowly migrating away in favor of wezterm)
* [`nvim`](https://neovim.io/) - Neovim configuration
* [`vifm`](https://github.com/vifm/vifm) - vim-like file-manager
* [`qutebrowser`](https://github.com/qutebrowser/qutebrowser) - vim-key enabled web browser
* [`pass`](pass/README.md) - Password management suite
* [`bibtex`] - LateX/BibteX/pandoc plaintext writing & reference suite
* [`git`](git/README.md) - distributed version control system. * [`git`](git/README.md) - distributed version control system.
* [`office`](office/README.md) - office/productivity software for writing e-mail and setting appointments * [`gopass`](https://github.com/gopasspw/gopass) - Password management suite, building on (and largely compatible with)
`pass` for unix
* [`i3`](https://i3wm.org/) - Tiling window manager
* [`nvim`](https://neovim.io/) - Neovim configuration
* [`pandoc`](https://pandoc.org) - Pandoc plaintext transformation options (mostly latex templates)
* [`picom`](https://github.com/yshui/picom) - X11 compositor (maintained fork from compton)
* [`polybar`](https://github.com/polybar/polybar) - Easy to customize statusbar
* [`qutebrowser`](https://github.com/qutebrowser/qutebrowser) - vim-key enabled web browser
* [`rofi`](https://github.com/davatorium/rofi) - Application launcher, dmenu replacement
* [`sxhkd`](https://github.com/baskerville/sxhkd) - X11 hotkey manager
* [`tmux`](https://github.com/tmux/tmux/) - terminal multiplexer
* [`vifm`](https://github.com/vifm/vifm) - vim-like file-manager
## Notes ## Notes
* Generally, most configuration for applications attempts to follow the XDG specifications, keeping configuration in .config directory and supplementary files in .local/share directory. Over time, I am moving more applications to this standard: it keeps the home directory clean, and the separation of configuration, binaries, and data relatively clear. * Generally, most configuration for applications attempts to follow the XDG specifications, keeping configuration in .config directory and supplementary files in .local/share directory. Over time, I am moving more applications to this standard: it keeps the home directory clean, and the separation of configuration, binaries, and data relatively clear.
* `.config/shell` contains all the general zsh/bash/sh configuration and environment variables usually contained in `.zshrc`, `.zprofile` and similar. It is divided in login shell config (loginrc.d), general shell config (rc.d) and zsh specific (zsh.d). Over time this should be migrated to specific `stow` 'units', but for now here is where it is.
* The `zsh` directory contains all setup for the z-shell, my daily work environment. It should not be required for working with any other module but will add additional functionality to many (such as command auto-completion and so on). `sh` sets some base functionality for any shell you may wish to work in. It is, for now, the only module that is required for some other modules to work.[^shreq] * The `zsh` directory contains all setup for the z-shell, my daily work environment. It should not be required for working with any other module but will add additional functionality to many (such as command auto-completion and so on). `sh` sets some base functionality for any shell you may wish to work in. It is, for now, the only module that is required for some other modules to work.[^shreq]
* `rofi` contains additional scripts and a simple theming framework for rofi and should probably be reorganized to put the correct files into the correct directories (per xdg) at some point. * `rofi` contains additional scripts and a simple theming framework for rofi and should probably be reorganized to put the correct files into the correct directories (per xdg) at some point.
* Whereas `sh` module scripts are requirements for other scripts, `.local/bin` in the `scripts` module contains most executable user scripts. Most of these have been migrated to other corresponding modules (e.g. if a script exclusively targets git functionality, it will live there), some useful --- or left-over --- stand-alone scripts remain however. * `.local/bin` in `scripts` `stow` unit contains most executable user scripts. Most of these have been migrated to their corresponding modules (e.g. if a script exclusively targets git functionality, it will live there), some stand-alone scripts remain however.
* `.local/share/pandoc` contains configuration for academic latex writing (pandoc, really) and is of interest if you want to use this functionality. * `.local/share/pandoc` contains configuration for academic latex (pandoc, really) writing and is of interest if you want to use this functionality.
* `.xinitrc` is used for x initialization and program startup. At some point, some of the consistently running applications may be moved to systemd/runit as supervised services. * `.xinitrc` is used for x initialization and program startup.
* Generally, top-level directories starting with a . are only meaningful for the *repository* not for the functionality of the machine that these dotfiles are deployed on. That means `.gitlab-ci.yml`, `.assets/`, `.gitignore` and similar files and directories will not show up in the final deployment in any home directory. Perhaps they should be called dotdot-files since they're the dotfiles for my dotfiles. 🙂 (Also, '[dotfiles](https://en.wikipedia.org/wiki/Semantic_satiation)'.) * Generally, directories starting with a . are only meaningful for the *repository* not for the functionality of the machine that these dotfiles are deployed on. That means `.gitlab-ci.yml`, `.assets/`, `.stowrc` and similar files and directories will not show up in the final deployment in any home directory. Perhaps they should be called dotdot-files since they're the dotfiles for my dotfiles. 🙂 (Also, 'dotfiles'.)
[^shreq]: I may remove this requirement in the future to make modules more self-contained. However, relying on some base utility scripts makes it easier to avoid duplicating such functionality for each individual script in other modules. [^shreq]: I may remove this requirement in the future to make modules more self-contained. However, relying on some base utility scripts makes it easier to avoid duplicating such functionality for each individual script in other modules.
![Gapless - the same image as above, only displayed without gaps](https://gitlab.com/marty-oehme/dotfiles/-/wikis/uploads/21791f77da013cdac64f11eff61584e3/gapless.png) ![Gapless](.assets/gapless.png)

View file

@ -0,0 +1,572 @@
# Base16 OneDarkCustom - alacritty color config
# Colors (One Dark)
onedark: &colorscheme
# Default colors
primary:
background: '0x1e2127'
foreground: '0xabb2bf'
# Normal colors
normal:
black: '0x1e2127'
red: '0xe06c75'
green: '0x98c379'
yellow: '0xd19a66'
blue: '0x61afef'
magenta: '0xc678dd'
cyan: '0x56b6c2'
white: '0xabb2bf'
# Bright colors
bright:
black: '0x5c6370'
red: '0xe06c75'
green: '0x98c379'
yellow: '0xd19a66'
blue: '0x61afef'
magenta: '0xc678dd'
cyan: '0x56b6c2'
white: '0xffffff'
draw_bold_text_with_bright_colors: false
# Base16End ashes - alacritty color config
# Configuration for Alacritty, the GPU enhanced terminal emulator.
# Any items in the `env` entry below will be added as
# environment variables. Some entries may override variables
# set by alacritty itself.
#env:
# TERM variable
#
# This value is used to set the `$TERM` environment variable for
# each instance of Alacritty. If it is not present, alacritty will
# check the local terminfo database and use `alacritty` if it is
# available, otherwise `xterm-256color` is used.
#TERM: xterm-256color
window:
# Window dimensions (changes require restart)
#
# Specified in number of columns/lines, not pixels.
# If both are `0`, this setting is ignored.
dimensions:
columns: 0
lines: 0
# Window position (changes require restart)
#
# Specified in number of pixels.
# If the position is not set, the window manager will handle the placement.
#position:
# x: 0
# y: 0
# Window padding (changes require restart)
#
# Blank space added around the window in pixels. This padding is scaled
# by DPI and the specified value is always added at both opposing sides.
padding:
x: 0
y: 0
# Spread additional padding evenly around the terminal content.
dynamic_padding: false
# Window decorations
#
# Values for `decorations`:
# - full: Borders and title bar
# - none: Neither borders nor title bar
#
# Values for `decorations` (macOS only):
# - transparent: Title bar, transparent background and title bar buttons
# - buttonless: Title bar, transparent background, but no title bar buttons
decorations: full
# Startup Mode (changes require restart)
#
# Values for `startup_mode`:
# - Windowed
# - Maximized
# - Fullscreen
#
# Values for `startup_mode` (macOS only):
# - SimpleFullscreen
startup_mode: Windowed
# Window title
#title: Alacritty
# Window class (Linux only):
#class: Alacritty
scrolling:
# Maximum number of lines in the scrollback buffer.
# Specifying '0' will disable scrolling.
history: 10000
# Number of lines the viewport will move for every line scrolled when
# scrollback is enabled (history > 0).
multiplier: 3
# Faux Scrolling
#
# The `faux_multiplier` setting controls the number of lines the terminal
# should scroll when the alternate screen buffer is active. This is used
# to allow mouse scrolling for applications like `man`.
#
# Specifying `0` will disable faux scrolling.
# faux_multiplier: 3
# Scroll to the bottom when new text is written to the terminal.
auto_scroll: false
# Spaces per Tab (changes require restart)
#
# This setting defines the width of a tab in cells.
#
# Some applications, like Emacs, rely on knowing about the width of a tab.
# To prevent unexpected behavior in these applications, it's also required to
# change the `it` value in terminfo when altering this setting.
tabspaces: 8
# Font configuration (changes require restart)
font:
# Normal (roman) font face
normal:
# Font family
#
# Default:
# - (macOS) Menlo
# - (Linux) monospace
# - (Windows) Consolas
family: monospace
# The `style` can be specified to pick a specific face.
#style: Regular
# Bold font face
bold:
# Font family
#
# If the bold family is not specified, it will fall back to the
# value specified for the normal font.
family: monospace
# The `style` can be specified to pick a specific face.
style: Bold
# Italic font face
italic:
# Font family
#
# If the italic family is not specified, it will fall back to the
# value specified for the normal font.
family: monospace
# The `style` can be specified to pick a specific face.
style: Italic
# Point size
size: 10.5
# Offset is the extra space around each character. `offset.y` can be thought of
# as modifying the line spacing, and `offset.x` as modifying the letter spacing.
offset:
x: 0
y: 0
# Glyph offset determines the locations of the glyphs within their cells with
# the default being at the bottom. Increasing `x` moves the glyph to the right,
# increasing `y` moves the glyph upwards.
glyph_offset:
x: 0
y: 0
# Thin stroke font rendering (macOS only)
#
# Thin strokes are suitable for retina displays, but for non-retina screens
# it is recommended to set `use_thin_strokes` to `false`
#
# macOS >= 10.14.x:
#
# If the font quality on non-retina display looks bad then set
# `use_thin_strokes` to `true` and enable font smoothing by running the
# following command:
# `defaults write -g CGFontRenderingFontSmoothingDisabled -bool NO`
#
# This is a global setting and will require a log out or restart to take
# effect.
use_thin_strokes: true
# If `true`, bold text is drawn using the bright color variants.
# draw_bold_text_with_bright_colors: false
colors: *colorscheme
# Visual Bell
#
# Any time the BEL code is received, Alacritty "rings" the visual bell. Once
# rung, the terminal background will be set to white and transition back to the
# default background color. You can control the rate of this transition by
# setting the `duration` property (represented in milliseconds). You can also
# configure the transition function by setting the `animation` property.
#
# Values for `animation`:
# - Ease
# - EaseOut
# - EaseOutSine
# - EaseOutQuad
# - EaseOutCubic
# - EaseOutQuart
# - EaseOutQuint
# - EaseOutExpo
# - EaseOutCirc
# - Linear
#
# Specifying a `duration` of `0` will disable the visual bell.
visual_bell:
animation: EaseOutCubic
duration: 0
color: '0x222220'
# Background opacity
#
# Window opacity as a floating point number from `0.0` to `1.0`.
# The value `0.0` is completely transparent and `1.0` is opaque.
background_opacity: 1.0
# Mouse bindings
#
# Available fields:
# - mouse
# - action
# - mods (optional)
#
# Values for `mouse`:
# - Middle
# - Left
# - Right
# - Numeric identifier such as `5`
#
# All available `mods` and `action` values are documented in the key binding
# section.
mouse_bindings:
- { mouse: Middle, action: PasteSelection }
mouse:
# Click settings
#
# The `double_click` and `triple_click` settings control the time
# alacritty should wait for accepting multiple clicks as one double
# or triple click.
double_click: { threshold: 300 }
triple_click: { threshold: 300 }
# If this is `true`, the cursor is temporarily hidden when typing.
hide_when_typing: false
url:
# URL launcher
#
# This program is executed when clicking on a text which is recognized as a URL.
# The URL is always added to the command as the last parameter.
#
# When set to `None`, URL launching will be disabled completely.
#
# Default:
# - (macOS) open
# - (Linux) xdg-open
# - (Windows) explorer
#launcher: xdg-open
# URL modifiers
#
# These are the modifiers that need to be held down for opening URLs when clicking
# on them. The available modifiers are documented in the key binding section.
modifiers: None
selection:
semantic_escape_chars: ",│`|:\"' ()[]{}<>"
# When set to `true`, selected text will be copied to the primary clipboard.
save_to_clipboard: true
# Allow terminal applications to change Alacritty's window title.
dynamic_title: true
cursor:
# Cursor style
#
# Values for `style`:
# - ▇ Block
# - _ Underline
# - | Beam
style: Beam
# If this is `true`, the cursor will be rendered as a hollow box when the
# window is not focused.
unfocused_hollow: true
# Live config reload (changes require restart)
live_config_reload: true
# Shell
#
# You can set `shell.program` to the path of your favorite shell, e.g. `/bin/fish`.
# Entries in `shell.args` are passed unmodified as arguments to the shell.
#
# Default:
# - (Linux/macOS) /bin/bash --login
# - (Windows) powershell
#shell:
# program: /bin/bash
# args:
# - --login
# Windows 10 ConPTY backend (Windows only)
#
# This will enable better color support and may resolve other issues,
# however this API and its implementation is still young and so is
# disabled by default, as stability may not be as good as the winpty
# backend.
#
# Alacritty will fall back to the WinPTY automatically if the ConPTY
# backend cannot be initialized.
enable_experimental_conpty_backend: false
# Send ESC (\x1b) before characters when alt is pressed.
alt_send_esc: true
debug:
# Display the time it takes to redraw each frame.
render_timer: false
# Keep the log file after quitting Alacritty.
persistent_logging: false
# Log level
#
# Values for `log_level`:
# - None
# - Error
# - Warn
# - Info
# - Debug
# - Trace
log_level: Warn
# Print all received window events.
print_events: false
# Record all characters and escape sequences as test data.
ref_test: false
# Key bindings
#
# Key bindings are specified as a list of objects. Each binding will specify a
# key and modifiers required to trigger it, terminal modes where the binding is
# applicable, and what should be done when the key binding fires. It can either
# send a byte sequence to the running application (`chars`), execute a
# predefined action (`action`) or fork and execute a specified command plus
# arguments (`command`).
#
# Bindings are always filled by default, but will be replaced when a new binding
# with the same triggers is defined. To unset a default binding, it can be
# mapped to the `None` action.
#
# Example:
# `- { key: V, mods: Control|Shift, action: Paste }`
#
# Available fields:
# - key
# - mods (optional)
# - chars | action | command (exactly one required)
# - mode (optional)
#
# Values for `key`:
# - `A` -> `Z`
# - `F1` -> `F12`
# - `Key1` -> `Key0`
#
# A full list with available key codes can be found here:
# https://docs.rs/glutin/*/glutin/enum.VirtualKeyCode.html#variants
#
# Instead of using the name of the keys, the `key` field also supports using
# the scancode of the desired key. Scancodes have to be specified as a
# decimal number.
# This command will allow you to display the hex scancodes for certain keys:
# `showkey --scancodes`
#
# Values for `mods`:
# - Command
# - Control
# - Super
# - Shift
# - Alt
#
# Multiple `mods` can be combined using `|` like this: `mods: Control|Shift`.
# Whitespace and capitalization is relevant and must match the example.
#
# Values for `chars`:
# The `chars` field writes the specified string to the terminal. This makes
# it possible to pass escape sequences.
# To find escape codes for bindings like `PageUp` ("\x1b[5~"), you can run
# the command `showkey -a` outside of tmux.
# Note that applications use terminfo to map escape sequences back to
# keys. It is therefore required to update the terminfo when
# changing an escape sequence.
#
# Values for `action`:
# - Paste
# - PasteSelection
# - Copy
# - IncreaseFontSize
# - DecreaseFontSize
# - ResetFontSize
# - ScrollPageUp
# - ScrollPageDown
# - ScrollToTop
# - ScrollToBottom
# - ClearHistory
# - Hide
# - Quit
# - ClearLogNotice
# - SpawnNewInstance
# - None
#
# Values for `command`:
# The `command` field must be a map containing a `program` string and
# an `args` array of command line parameter strings.
#
# Example:
# `command: { program: "alacritty", args: ["-e", "vttest"] }`
#
# Values for `mode`:
# - ~AppCursor
# - AppCursor
# - ~AppKeypad
# - AppKeypad
key_bindings:
# (Windows/Linux only)
#- { key: V, mods: Control|Shift, action: Paste }
#- { key: C, mods: Control|Shift, action: Copy }
#- { key: Insert, mods: Shift, action: PasteSelection }
#- { key: Key0, mods: Control, action: ResetFontSize }
#- { key: Equals, mods: Control, action: IncreaseFontSize }
#- { key: Subtract, mods: Control, action: DecreaseFontSize }
# (macOS only)
#- { key: Key0, mods: Command, action: ResetFontSize }
#- { key: Equals, mods: Command, action: IncreaseFontSize }
#- { key: Minus, mods: Command, action: DecreaseFontSize }
#- { key: K, mods: Command, action: ClearHistory }
#- { key: K, mods: Command, chars: "\x0c" }
#- { key: V, mods: Command, action: Paste }
#- { key: C, mods: Command, action: Copy }
#- { key: H, mods: Command, action: Hide }
#- { key: Q, mods: Command, action: Quit }
#- { key: W, mods: Command, action: Quit }
- { key: Paste, action: Paste }
- { key: Copy, action: Copy }
- { key: L, mods: Control, action: ClearLogNotice }
- { key: L, mods: Control, chars: "\x0c" }
- { key: Home, chars: "\x1bOH", mode: AppCursor }
- { key: Home, chars: "\x1b[H", mode: ~AppCursor }
- { key: End, chars: "\x1bOF", mode: AppCursor }
- { key: End, chars: "\x1b[F", mode: ~AppCursor }
- { key: PageUp, mods: Shift, action: ScrollPageUp, mode: ~Alt }
- { key: PageUp, mods: Shift, chars: "\x1b[5;2~", mode: Alt }
- { key: PageUp, mods: Control, chars: "\x1b[5;5~" }
- { key: PageUp, chars: "\x1b[5~" }
- { key: PageDown, mods: Shift, action: ScrollPageDown, mode: ~Alt }
- { key: PageDown, mods: Shift, chars: "\x1b[6;2~", mode: Alt }
- { key: PageDown, mods: Control, chars: "\x1b[6;5~" }
- { key: PageDown, chars: "\x1b[6~" }
- { key: Tab, mods: Shift, chars: "\x1b[Z" }
- { key: Back, chars: "\x7f" }
- { key: Back, mods: Alt, chars: "\x1b\x7f" }
- { key: Insert, chars: "\x1b[2~" }
- { key: Delete, chars: "\x1b[3~" }
- { key: Left, mods: Shift, chars: "\x1b[1;2D" }
- { key: Left, mods: Control, chars: "\x1b[1;5D" }
- { key: Left, mods: Alt, chars: "\x1b[1;3D" }
- { key: Left, chars: "\x1b[D", mode: ~AppCursor }
- { key: Left, chars: "\x1bOD", mode: AppCursor }
- { key: Right, mods: Shift, chars: "\x1b[1;2C" }
- { key: Right, mods: Control, chars: "\x1b[1;5C" }
- { key: Right, mods: Alt, chars: "\x1b[1;3C" }
- { key: Right, chars: "\x1b[C", mode: ~AppCursor }
- { key: Right, chars: "\x1bOC", mode: AppCursor }
- { key: Up, mods: Shift, chars: "\x1b[1;2A" }
- { key: Up, mods: Control, chars: "\x1b[1;5A" }
- { key: Up, mods: Alt, chars: "\x1b[1;3A" }
- { key: Up, chars: "\x1b[A", mode: ~AppCursor }
- { key: Up, chars: "\x1bOA", mode: AppCursor }
- { key: Down, mods: Shift, chars: "\x1b[1;2B" }
- { key: Down, mods: Control, chars: "\x1b[1;5B" }
- { key: Down, mods: Alt, chars: "\x1b[1;3B" }
- { key: Down, chars: "\x1b[B", mode: ~AppCursor }
- { key: Down, chars: "\x1bOB", mode: AppCursor }
- { key: F1, chars: "\x1bOP" }
- { key: F2, chars: "\x1bOQ" }
- { key: F3, chars: "\x1bOR" }
- { key: F4, chars: "\x1bOS" }
- { key: F5, chars: "\x1b[15~" }
- { key: F6, chars: "\x1b[17~" }
- { key: F7, chars: "\x1b[18~" }
- { key: F8, chars: "\x1b[19~" }
- { key: F9, chars: "\x1b[20~" }
- { key: F10, chars: "\x1b[21~" }
- { key: F11, chars: "\x1b[23~" }
- { key: F12, chars: "\x1b[24~" }
- { key: F1, mods: Shift, chars: "\x1b[1;2P" }
- { key: F2, mods: Shift, chars: "\x1b[1;2Q" }
- { key: F3, mods: Shift, chars: "\x1b[1;2R" }
- { key: F4, mods: Shift, chars: "\x1b[1;2S" }
- { key: F5, mods: Shift, chars: "\x1b[15;2~" }
- { key: F6, mods: Shift, chars: "\x1b[17;2~" }
- { key: F7, mods: Shift, chars: "\x1b[18;2~" }
- { key: F8, mods: Shift, chars: "\x1b[19;2~" }
- { key: F9, mods: Shift, chars: "\x1b[20;2~" }
- { key: F10, mods: Shift, chars: "\x1b[21;2~" }
- { key: F11, mods: Shift, chars: "\x1b[23;2~" }
- { key: F12, mods: Shift, chars: "\x1b[24;2~" }
- { key: F1, mods: Control, chars: "\x1b[1;5P" }
- { key: F2, mods: Control, chars: "\x1b[1;5Q" }
- { key: F3, mods: Control, chars: "\x1b[1;5R" }
- { key: F4, mods: Control, chars: "\x1b[1;5S" }
- { key: F5, mods: Control, chars: "\x1b[15;5~" }
- { key: F6, mods: Control, chars: "\x1b[17;5~" }
- { key: F7, mods: Control, chars: "\x1b[18;5~" }
- { key: F8, mods: Control, chars: "\x1b[19;5~" }
- { key: F9, mods: Control, chars: "\x1b[20;5~" }
- { key: F10, mods: Control, chars: "\x1b[21;5~" }
- { key: F11, mods: Control, chars: "\x1b[23;5~" }
- { key: F12, mods: Control, chars: "\x1b[24;5~" }
- { key: F1, mods: Alt, chars: "\x1b[1;6P" }
- { key: F2, mods: Alt, chars: "\x1b[1;6Q" }
- { key: F3, mods: Alt, chars: "\x1b[1;6R" }
- { key: F4, mods: Alt, chars: "\x1b[1;6S" }
- { key: F5, mods: Alt, chars: "\x1b[15;6~" }
- { key: F6, mods: Alt, chars: "\x1b[17;6~" }
- { key: F7, mods: Alt, chars: "\x1b[18;6~" }
- { key: F8, mods: Alt, chars: "\x1b[19;6~" }
- { key: F9, mods: Alt, chars: "\x1b[20;6~" }
- { key: F10, mods: Alt, chars: "\x1b[21;6~" }
- { key: F11, mods: Alt, chars: "\x1b[23;6~" }
- { key: F12, mods: Alt, chars: "\x1b[24;6~" }
- { key: F1, mods: Super, chars: "\x1b[1;3P" }
- { key: F2, mods: Super, chars: "\x1b[1;3Q" }
- { key: F3, mods: Super, chars: "\x1b[1;3R" }
- { key: F4, mods: Super, chars: "\x1b[1;3S" }
- { key: F5, mods: Super, chars: "\x1b[15;3~" }
- { key: F6, mods: Super, chars: "\x1b[17;3~" }
- { key: F7, mods: Super, chars: "\x1b[18;3~" }
- { key: F8, mods: Super, chars: "\x1b[19;3~" }
- { key: F9, mods: Super, chars: "\x1b[20;3~" }
- { key: F10, mods: Super, chars: "\x1b[21;3~" }
- { key: F11, mods: Super, chars: "\x1b[23;3~" }
- { key: F12, mods: Super, chars: "\x1b[24;3~" }
- { key: NumpadEnter, chars: "\n" }

View file

@ -9,7 +9,6 @@
# #
# to customize this to your own needs, change the `push folder` to the # to customize this to your own needs, change the `push folder` to the
# location of your dotfiles (stow) repository # location of your dotfiles (stow) repository
alias dotlink="pushd ~/.dotfiles;\ alias dotlink="pushd ~/.dotfiles;\
dotter deploy;\ stow -R */ 2> >(grep -v 'Absolute/relative mismatch between Stow dir' 1>&2) ;\
popd" popd"

View file

@ -0,0 +1,4 @@
# TODO find a more generic way to express 'ignore any non-folder files'
^/install_packages.sh
^/packages.*.txt

View file

@ -1,22 +0,0 @@
FROM archlinux:latest
# First build then run this dockerfile with:
# `podman build -t bootstrap .`
# `podman run -it -v /path/to/my/dotfiles:/path/to/my/dotfiles:ro bootstrap`
RUN pacman-key --init
RUN pacman -Syu --noconfirm git vi base-devel sudo zsh man man-pages
RUN useradd -m -G wheel -s /usr/bin/zsh marty
RUN echo "%wheel ALL=(ALL:ALL) ALL" >> /etc/sudoers
RUN echo "marty:password" | chpasswd
# RUN su marty
# RUN cd /home/marty
# RUN git clone "https://git.martyoeh.me/Marty/dotfiles" .dotfiles
# link it directly from dotfile development dir to experiment
USER marty
VOLUME /home/marty/.dotfiles
WORKDIR /home/marty/.dotfiles
CMD ["/usr/bin/bash"]

View file

@ -1,9 +0,0 @@
# bootstrap module
The bootstrapping module mainly concerns the setup of the repository itself -- installation of packages, setting up basic options and maintenance scripts.
* installs general list of packages, listed [here](bootstrap/packages.tsv)
* if githooks are enabled (either through install script, or manually) will compare installed packages with those on the package list on each commit and warn user about differences
* contains a simple alias `dotlink` which allows quickly re-linking dotfiles when they have been changed. This is useful to invoke when files have been removed or added and need to be sym-linked by stow again (only works for `~/.dotfiles` dot directory)
* contains an `update_package_list.sh` script which I can use to quickly repopulate the list of explicitly installed packages, noting down their source (repositories or AUR) and retaining their target, if I set any (only works for `~/.dotfiles` dot directory)

View file

@ -7,110 +7,86 @@
# DESCRIPTION: Display usage information for this script. # DESCRIPTION: Display usage information for this script.
# PARAMETERS: see usage function # PARAMETERS: see usage function
#============================================================================== #==============================================================================
PKG_TSV_FILE=${PKG_TSV_FILE:-bootstrap/packages_stable.tsv} packages="${BOOTSTRAP_PACKAGES:-packages.txt}"
packages_repo="${BOOTSTRAP_PACKAGES:-$(grep -e ' R ' "$PKG_TSV_FILE" | cut -f1 -d' ')}"
packages_aur="${BOOTSTRAP_PACKAGES_AUR:-$(grep -e ' A ' "$PKG_TSV_FILE" | cut -f1 -d' ')}"
packages_pipx="${BOOTSTRAP_PACKAGES_PIPX:-$(grep -e ' P ' "$PKG_TSV_FILE" | cut -f1,5 -d' ')}"
main() { main() {
local cmd="" local cmd=""
local ret=0 local ret=0
case "$1" in case "$1" in
-v | --version) -v | --version)
printf "Package bootstrap script.\n\n©Marty Oehme\n\nVersion: 0.3\n" printf "Package bootstrap script.\n\n©Marty Oehme\n\nVersion: 0.3\n"
;; ;;
-h | --help) -h | --help)
printf "Usage: install [-f|--force][-v|--version][-h|--help]\n\n-f Do not ask for any confirmations but force update and installation.\n" printf "Usage: install [-f|--force][-v|--version][-h|--help]\n\n-f Do not ask for any confirmations but force update and installation.\n"
;; ;;
-f | --force) -f | --force)
install true install true
;; ;;
*) *)
install false install false
;; ;;
esac esac
shift shift
$cmd "$@" $cmd "$@"
ret=$((ret + $?)) ret=$((ret + $?))
exit $ret exit $ret
} }
install_paru() { install_yay() {
# check for existing paru installation # check for existing yay installation
if type paru >/dev/null 2>&1; then if type yay >/dev/null 2>&1; then
echo "Existing paru installation found ..........................................." echo "Existing yay installation found ..........................................."
return return
fi fi
# use tmp dir to make paru # use tmp dir to make yay
tempdir=".paru" target=$(mktemp -d)
git clone https://aur.archlinux.org/paru.git "$tempdir" git clone https://aur.archlinux.org/yay.git "$target"
pushd "$tempdir" || exit 1 cd "$target" || exit
makepkg -si makepkg -si
popd || exit 1
rm -rf "$tempdir"
} }
update_repos() { update_repos() {
unattended="$1" unattended="$1"
if "$unattended"; then if "$unattended"; then
paru -Sqyy --noconfirm yay -Sqyy --noconfirm
else else
paru -Syy yay -Syy
fi fi
} }
install_packages() { install_packages() {
unattended="$1" unattended="$1"
if "$unattended"; then if "$unattended"; then
echo "$packages_repo" "$packages_aur" | paru -Squ --noconfirm --needed - yay -Squ --noconfirm --needed - <"$packages"
else else
echo "$packages_repo" | paru -Squ --needed - yay -Su --needed - <"$packages"
echo "$packages_aur" | paru -S --needed - fi
fi
} }
install_pipx() { check_consent() {
if type pipx >/dev/null 2>&1; then echo "This will take a while and install many packages. Proceed [y/N]?"
echo "Existing pipx installation found .........................................." read -r yes
return if [[ "$yes" != y* ]]; then
fi echo "Exiting."
if "$unattended"; then exit
paru -S --noconfirm python-pipx fi
else
paru -S python-pipx
fi
}
install_pipx_pkgs() {
while IFS= read -r line; do
if [ -z "$line" ]; then return; fi
prog=$(echo "$line" | cut -f1 -d' ')
pipx install "$prog"
injections=$(echo "$line" | cut -f2 -d' ')
for inject_args in ${injections//,/ }; do
pipx inject "$prog" "$inject_args"
done
done <<<"$packages_pipx"
} }
install() { install() {
unattended=$1 unattended=$1
echo "Beginning package bootstrap ..............................................." echo "Beginning package bootstrap ..............................................."
echo "Installing paru ............................................................" if ! "$unattended"; then
install_paru check_consent
echo "Installing apps ..........................................................." fi
update_repos "$unattended" echo "Installing yay ............................................................"
install_packages "$unattended" install_yay
echo "Done ......................................................................" echo "Installing apps ..........................................................."
echo "Installing pipx ..........................................................." update_repos "$unattended"
install_pipx install_packages "$unattended"
echo "Installing pipx packages .................................................." echo "Done ......................................................................"
install_pipx_pkgs
echo "Done ......................................................................"
} }
main "$@" main "$@"

135
bootstrap/packages.txt Normal file
View file

@ -0,0 +1,135 @@
alacritty
anki
asciinema
atool
bibtool
bison
chromium
dhcpcd
dialog
docker
dunst
exa
fasd
feh
flashfocus-git
flex
fzf
git-lfs
gitlint
glances
glow
gnome-keyring
go
gopass
grub
hugo
i3blocks
i3-gaps
i3lock
i3status
iputils
jabref-latest
jpdftweak
keybase-bin
libnotify
licenses
linux-firmware
linux-headers
linux-lts
linux-lts-headers
littler
logrotate
lprng
lvm2
lynx
man-db
man-pages
masterpdfeditor-free
mosh
mpv
nano
neovim
nerd-fonts-fira-code
nerd-fonts-iosevka
netctl
networkmanager
nextcloud-client
ntfs-3g
ntp
os-prober
pandoc-citeproc
pdfjs
pia-tools
picom
pkgconf
playerctl
polybar
psmisc
pulseaudio-alsa
pulsemixer
python-pdfminer.six
python-pipx
python-pybtex
python-pynvim
python-ueberzug
qutebrowser
redshift
ripgrep-all
rng-tools
rofi-calc
rofi-dmenu
rofi-greenclip
rofimoji
scrot
shellcheck-static
shfmt
spotify
sshfs
stow
surfraw
sxhkd
systemd-sysvcompat
texlive-bibtexextra
texlive-fontsextra
texlive-formatsextra
texlive-games
texlive-humanities
texlive-music
texlive-pictures
texlive-pstricks
texlive-publishers
texlive-science
tmux
tomb
topgrade
ttf-comic-neue
ttf-heuristica
ttf-signika
unclutter
unrar
usbutils
vagrant
vi
vifm
virtualbox
xcape
xclip
xdg-user-dirs
xorg-xev
xorg-xinit
xorg-xinput
yarn
yay
youtube-dl
zathura-pdf-mupdf
pacman-contrib
# zsh plugins
oh-my-zsh-git
alias-tips-git
zsh-autosuggestions
zsh-completions-git
zsh-fast-syntax-highlighting-git
zsh-theme-powerlevel10k-git
nvm

View file

@ -0,0 +1,11 @@
ansible
autoconf
automake
bash-bats
dosfstools
hplip
nvidia
powertop
qemu
virt-manager
zotero

View file

@ -1,380 +0,0 @@
Name Description Source Target Injections
aaxtomp3 Convert Audible's .aax filetype to MP3, FLAC, M4A, or OPUS A
abduco Tool for session {at,de}tach support which allows a process to run independently from its controlling terminal R
acpid A daemon for delivering ACPI power management events with netlink support R
afew Initial tagging script for notmuch mail R
alias-tips-git An oh-my-zsh plugin to help remembering those aliases you defined once A
alsa-utils Advanced Linux Sound Architecture - Utilities R
anki-bin Helps you remember facts (like words/phrases in a foreign language) efficiently. Installed with wheel. A
ansible Official assortment of Ansible collections R
ansible-lint Checks playbooks for practices and behaviour that could potentially be improved. R
arch-wiki-lite Arch Wiki without HTML. 1/9 as big, easily searched & viewable on console R
arduino Arduino prototyping platform SDK R
arduino-avr-core Arduino AVR core with upstream avr-gcc and avrdude R
arduino-cli Arduino command line interface R
asciinema Record and share terminal sessions R
asix-ax88179-dkms A kernel module for ASIX AX88178A AX88179 USB 3.0 network adapters A
aspell-de German dictionary for aspell R
aspell-en English dictionary for aspell R
atool A script for managing file archives of various types R
atuin Magical shell history R
aubio A tool for extracting annotations from audio signals R
auto-cpufreq Automatic CPU speed & power optimizer A
autofs A kernel-based automounter for Linux A
barrier Open-source KVM software based on Synergy (GUI) R
base Minimal package set to define a basic Arch Linux installation R
base-devel Basic tools to build Arch Linux packages R
bash-completion Programmable completion for the bash shell R
bash-language-server Bash language server implementation based on Tree Sitter and its grammar for Bash R
bat Cat clone with syntax highlighting and git integration R
bats Bash Automated Testing System R
bc An arbitrary precision calculator language R
beancount A personal double entry accounting and budgeting software P git+https://github.com/bratekarate/beancount-categorizer.git,beancount-dkb,fava,python-magic,smart-importer
bearssl Implementation of the SSL/TLS protocol (RFC 5246) written in C R
beets Organize your music collection from the command line P beetcamp,deets-describe,beets-ydl,pyacoustid,pylast
bemenu-dmenu Symlink for using bemenu (native wayland support) as a drop-in replacement to dmenu A
bemoji Emoji picker that remembers your favorites A
bibclean BibTeX and Scribe bibliography prettyprinter and syntax checker A
biber A Unicode-capable BibTeX replacement for biblatex users R
bibtool A tool for manipulating BibTeX files R
bind A complete, highly portable implementation of the DNS protocol R
bluetuith-bin A TUI based bluetooth manager A
bluez-utils Development and debugging utilities for the bluetooth protocol stack R
booster Fast and secure initramfs generator R
brightnessctl Lightweight brightness control tool R
btop A monitor of system resources, bpytop ported to C++ R
caddy Fast web server with automatic HTTPS R
calcurse A text-based personal organizer R
catdoc A convertor for Microsoft Word, Excel, PowerPoint and RTF Files to text R
chafa Image-to-text converter supporting a wide range of symbols and palettes, transparency, animations, etc. R
cinny-desktop-bin Matrix client focusing primarily on a simple, elegant and secure interface (binary release) A
clipman A simple clipboard manager for Wayland A
cups-pdf PDF printer for cups R
cups-pk-helper A helper that makes system-config-printer use PolicyKit R
dbus-broker Linux D-Bus Message Broker R
dcnnt Yet another tool to connect Android phone with desktop similar to KDE Connect A
dconf-editor GSettings editor for GNOME R
dell-command-configure Configure various BIOS features on Dell laptops A
dhcpcd RFC2131 compliant DHCP client daemon R
distrobox Use any linux distribution inside your terminal. A
dnsmasq Lightweight, easy to configure DNS forwarder and DHCP server R
docker Pack, ship and run any application as a lightweight container R
docker-compose Fast, isolated development environments using Docker R
docx2txt Recovers text from DOCX files, with good formatting. R
dos2unix Text file format converter R
dotter-rs-bin A dotfile manager and templater written in Rust A
duf Disk Usage/Free Utility R
dust A more intuitive version of du in rust R
efm-langserver General purpose Language Server A
enca Charset analyser and converter R
entr Run arbitrary commands when files change R
euporie View and work with ipnb Python notebooks from the cli P
exercism-bin Command line client for exercism.io A
exfat-utils Utilities for exFAT file system R
eza A modern replacement for ls (community fork of exa) R
f3 Simple tool that tests flash cards capacity and performance to see if they live up to claimed specifications A
fd Simple, fast and user-friendly alternative to find R
ffmpegthumbnailer Lightweight video thumbnailer that can be used by file managers R
firefox Standalone web browser from mozilla.org R
flavours A simple and easy cli to build and use base16 schemes A
fonts-cjk Linux 下的免费商用字体包 A
freerdp Free implementation of the Remote Desktop Protocol (RDP) R
fwupd Simple daemon to allow session software to update firmware R
fzf-tab-bin-git Replace zsh's default completion selection menu with fzf (git version). This package also compiles the optional binary module. A
gallery-dl Command-line program to download image-galleries and collections from several image hosting sites A
gamemode A daemon/lib combo that allows games to request a set of optimisations be temporarily applied to the host OS R
gimp GNU Image Manipulation Program R
git-delta Syntax-highlighting pager for git and diff output R
git-lfs Git extension for versioning large files R
gitlint Git commit message linter A
gitui Blazing fast terminal-ui for git written in Rust R
gk6x-bin Configure keys, macros, and lighting on GK6X keyboards (GK64, GK84, GK61, etc) A
glances CLI curses-based monitoring tool R
glfw-wayland A free, open source, portable framework for graphical application development (wayland) R
glow Command-line markdown renderer R
gnu-netcat GNU rewrite of netcat, the network piping application R
gnumeric A GNOME Spreadsheet Program R
gnuplot Plotting package which outputs to X11, PostScript, PNG, GIF, and others R
go-md2man A markdown to manpage generator R
gomuks A terminal based Matrix client written in Go A
gopls Language server for Go programming language R
gotty-bin Simple command line tool that turns your CLI tools into web applications. A
grim Screenshot utility for Wayland R
grub GNU GRand Unified Bootloader (2) R
gsimplecal Simple and lightweight GTK calendar R
gst-plugins-bad Multimedia graph framework - bad plugins R
gstreamer-vaapi Multimedia graph framework - vaapi plugin R
gucharmap Gnome Unicode Charmap R
haveged Entropy harvesting daemon using CPU timings R
heimdall Tool suite used to flash firmware (ROMs) onto Samsung Galaxy S devices R
htop Interactive process viewer R
hugo Fast and Flexible Static Site Generator in Go R
iftop Display bandwidth usage on an interface R
imapfilter A mail filtering utility for processing IMAP mailboxes A
imv Image viewer for Wayland and X11 R
intel-ucode Microcode update files for Intel CPUs R
iputils Network monitoring tools, including ping R
ipython An enhanced Interactive Python shell. R
isbntools A variety of tools to work with isbn addresses P
iucode-tool Tool to manipulate Intel® IA-32/X86-64 microcode bundles R
iwd Internet Wireless Daemon R
jc Converts the output of popular command-line tools and file-types to JSON R
jiq-bin Interactive JSON query tool using jq expressions A
jmtpfs FUSE and libmtp based filesystem for accessing MTP (Media Transfer Protocol) devices A
jpdftweak A Swiss Army Knife GUI application for PDF documents A
jrnl Collect your thoughts and notes without leaving the command line R
jupyter-nbclient A tool for running Jupyter Notebooks in different execution contexts. R
kanshi Dynamic output configuration for Wayland WMs R
keyd A key remapping daemon for linux R
khal CLI calendar application built around CalDAV R
khard Console address book manager R
kubo IPFS implementation in Go R
lazygit Simple terminal UI for git commands R
lib32-gamemode A daemon/lib combo that allows games to request a set of optimisations be temporarily applied to the host OS R
libdvdcss Portable abstraction library for DVD decryption R
libfido2 Library functionality for FIDO 2.0, including communication with a device over USB R
libqalculate Multi-purpose desktop calculator R
libreoffice-fresh LibreOffice branch which contains new features and program enhancements R
libva-intel-driver VA-API implementation for Intel G45 and HD Graphics family R
libvirt API for controlling virtualization engines (openvz,kvm,qemu,virtualbox,xen,etc) R
linux The Linux kernel and modules R
linux-firmware Firmware files for Linux R
linux-headers Headers and scripts for building modules for the Linux kernel R
linux-lts The LTS Linux kernel and modules R
littler a hash-bang and simple command line pipe front end for GNU R A
logrotate Rotates system logs automatically R
lsof Lists open files for running Unix processes R
lswt List Wayland toplevels A
lua-format LuaFormatter - Code formatter for Lua A
lua-language-server Lua Language Server coded by Lua R
lua51 Powerful lightweight programming language designed for extending applications R
luacheck A tool for linting and static analysis of Lua code R
lutris Open Gaming Platform R
ly TUI display manager R
lynx A text browser for the World Wide Web R
magic-wormhole Securely transfer data between computers R
maim Utility to take a screenshot using imlib2 R
mako Lightweight notification daemon for Wayland R
man-db A utility for reading man pages R
man-pages Linux man pages R
markdown-anki-decks Construct and modify anki decks directly with markdown P
markdownlint-cli MarkdownLint Command Line Interface A
masterpdfeditor-free A complete solution for creation and editing PDF files - Free version without watermark A
mbsync-git free (GPL) mailbox synchronization program A
mediainfo Supplies technical and tag information about a video or audio file (CLI interface) R
mermaid-cli Generation of diagram and flowchart from text in a similar manner as markdown (CLI) A
mimeo Open files by MIME-type or file name using regular expressions. A
minidlna A DLNA/UPnP-AV Media server (aka ReadyDLNA) R
minio-client Replacement for ls, cp, mkdir, diff and rsync commands for filesystems and object storage R
mopidy-bandcamp Mopidy backend for Bandcamp A
mopidy-iris A Mopidy Web client that utilizes the Spotify and EchoNest frameworks. (Formerly Spotmop) A
mopidy-local Mopidy extension for local media playback A
mopidy-mpd Mopidy extension for controlling playback from MPD clients A
mopidy-mpris Mopidy extension for controlling Mopidy through the MPRIS D-Bus interface A
mopidy-scrobbler Mopidy extension for scrobbling played tracks to Last.fm A
mopidy-somafm Mopidy extension for playing music from SomaFM A
mopidy-youtube Mopidy extension for playing music from Youtube A
moreutils A growing collection of the unix tools that nobody thought to write thirty years ago R
mosh Mobile shell, surviving disconnects with local echo and line editing R
mpv-mpris MPRIS plugin for mpv R
msmtp A mini smtp client R
mupdf-gl Lightweight PDF and XPS viewer with OpenGL backend R
mutt-ics Show calendar event details in mutt A
ncmpcpp Almost exact clone of ncmpc with some new features R
needrestart Restart daemons after library updates. A
neomutt A version of mutt with added features R
neovim Fork of Vim aiming to improve user experience, plugins, and GUIs R
net-tools Configuration tools for Linux networking R
netbird-bin WireGuard-based mesh network A
netctl Profile based systemd network management R
nethogs A net top tool which displays traffic used per process instead of per IP or interface R
network-manager-applet Applet for managing network connections R
networkmanager-openconnect NetworkManager VPN plugin for OpenConnect R
newsboat RSS/Atom feed reader for text terminals R
nextcloud-client Nextcloud desktop client R
nfs-utils Support programs for Network File Systems R
nmap Utility for network discovery and security auditing R
nodejs-pandiff Prose diffs for any document format supported by Pandoc A
noto-fonts-emoji Google Noto emoji fonts R
npm A package manager for javascript R
nss-mdns glibc plugin providing host name resolution via mDNS R
nsxiv Neo (or New or Not) Simple (or Small or Suckless) X Image Viewer A
ntfs-3g NTFS filesystem driver and utilities R
ntp Network Time Protocol reference implementation R
nushell A new type of shell R
nzbget Download from Usenet using .nzb files R
offpunk Fork of the command-line Gemini client AV-98 with added offline capabilities A
oh-my-zsh-git A community-driven framework for managing your zsh configuration. Includes 180+ optional plugins and over 120 themes to spice up your morning, and an auto-update tool so that makes it easy to keep up with the latest updates from the community A
os-prober Utility to detect other OSes on a set of drives R
pacman-contrib Contributed scripts and tools for pacman systems R
papis Papis is a powerful and highly extensible command-line based document and bibliography manager. P whoosh,papis-zotero,papis-scihub,git+https://git.martyoeh.me/Marty/papis-extract.git,git+https://github.com/supersambo/papis-tui,pybtex-apa-style,git+https://git.martyoeh.me/Marty/papis-bbt-formatter.git
parallel A shell tool for executing jobs in parallel R
parsec-bin Remotely connect to a gaming pc for a low latency remote computing experience A
paru-bin Feature packed AUR helper A
pass-coffin A password store extension that hides data inside a signed and encrypted coffin A
pass-ssh A pass extension that creates ssh keys with an automatically generated passphrases stored in pass and outputs the public key using fzf or rofi A
pavucontrol PulseAudio Volume Control R
pbzip2 Parallel implementation of the bzip2 block-sorting file compressor R
pdfjs PDF reader in javascript R
pdftk Command-line tool for working with PDFs R
peek Simple screen recorder with an easy to use interface R
perf Linux kernel performance auditing tool R
perl-authen-sasl Perl/CPAN Module Authen::SASL : SASL authentication framework R
piavpn-bin Private Internet Access client A
pigz Parallel implementation of the gzip file compressor R
pipewire-alsa Low-latency audio/video router and processor - ALSA configuration R
pipewire-roc Low-latency audio/video router and processor - ROC streaming support R
playerctl mpris media player controller and lib for spotify, vlc, audacious, bmp, xmms2, and others. R
podman Tool and library for running OCI-based containers in pods R
powertop A tool to diagnose issues with power consumption and power management R
prettier An opinionated code formatter for JS, JSON, CSS, YAML and much more R
protonvpn Official ProtonVPN metapackage that installs protonvpn-gui and protonvpn-cli, maintained by the ProtonVPN team. A
ptpython Python REPL build on top of prompt_toolkit A
pulsemixer CLI and curses mixer for pulseaudio R
pup Command line tool for processing HTML A
pv A terminal-based tool for monitoring the progress of data through a pipeline. R
pyright Type checker for the Python language R
python-adblock Brave's adblock library in Python R
python-dictcc commandline tool for dict.cc A
python-docs Set of HTML documentation for python R
python-html2text A HTML to markdown-structured text converter R
python-jupytext Jupyter notebooks as Markdown documents, Julia, Python or R scripts A
python-openpyxl A Python library to read/write Excel 2007 xlsx/xlsm files R
python-pagelabels Python library to manipulate PDF page numbers and labels. A
python-pancritic CriticMarkdup parser with optional pandoc backend A
python-pdfminer Python PDF Parser R
python-pip The PyPA recommended tool for installing Python packages R
python-pipx Install and Run Python Applications in Isolated Environments R
python-poethepoet A task runner that works well with poetry A
python-polars-bin Blazingly fast DataFrames library using Apache Arrow Columnar Format as memory model A
python-pybluez Python wrapper for the BlueZ Bluetooth stack R
python-pybtex A BibTeX-compatible bibliography processor written in Python R
python-pynvim Python client for Neovim R
python-pyqt6-3d Python bindings for Qt3D R
python-pyqt6-charts Python bindings for QtChart R
python-pyqt6-datavisualization Python bindings for QtDataVisualization R
python-pyqt6-networkauth Python bindings for QtNetworkAuth R
python-readability-lxml Fast html to text parser (article readability tool) python library R
python-slugify A Python slugify application that handles unicode R
python-tasklib Python library for interacting with taskwarrior databases R
qemu-desktop A QEMU setup for desktop environments R
qt5-wayland Provides APIs for Wayland R
qt5-xmlpatterns Support for XPath, XQuery, XSLT and XML schema validation R
qt6-svg Classes for displaying the contents of SVG files R
qt6-wayland Provides APIs for Wayland R
qtcurve-gtk2 A configurable set of widget styles for KDE and Gtk R
quarto-cli-bin An open-source scientific and technical publishing system built on Pandoc (binary from official repo) A
qutebrowser A keyboard-driven, vim-like browser based on Python and Qt R
refind An EFI boot manager R
refind-btrfs Generate rEFInd manual boot stanzas from Btrfs snapshots A
reflector A Python 3 module and script to retrieve and filter the latest Pacman mirror list. R
remind A sophisticated calendar and alarm program. R
remmina remote desktop client written in GTK+ R
restic Fast, secure, efficient backup program R
ripgrep-all rga: ripgrep, but also search in PDFs, E-Books, Office documents, zip, tar.gz, etc. R
river A dynamic tiling wayland compositor R
rivercarro A slightly modified version of rivertile layout generator for river. A
rng-tools Random number generator related utilities R
sc-im A spreadsheet program based on SC A
scc Sloc, Cloc and Code: a very fast accurate code counter with complexity calculations and COCOMO estimates written in pure Go A
scc-bin Sloc, Cloc and Code: scc is a very fast accurate code counter with complexity calculations and COCOMO estimates written in pure Go A
scrcpy Display and control your Android device R
screen Full-screen window manager that multiplexes a physical terminal R
sd Intuitive find & replace R
sfz A simple static file server A
shellcheck-bin Shell script analysis tool (binary release, static) A
shfmt Format shell programs R
sioyek PDF viewer for research papers and technical books. A
slurp Select a region in a Wayland compositor R
smartmontools Control and monitor S.M.A.R.T. enabled ATA and SCSI Hard Drives R
snap-pac Pacman hooks that use snapper to create pre/post btrfs snapshots like openSUSE's YaST R
speedtest-cli Command line interface for testing internet bandwidth using speedtest.net R
sshfs FUSE client based on the SSH File Transfer Protocol R
starship The cross-shell prompt for astronauts R
steam Valve's digital software delivery system R
sudo Give certain users the ability to run some commands as root R
surfraw Shell Users' Revolutionary Front Rage Against the Web R
swaybg Wallpaper tool for Wayland compositors R
swayidle Idle management daemon for Wayland R
swww A Solution to your Wayland Wallpaper Woes R
task-spooler Queue up tasks from the shell for batch execution A
taskopen Script for taking notes and open urls with taskwarrior A
tasksh A shell command that wraps Taskwarrior commands A
tea A command line tool to interact with Gitea servers R
tectonic Modernized, complete, self-contained TeX/LaTeX engine, powered by XeTeX and TeXLive R
termdown Countdown timer and stopwatch in your terminal R
tex-gyre-fonts Substitute PostScript fonts in OpenType format R
texlab A cross-platform implementation of the Language Server Protocol for LaTeX. R
tgpt-bin ChatGPT in terminal without needing API keys A
thermald The Linux Thermal Daemon program from 01.org R
tidy-viewer CLI csv pretty printer that uses column styling A
timew Timewarrior, A command line time tracking application R
tinyxxd Standalone version of the hex dump utility that comes with ViM R
tlp Linux Advanced Power Management R
tmux Terminal multiplexer R
toilet free replacement for the FIGlet utility. A
topgrade-bin Invoke the upgrade procedure of multiple package managers A
traceroute Tracks the route taken by packets over an IP network R
translate-shell A command-line interface and interactive shell for Google Translate R
transmission-qt Fast, easy, and free BitTorrent client (Qt GUI) R
ttf-brill Brill Typeface by John Hudson for Brill Publishing House A
ttf-comic-neue Casual font that fixes the shortcomings of Comic Sans A
ttf-heuristica A serif latin & cyrillic font, derived from the "Adobe Utopia" font by Apanov A
ttf-iosevka-nerd Patched font Iosevka from nerd fonts library R
ttf-signika Sans-serif typeface from Google by Anna Giedryś A
ttf-victor-mono-nerd Patched font Victor Mono from nerd fonts library R
tuir Browse Reddit from your terminal A
tut A TUI for Mastodon with vim inspired keys A
typescript-language-server Language Server Protocol (LSP) implementation for TypeScript using tsserver R
udiskie Removable disk automounter using udisks R
ufw Uncomplicated and easy to use CLI tool for managing a netfilter firewall R
unrar The RAR uncompression program R
unrtf Command-line program which converts RTF documents to other formats R
urlview-xdg-git A curses URL parser for text files. Git version, adds support for QUITONLAUNCH option and XDG Base Directory specification compliance. A
usql A universal command-line interface for SQL databases A
v4l2loopback-dkms v4l2-loopback device module sources R
vagrant Build and distribute virtualized development environments R
vdirsyncer Synchronize CalDAV and CardDAV. R
viddy A modern watch command A
vifm A file manager with curses interface, which provides Vi[m]-like environment R
vim-language-server VimScript language server A
vimiv-qt-git An image viewer with vim-like keybindings A
virt-manager Desktop user interface for managing virtual machines R
virtualbox Powerful x86 virtualization for enterprise as well as home use R
virtualbox-guest-iso The official VirtualBox Guest Additions ISO image R
visidata Terminal spreadsheet multitool for discovering and arranging data R
viu Simple terminal image viewer R
wallabag-client Command line client for the self hosted read-it-later app Wallabag A
wavemon Ncurses-based monitoring application for wireless network devices R
waybar Highly customizable Wayland bar for Sway and Wlroots based compositors R
waylock A simple screenlocker for wayland compositors R
wdisplays GUI display configurator for wlroots compositors A
wev tool for debugging wayland events, similar to xev A
wezterm A GPU-accelerated cross-platform terminal emulator and multiplexer R
wf-recorder Screen recorder for wlroots-based compositors such as sway R
wget Network utility to retrieve files from the Web R
wireguard-tools next generation secure network tunnel - tools for configuration R
wireless_tools Tools allowing to manipulate the Wireless Extensions R
wl-mirror a simple Wayland output mirror client R
wlopm Wayland output power management. A
wlsunset Day/night gamma adjustments for Wayland compositors A
wlsunset Day/night gamma adjustments for Wayland compositors R
wpa_actiond Daemon that connects to wpa_supplicant and handles connect and disconnect events A
wtype xdotool type for wayland R
xdg-user-dirs Manage user directories like ~/Desktop and ~/Music R
xsv A CLI for indexing, slicing, analyzing, splitting and joining CSV files R
xxd-standalone Hexdump utility from vim A
yaml-language-server YAML Language Server R
yarn Fast, reliable, and secure dependency management R
yt-dlp A youtube-dl fork with additional features and fixes R
ytfzf A POSIX script to find and watch youtube videos from the terminal R
yubikey-manager Python library and command line tool for configuring a YubiKey R
zathura-cb Adds comic book support to zathura R
zathura-djvu DjVu support for Zathura R
zathura-pdf-mupdf PDF support for Zathura (MuPDF backend) (Supports PDF, ePub, and OpenXPS) R
zk A command-line tool helping you to maintain a Zettelkasten or personal wiki R
zotero-bin Zotero Standalone. Is a free, easy-to-use tool to help you collect, organize, cite, and share your research sources. A
zoxide A smarter cd command for your terminal R
zq Tooling for super-structured data A
zsh-autosuggestions Fish-like autosuggestions for zsh R
zsh-fast-syntax-highlighting Optimized and extended zsh-syntax-highlighting A
Can't render this file because it has a wrong number of fields in line 32.

View file

@ -1,16 +0,0 @@
Name Description Source Target
adbfs-rootless-git fuse filesystem over adb tool for android devices, no device root required A
arch-install-scripts Scripts to aid in installing Arch Linux R
blueberry Bluetooth configuration tool R
dotter-rs-bin A dotfile manager and templater written in Rust A
eza A modern replacement for ls (community fork of exa) R
feishin-appimage A modern self-hosted music player. A
khal CLI calendar application built around CalDAV R
m4b-tool-bin A command line utility to merge, split and chapterize audiobook files such as mp3, ogg, flac, m4a or m4b A
nodejs-markmap-cli Create markmaps (mindmaps from markdown) from CLI A
pv A terminal-based tool for monitoring the progress of data through a pipeline R
qpwgraph PipeWire Graph Qt GUI Interface R
texlive-latexextra TeX Live - LaTeX additional packages R
toilet Free replacement for the FIGlet utility R
vifm A file manager with curses interface, which provides Vi[m]-like environment R
woeusb-ng Simple tool that enable you to create your own usb stick with Windows installer. A
1 Name Description Source Target
2 adbfs-rootless-git fuse filesystem over adb tool for android devices, no device root required A
3 arch-install-scripts Scripts to aid in installing Arch Linux R
4 blueberry Bluetooth configuration tool R
5 dotter-rs-bin A dotfile manager and templater written in Rust A
6 eza A modern replacement for ls (community fork of exa) R
7 feishin-appimage A modern self-hosted music player. A
8 khal CLI calendar application built around CalDAV R
9 m4b-tool-bin A command line utility to merge, split and chapterize audiobook files such as mp3, ogg, flac, m4a or m4b A
10 nodejs-markmap-cli Create markmaps (mindmaps from markdown) from CLI A
11 pv A terminal-based tool for monitoring the progress of data through a pipeline R
12 qpwgraph PipeWire Graph Qt GUI Interface R
13 texlive-latexextra TeX Live - LaTeX additional packages R
14 toilet Free replacement for the FIGlet utility R
15 vifm A file manager with curses interface, which provides Vi[m]-like environment R
16 woeusb-ng Simple tool that enable you to create your own usb stick with Windows installer. A

View file

@ -1,39 +0,0 @@
# Makes capslock to control/escape
# insert to paste
# right alt to enable German Umlaute (äÄöÖüÜ),
# sharp s (ß), and the Euro sign (€).
# Needs compose key to be set in xkb to work correctly:
# $ setxkbmap -option "compose:menu"
[ids]
*
[main]
capslock = overload(control, esc)
insert = S-insert
rightalt = layer(dia)
shift = layer(shift)
rightshift = layer(shift)
[shift:S]
rightalt = layer(shiftedDia)
[dia]
shift = layer(shiftedDia)
rightshift = layer(shiftedDia)
a = macro(compose a ")
o = macro(compose o ")
u = macro(compose u ")
s = macro(compose s s)
e = macro(compose = e)
[shiftedDia]
a = macro(compose A ")
o = macro(compose O ")
u = macro(compose U ")

View file

@ -1,100 +0,0 @@
#
# /etc/pacman.conf
#
# See the pacman.conf(5) manpage for option and repository directives
#
# GENERAL OPTIONS
#
[options]
# The following paths are commented out with their default values listed.
# If you wish to use different paths, uncomment and update the paths.
#RootDir = /
#DBPath = /var/lib/pacman/
#CacheDir = /var/cache/pacman/pkg/
#LogFile = /var/log/pacman.log
#GPGDir = /etc/pacman.d/gnupg/
#HookDir = /etc/pacman.d/hooks/
HoldPkg = pacman glibc
#XferCommand = /usr/bin/curl -L -C - -f -o %o %u
#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u
#CleanMethod = KeepInstalled
Architecture = auto
# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup
#IgnorePkg =
#IgnoreGroup =
#NoUpgrade =
#NoExtract =
# Misc options
UseSyslog
Color
#NoProgressBar
CheckSpace
VerbosePkgLists
ParallelDownloads = 5
# By default, pacman accepts packages signed by keys that its local keyring
# trusts (see pacman-key and its man page), as well as unsigned packages.
SigLevel = Required DatabaseOptional
LocalFileSigLevel = Optional
#RemoteFileSigLevel = Required
# NOTE: You must run `pacman-key --init` before first using pacman; the local
# keyring can then be populated with the keys of all official Arch Linux
# packagers with `pacman-key --populate archlinux`.
#
# REPOSITORIES
# - can be defined here or included from another file
# - pacman will search repositories in the order defined here
# - local/custom mirrors can be added here or in separate files
# - repositories listed first will take precedence when packages
# have identical names, regardless of version number
# - URLs will have $repo replaced by the name of the current repo
# - URLs will have $arch replaced by the name of the architecture
#
# Repository entries are of the format:
# [repo-name]
# Server = ServerName
# Include = IncludePath
#
# The header [repo-name] is crucial - it must be present and
# uncommented to enable the repo.
#
# The testing repositories are disabled by default. To enable, uncomment the
# repo name header and Include lines. You can add preferred servers immediately
# after the header, and they will be used before the default mirrors.
#[testing]
#Include = /etc/pacman.d/mirrorlist
[core]
Include = /etc/pacman.d/mirrorlist
[extra]
Include = /etc/pacman.d/mirrorlist
#[community-testing]
#Include = /etc/pacman.d/mirrorlist
[community]
Include = /etc/pacman.d/mirrorlist
# If you want to run 32 bit applications on your x86_64 system,
# enable the multilib repositories as required here.
#[multilib-testing]
#Include = /etc/pacman.d/mirrorlist
[multilib]
Include = /etc/pacman.d/mirrorlist
# An example of a custom package repository. See the pacman manpage for
# tips on creating your own repositories.
#[custom]
#SigLevel = Optional TrustAll
#Server = file:///home/custompkgs

View file

@ -1,3 +0,0 @@
[Sleep]
HibernateDelaySec=120min
SuspendEstimationSec=30min

View file

@ -1 +0,0 @@
ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ATTRS{idVendor}=="0000", ATTRS{idProduct}=="3825", ATTR{power/wakeup}="disabled"

View file

@ -1,97 +0,0 @@
#!/usr/bin/env bash
BOOTSTRAP_DIR=${BOOTSTRAP_DIR:-$(pwd)/bootstrap}
INPUTFILES=$(find "${BOOTSTRAP_DIR}" -type f -name 'packages*.tsv')
OUTPUTFILE=${BOOTSTRAP_DIR}/packages_testing.tsv
pkg_all=$(pacman -Qqett)
pkg_repo=$(pacman -Qqn)
pkg_aur=$(pacman -Qqm)
while getopts "nvhf:" opt; do
case "$opt" in
n) DRYRUN=true ;;
v) VERBOSE=true ;;
f) OUTPUTFILE="$OPTARG" ;;
h | *)
{
printf "\nUpdate the list of installed packages.\n\nWill compare packages committed to the dotfile repository\nand those currently installed (on an Arch system, using pacman).\nUpdates the list of committed packages in repository\nand prints out the differences as a diff.\n\nOptions:\n\n\t-h\tDisplay this help.\n\t-v\tShow verbose information.\n\t-n\tPrint out changes without changing anything (dry-run).\n"
exit 1
}
;;
esac
done
# get all existing written packages
if [ -n "$INPUTFILES" ]; then
INPUT=$(cat $INPUTFILES | grep -v -e '^Name Description Source Target' | sort)
else
INPUT=""
fi
print_msg() {
# shellcheck disable=2059
[ -n "$VERBOSE" ] && printf "$@"
}
# tsv file:
# packagename, description, source, target
# toot a toot manager A D
if [ -f "${OUTPUTFILE}_TEMP" ]; then
rm "${OUTPUTFILE}_TEMP"
fi
touch "${OUTPUTFILE}_TEMP"
# create new package list
for pkg in $pkg_all; do
source=""
if echo "$pkg_repo" | grep -F -q -x "$pkg"; then
source="R"
elif echo "$pkg_aur" | grep -F -q -x "$pkg"; then
source="A"
else
echo "ERROR: The package $pkg could not be found in repositories or AUR."
exit 1
fi
desc=$(pacman -Qs "$pkg" | grep -A1 --color "local/$pkg\s" | tail -n1)
#remove leading whitespace
desc="${desc#"${desc%%[![:space:]]*}"}"
target=""
found_line=$(echo "$INPUT" | grep -e "^$pkg")
if [ -n "$found_line" ]; then
target=$(echo "$found_line" | cut -f4)
print_msg "Updating pkg: %s:%s from: %s, for: %s\n" "$pkg" "$desc" "$source" "$target"
else
print_msg "Adding pkg: %s:%s from: %s, for: %s\n" "$pkg" "$desc" "$source" "$target"
fi
printf "%s\t%s\t%s\t%s\n" "$pkg" "$desc" "$source" "$target" >>"${OUTPUTFILE}_TEMP"
done
# notify on any removed packages
while read -r line; do
if ! echo "$line" | cut -f1 | xargs -I _ grep -F -q -x _ <(echo "$pkg_all"); then
printf "REMOVED: %s\n" "$line"
fi
done <<<"<(echo $INPUT | tail +2)"
# show file changes
if [ -f "$OUTPUTFILE"_TEMP ]; then
changes=$(diff --color=always -y --suppress-common-lines <(echo "$INPUT") <(sort "$OUTPUTFILE"_TEMP | tail -n+2))
printf "FILE CHANGES:\n=============\n%s" "$changes"
fi
# actually write changes to file
if [ -z "$DRYRUN" ]; then
while IFS= read -r line; do
sed -i -e "/^${line//\//\\/}$/d" "$OUTPUTFILE"_TEMP
done <<< "$INPUT"
cat <(printf "Name\tDescription\tSource\tTarget\n") "${OUTPUTFILE}_TEMP" > "$OUTPUTFILE"
fi
rm "${OUTPUTFILE}_TEMP"

View file

@ -1,105 +0,0 @@
# Configuration for flavours
# https://github.com/Misterio77/flavours
#
# This file should contain a [[items]] section for each application you want themed
# You can also set a shell (outside items) on which to run hooks
# Check flavours repository for more information and examples
# Explanation and default values for keys:
# # Through which shell command hooks will run. The command will be replaced in '{}'
shell = "bash -c '{}'"
#
# [[items]]
# # File to inject to, supports tilde and env var expansion. required
# file = "~/.config/example"
# # Template to use. required
# template = "example"
#
# # Subtemplate to use
# subtemplate = "default"
# # If not rewriting, on which line (usually a comment) to start replacing
# start = "# Start flavours"
# # If not rewriting, on which line (usually a comment) to stop replacing
# end = "# End flavours"
# # Should we rewrite the entire file, instead of using the above delimiters?
# rewrite = false
# # Command to execute after injecting (goes through shell)
# hook = ""
# # Whether this hook should be executed when flavours is ran with lightweight flag
# light = true
[[items]]
template = "waybar"
file = "~/.local/state/waybar/colorscheme.css"
rewrite = true
light = false
hook = "killall -SIGUSR2 waybar"
[[items]]
# Uses custom nvim template to work together with
# RRethy base16 neovim plugin
template = "nvim"
file = "~/.local/state/nvim/colorscheme.lua"
rewrite = true
[[items]]
# For newer wezterm versions (missing cursor= field)
# make use of my custom wezterm template
template = "wezterm"
file = "~/.local/state/wezterm/colors.toml"
rewrite = true
[[items]]
template = "zathura"
file = "~/.local/state/zathura/colors.config"
rewrite = true
[[items]]
template = "qutebrowser"
subtemplate = "minimal"
file = "~/.local/state/qutebrowser/colorscheme.py"
rewrite = true
hook = "pgrep -x qutebrowser && qutebrowser :config-source"
# CSS Webpage styling in qutebrowser
[[item]]
file = "~/.config/qutebrowser/stylesheets/stylesheet.css"
template = "styles"
subtemplate = "css-variables"
rewrite = false
start = "/* Start flavours */"
end = "/* End flavours */"
[[items]]
# MAKO DOES NOT SUPPORT INCLUDES YET
template = "mako"
file = "~/.config/mako/config"
light = false
rewrite = false
start = "# Start flavours"
end = "# End flavours"
hook = "killall mako"
[[items]]
# SIOYEK does not support includes afaik
template = "sioyek"
file = "~/.config/sioyek/prefs_user.config"
rewrite = false
start = "# START FLAVOURS"
end = "# END FLAVOURS"
[[items]]
# additionally requires style = base16 to be set
# in the [GENERAL] section of ~/.config/vimiv/vimiv.conf
template = "vimiv"
file = "~/.config/vimiv/styles/base16"
rewrite = true
[[items]]
template = "fzf"
subtemplate = "sh"
file = "~/.config/sh/env.d/fzf-base16.sh"
rewrite = true
hook = "source ~/.config/sh/env.d/fzf-base16.sh"

View file

@ -1,9 +0,0 @@
# Scheme name: {{scheme-name}}
# Scheme system: {{scheme-system}}
# Scheme author: {{scheme-author}}
# Template author: Tinted Theming (https://github.com/tinted-theming)
export FZF_DEFAULT_OPTS="$FZF_DEFAULT_OPTS"\
" --color=bg+:#{{base01-hex}},bg:#{{base00-hex}},spinner:#{{base0C-hex}},hl:#{{base0D-hex}}"\
" --color=fg:#{{base04-hex}},header:#{{base0D-hex}},info:#{{base0A-hex}},pointer:#{{base0C-hex}}"\
" --color=marker:#{{base0C-hex}},fg+:#{{base06-hex}},prompt:#{{base0A-hex}},hl+:#{{base0D-hex}}"

View file

@ -1,42 +0,0 @@
-- base16-nvim (https://github.com/wincent/base16-nvim)
-- by Greg Hurrell (https://github.com/wincent)
-- based on
-- base16-vim (https://github.com/chriskempson/base16-vim)
-- by Chris Kempson (https://github.com/chriskempson)
-- using nvim-base16 neovim plugin
-- by RRethy (https://github.com/RRethy/nvim-base16)
-- {{scheme-name}} scheme by {{scheme-author}}
local function exists(plugin)
local status, lib = pcall(require, plugin)
if(status) then return true end
return false
end
if exists("mini.base16") then
require('mini.base16').setup({
palette = {
base00 = '#{{base00-hex}}',
base01 = '#{{base01-hex}}',
base02 = '#{{base02-hex}}',
base03 = '#{{base03-hex}}',
base04 = '#{{base04-hex}}',
base05 = '#{{base05-hex}}',
base06 = '#{{base06-hex}}',
base07 = '#{{base07-hex}}',
base08 = '#{{base08-hex}}',
base09 = '#{{base09-hex}}',
base0A = '#{{base0A-hex}}',
base0B = '#{{base0B-hex}}',
base0C = '#{{base0C-hex}}',
base0D = '#{{base0D-hex}}',
base0E = '#{{base0E-hex}}',
base0F = '#{{base0F-hex}}'
},
})
end
if exists("lualine") then
require("lualine").setup()
end
-- vim: filetype=lua

View file

@ -1,20 +0,0 @@
# base16-sioyek (https://github.com/loiccoyle/base16-sioyek)
# by Loic Coyle
# {{scheme-name}} scheme by{{scheme-author}}
custom_background_color #{{base00-hex}}
custom_color_mode_empty_background_color #{{base00-hex}}
custom_text_color #{{base06-hex}}
page_separator_color #{{base00-hex}}
search_highlight_color #{{base0A-hex}}
status_bar_color #{{base00-hex}}
status_bar_text_color #{{base06-hex}}
ui_text_color #{{base06-hex}}
ui_selected_text_color #{{base06-hex}}
ui_background_color #{{base01-hex}}
ui_selected_background_color #{{base03-hex}}
visual_mark_color {{base03-dec-r}} {{base03-dec-g}} {{base03-dec-b}} 0.2
text_highlight_color #{{base03-hex}}
link_highlight_color #{{base0D-hex}}
synctex_highlight_color #{{base08-hex}}

View file

@ -1,44 +0,0 @@
# Base16 {{scheme-name}} - wezterm color config
# Scheme by {{scheme-author}}
[colors]
foreground = "#{{base05-hex}}"
background = "#{{base00-hex}}"
cursor_bg = "#{{base05-hex}}"
cursor_border = "#{{base05-hex}}"
selection_bg = "#{{base05-hex}}"
selection_fg = "#{{base00-hex}}"
ansi = [
"#{{base00-hex}}",
"#{{base08-hex}}",
"#{{base0B-hex}}",
"#{{base0A-hex}}",
"#{{base0D-hex}}",
"#{{base0E-hex}}",
"#{{base0C-hex}}",
"#{{base05-hex}}"
]
brights = [
"#{{base03-hex}}",
"#{{base08-hex}}",
"#{{base0B-hex}}",
"#{{base0A-hex}}",
"#{{base0D-hex}}",
"#{{base0E-hex}}",
"#{{base0C-hex}}",
"#{{base07-hex}}"
]
[colors.tab_bar]
background = "#{{base00-hex}}"
[colors.tab_bar.inactive_tab]
bg_color = "#{{base00-hex}}"
fg_color = "#{{base05-hex}}"
[colors.tab_bar.active_tab]
bg_color = "#{{base05-hex}}"
fg_color = "#{{base00-hex}}"
[colors.tab_bar.new_tab]
bg_color = "#{{base05-hex}}"
fg_color = "#{{base00-hex}}"

View file

@ -1,32 +0,0 @@
profile docked {
output "LG Electronics W2442 0x000574FD" position 1920,0
output "LG Electronics W2442 0x000574E1" position 0,0
output eDP-1 disable
exec notify-send "💻 Display changed" "Applying docked LG profile"
}
profile docked {
output "Goldstar Company Ltd W2442 0x000574FD" position 1920,0
output "Goldstar Company Ltd W2442 0x000574E1" position 0,0
output eDP-1 disable
exec notify-send "💻 Display changed" "Applying docked Goldstar profile"
}
profile dockedall {
output "LG Electronics W2442 0x000574FD" position 1920,0
output "LG Electronics W2442 0x000574E1" position 0,0
output eDP-1 enable position 960,1080
exec notify-send "💻 Display changed" "Applying docked 3-screen profile"
}
profile portable {
output "LG Electronics W2442 0x000574FD" disable
output "LG Electronics W2442 0x000574E1" disable
output eDP-1 enable position 0,0
exec notify-send "💻 Display changed" "Applying portable profile"
}
profile portable {
output eDP-1 enable position 0,0
exec notify-send "💻 Display changed" "Applying portable profile"
}

View file

@ -1,27 +0,0 @@
sort=-time
layer=overlay
width=300
height=110
border-size=2
border-radius=15
max-icon-size=64
default-timeout=5000
ignore-timeout=1
font=monospace 14
# Intentionally left empty, automatically filled by flavours
# on switching theme.
# Start flavours
# End flavours
[urgency=critical]
#on-notify=exec mpv /usr/share/sounds/freedesktop/stereo/message.oga
default-timeout=0
[mode=do-not-disturb]
invisible=1
[category=mpd]
default-timeout=2000
group-by=category

View file

@ -1,322 +0,0 @@
#!/usr/bin/env sh
mod="Mod4"
modemod="Mod1"
term=${TERMINAL:-foot}
layout="filtile"
time_to_lockscreen=300
time_to_screendim=600
time_to_suspend=900
## OPTIONS
riverctl spawn "dbus-update-activation-environment SEATD_SOCK DISPLAY WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=river"
riverctl focus-follows-cursor normal
riverctl set-cursor-warp on-output-change
riverctl hide-cursor when-typing enabled
riverctl attach-mode bottom
# Set background and border color
riverctl background-color 0x000000
riverctl border-width 1
riverctl border-color-focused 0xffffff
riverctl border-color-unfocused 0x586e75
# Set repeat rate
riverctl set-repeat 75 300
# Make certain views start floating
riverctl rule-add -app-id float float
# riverctl rule-add -title "popup title with spaces" float
# # Set app-ids and titles of views which should use client side decorations
riverctl rule-add -app-id "gedit" csd
riverctl rule-add -app-id "org.pwmt.zathura" csd
## DEBUG
# Reload river configuration
riverctl map normal $mod+Shift F12 spawn "$HOME/.config/river/init"
## HOTKEYS
# close focused view
riverctl map normal $mod+Shift C close
# Open terminal
riverctl map normal $mod Return spawn "$term"
# Open floating terminal
riverctl map normal $mod+Control Return spawn "$term -e --class float"
# Open run menu
riverctl map normal $mod Space spawn "bemenu-run"
# Toggle status bar
riverctl map normal $mod F7 spawn "killall -SIGUSR1 waybar"
# Switch to lockscreen
riverctl map normal $mod X spawn "lockscreen"
# Open logout script
riverctl map normal $mod backspace spawn "powermenu"
# Open Bookmark search
riverctl map normal None XF86Search spawn "qutedmenu"
riverctl map normal $mod+Shift O spawn "qutedmenu"
# Clipboard history
riverctl map normal $mod+Shift Space spawn "clipman pick --tool=bemenu"
riverctl map normal $mod+Shift+Control Space spawn "clipman clear --all"
# Open floating calculator
riverctl map normal $mod+Shift R spawn "$term -e --class float qalc"
# Open emoji picker
riverctl map normal $mod+Shift E spawn "bemoji -nt"
# Open translation helper
riverctl map normal $mod+Shift T spawn "bemenu-translate"
# Open item from library
riverctl map normal $mod+Shift L spawn "papis -s picktool dmenu open"
# Desktop theming
# shellcheck disable=SC2016
riverctl map normal $mod+Shift S spawn 'flavourchoose'
# Password dropdown frontend
riverctl map normal $mod+Shift P spawn "pass-pick"
# File upload
riverctl map normal $mod+Shift U spawn "$term -e --class float sharefile | xargs notify-send"
# Open recent downloads
riverctl map normal $mod+Shift D spawn "recently-downloaded"
# # Screenshot
riverctl map normal None Print spawn "screenshot"
riverctl map normal Shift Print spawn "screenshot | sharefile -"
riverctl map normal $mod Print spawn "screenshot region"
riverctl map normal $mod+Shift Print spawn "screenshot region | sharefile -"
# control notification daemon
riverctl map normal $mod N spawn "makoctl dismiss"
riverctl map normal $mod+Shift N spawn "makoctl dismiss --all"
riverctl map normal $mod+Control N spawn "makoctl restore"
# MOVEMENT
# focus the next/previous view in the layout stack
riverctl map normal $mod J focus-view next
riverctl map normal $mod K focus-view previous
# swap the focused view with the next/previous view in the layout stack
riverctl map normal $mod+Shift J swap next
riverctl map normal $mod+Shift K swap previous
# bump the focused view to the top of the layout stack
riverctl map normal $mod+Shift Return zoom
# change layout orientation
riverctl map normal $mod Up send-layout-cmd $layout "main-location top"
riverctl map normal $mod Right send-layout-cmd $layout "main-location right"
riverctl map normal $mod Down send-layout-cmd $layout "main-location bottom"
riverctl map normal $mod Left send-layout-cmd $layout "main-location left"
# snap views to screen edges
riverctl map normal $mod+Control H snap left
riverctl map normal $mod+Control J snap down
riverctl map normal $mod+Control K snap up
riverctl map normal $mod+Control L snap right
# Mod+F to toggle fullscreen
riverctl map normal $mod F toggle-fullscreen
# if we are running filtile we also have access to monocle mode
if [ "$layout" = "filtile" ]; then
riverctl map normal $mod+Shift F spawn "riverctl send-layout-cmd $layout monocle"
fi
riverctl map normal $mod+Shift v toggle-float
# shellcheck disable=SC2016
# Make all connected outputs show the desktop and no windows at all
riverctl map normal $mod+Shift M spawn 'for i in $(wlopm | wc -l); do riverctl set-focused-tags $((1 << 10)); riverctl focus-output next; done; riverctl set-focused-tags $((1 << 10)); riverctl focus-output next'
riverctl map normal $mod+Shift F10 spawn "riverctl send-layout-cmd $layout '--tags all --output all view-padding 0'"
riverctl map normal $mod F10 spawn "riverctl send-layout-cmd $layout '--tags all --output all view-padding 6'"
# Mod + Left Mouse Button to move views
riverctl map-pointer normal $mod BTN_LEFT move-view
# Mod + Right Mouse Button to resize views
riverctl map-pointer normal $mod BTN_RIGHT resize-view
### Begin resize and moving mode, for floating windows
riverctl declare-mode interact_float
riverctl map normal $modemod R enter-mode interact_float
riverctl map interact_float $modemod R enter-mode normal
riverctl map interact_float None Escape enter-mode normal
# toggle float
riverctl map interact_float $mod+Shift v toggle-float
# move views around screen
riverctl map -repeat interact_float None H move left 100
riverctl map -repeat interact_float None J move down 100
riverctl map -repeat interact_float None K move up 100
riverctl map -repeat interact_float None L move right 100
# resize views on screen
riverctl map -repeat interact_float $mod H resize horizontal -100
riverctl map -repeat interact_float $mod J resize vertical 100
riverctl map -repeat interact_float $mod K resize vertical -100
riverctl map -repeat interact_float $mod L resize horizontal 100
# decrease/increase the main ratio of layout
riverctl map interact_float $mod+Shift H send-layout-cmd $layout "main-ratio -0.05"
riverctl map interact_float $mod+Shift L send-layout-cmd $layout "main-ratio +0.05"
# increment/decrement the main layout
riverctl map interact_float $mod+Shift J send-layout-cmd $layout "main-count +1"
riverctl map interact_float $mod+Shift K send-layout-cmd $layout "main-count -1"
# snap views to screen edges
riverctl map interact_float $mod+Control H snap left
riverctl map interact_float $mod+Control J snap down
riverctl map interact_float $mod+Control K snap up
riverctl map interact_float $mod+Control L snap right
### End resize and moving mode
## Passthrough mode which disables all other mappings and only retains the single
# mapping to return to normal mode. Useful for some full screen applications
# which should capture everything, or for testing nested wayland compositors.
riverctl declare-mode passthrough
riverctl map normal $mod F11 enter-mode passthrough
riverctl map passthrough $mod F11 enter-mode normal
# focus the next/previous output
riverctl map normal $mod Period focus-output next
riverctl map normal $mod Comma focus-output previous
# send the focused view to the next/previous output
riverctl map normal $mod+Shift Period send-to-output next
riverctl map normal $mod+Shift Comma send-to-output previous
# set up 10 tags (with '0' opening the 10th one)
for i in $(seq 0 9); do
tags="$((1 << (i - 1)))"
if [ "$i" -eq 0 ]; then tags="$((1 << 9))"; fi
# Mod+[1-9] to focus tag [0-8]
riverctl map normal $mod "$i" set-focused-tags $tags
# Mod+Shift+[1-9] to tag focused view with tag [0-8]
riverctl map normal $mod+Shift "$i" set-view-tags $tags
# Mod+Ctrl+[1-9] to toggle focus of tag [0-8]
riverctl map normal $mod+Control "$i" toggle-focused-tags $tags
# Mod+Shift+Ctrl+[1-9] to toggle tag [0-8] of focused view
riverctl map normal $mod+Shift+Control "$i" toggle-view-tags $tags
done
# focus all tags
all_tags=$(((1 << 32) - 1))
riverctl map normal $mod equal set-focused-tags $all_tags
# tag focused view with all tags
riverctl map normal $mod+Shift equal set-view-tags $all_tags
# Various media key mapping examples for both normal and locked mode which do
# not have a modifier
for mode in normal locked; do
# Eject the optical drive
riverctl map $mode None XF86Eject spawn 'eject -T'
riverctl map -repeat $mode None XF86AudioRaiseVolume spawn 'pactl set-sink-volume @DEFAULT_SINK@ +5%'
riverctl map -repeat $mode None XF86AudioLowerVolume spawn 'pactl set-sink-volume @DEFAULT_SINK@ -5%'
riverctl map $mode None XF86AudioMute spawn 'pactl set-sink-mute @DEFAULT_SINK@ toggle'
# Control MPRIS aware media players with playerctl (https://github.com/altdesktop/playerctl)
riverctl map $mode None XF86AudioMedia spawn 'playerctl play-pause'
riverctl map $mode None XF86AudioPlay spawn 'playerctl play-pause'
riverctl map $mode None XF86AudioPrev spawn 'playerctl previous'
riverctl map $mode None XF86AudioNext spawn 'playerctl next'
# You can control screen backlight brighness with light (https://github.com/haikarainen/light); but we prefer brightnessctl
riverctl map -repeat $mode None XF86MonBrightnessUp spawn 'brightnessctl set 10%+'
riverctl map -repeat $mode None XF86MonBrightnessDown spawn 'brightnessctl set 10%-'
done
# The scratchpad will live on an unused tag. Which tags are used depends on your
# config, but rivers default uses the first 9 tags.
scratch_tag=$((1 << 20))
# Toggle showing the scratchpad
riverctl map normal $mod grave toggle-focused-tags ${scratch_tag}
# Send windows to the scratchpad
riverctl map normal $mod+Shift grave set-view-tags ${scratch_tag}
# Set spawn tagmask to ensure new windows don't have the scratchpad tag unless
# explicitly set.
all_but_scratch_tag=$((((1 << 32) - 1) ^ scratch_tag))
riverctl spawn-tagmask ${all_but_scratch_tag}
# set up scratch pad for todo and 'drop-down' terminal
# call scratchpads to current workspace -- scratchpads started on i3 starting (see end of file)
# bindsym $mod+t [class="scratchpad" title="dropdown-todo"] scratchpad show
# bindsym $mod+Shift+Return [class="scratchpad" title="dropdown-terminal"] scratchpad show
## INPUT
# device (touchscreen)
# enable touch clicking for touchpads
for pad in $(riverctl list-inputs | grep -i touchpad); do
riverctl input "$pad" events enabled
riverctl input "$pad" tap enabled
done
for pad in $(riverctl list-inputs | grep -i touchscreen); do
riverctl input "$pad" events enabled
riverctl input "$pad" tap enabled
riverctl input "$pad" drag enabled
riverctl input "$pad" pointer-accel 0.5
done
setxkbmap -option "compose:menu"
# start dynamic display configuration
[ "$(pidof kanshi)" -eq 0 ] || riverctl spawn kanshi
# set a nice wallpaper
if exist swww; then
riverctl spawn "swww init"
outputs=$(swww query | cut -d':' -f1)
if [ "$(echo "$outputs" | grep -c -e '^DP')" -eq 2 ] && [ -e "$HOME/pictures/wall_r.jpg" ]; then
swww img -o "$(echo "$outputs" | head -n1)" "$HOME/pictures/wall_l.jpg"
swww img -o "$(echo "$outputs" | tail -n1)" "$HOME/pictures/wall_r.jpg"
elif [ -e "$HOME/pictures/wall.jpg" ]; then
swww img "$HOME/pictures/wall.jpg"
fi
fi
# start status bar
killall waybar
riverctl spawn waybar
# start redshift-like sundown warming using current location or standard values
killall wlsunset
loc=$(curl ipinfo.io | grep -e '"loc": ' | sed -e 's/^.*"loc": "\(.*\)",$/\1/')
if [ -n "$loc" ]; then
riverctl spawn "wlsunset -l \"$(echo "$loc" | cut -d, -f1)\" -L \"$(echo "$loc" | cut -d, -f2)\""
else
riverctl spawn "wlsunset -S \"09:00\" -s \"21:00\" -d \"3600\""
fi
unset loc
# start screen idle locking/dimming/sleep tool
killall swayidle
riverctl spawn "swayidle \
timeout ${time_to_suspend} \"[ $(cat /sys/class/power_supply/AC/online) -eq 0 ] && systemctl suspend-then-hibernate\"
timeout ${time_to_screendim} \"wlopm --off '*'\" \
resume \"wlopm --on '*'\" \
timeout ${time_to_lockscreen} \"pidof waylock || lockscreen\" \
after-resume \"wlopm --on '*'\" \
before-sleep \"pidof waylock || lockscreen\" &"
killall clipman
riverctl spawn "wl-paste -t text --watch clipman store"
# bash ~/.config/bin/gtktheme # setting our gtk variables
# killall polkit-gnome-authentication-agent-1
# /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 &
# start layouting engine
killall $layout
riverctl spawn "$layout\
--tags all --output all main-ratio 0.65,\
--tags all --output all view-padding 6,\
--tags all --output all outer-padding 0,\
--tags all --output all smart-padding on,\
--tags all --output all smart-padding 0"
# River will send the process group of the init executable SIGTERM on exit.
riverctl default-layout $layout
brightnessctl set 70%

View file

@ -1,3 +0,0 @@
#!/usr/bin/env sh
export XKB_DEFAULT_OPTIONS='compose:menu'

View file

@ -1,192 +0,0 @@
{
"layer": "top",
"modules-left": ["river/tags", "custom/events", "custom/vidl", "river/window"],
"modules-center": ["clock", "custom/media"],
"modules-right": ["river/mode", "custom/wireguard", "custom/archupdates", "pulseaudio", "backlight", "network", "cpu", "memory", "temperature", "battery", "tray"],
"custom/archupdates": {
"format": "{} {icon}",
"format-alt-click": "right",
"format-icons": {
"default": ""
},
"return-type": "json",
"exec": "~/.config/waybar/modules/archupdates 5 json",
"interval": 3600,
"on-click": "$TERMINAL start --class float topgrade"
},
"backlight": {
"device": "intel_backlight",
"format": "{percent}% {icon}",
"format-icons": ["滋", "", "", ""],
"on-scroll-up": "brightnessctl set 1%+",
"on-scroll-down": "brightnessctl set 1%-"
},
"battery": {
"format": "{capacity}% {icon}",
"format-alt":"{capacity}% ({time}) {icon}",
"format-alt-click": "click-right",
"format-icons": ["", "", "", "", ""],
"interval": 60,
"states": {
"warning": 30,
"critical": 15
},
},
"clock": {
"format-alt": "{:%a, %d. %b %H:%M}",
"format-alt-click": "click-right",
"on-click": "gsimplecal"
},
"cpu": {
"interval": 10,
"format": "{usage}% ",
"max-length": 10,
"states": {
"warning": 50,
"critical": 80
},
"on-click": "$TERMINAL start --class float top",
"on-click-right": "$TERMINAL start --class float glances"
},
"custom/events": {
"exec-if": "command -v khal >/dev/null 2>&1",
"exec": "~/.config/waybar/modules/khal.py 2>/dev/null",
"return-type": "json",
"interval": 300,
"on-click": "$TERMINAL start --class float ikhal",
"format": "{icon}{}",
"format-icons": {
"event": " ",
"no-event": "",
},
},
"memory": {
"interval": 30,
"format": "{avail:0.1f}G ",
"format-alt": "{used:0.1f}G/{total:0.1f}G ",
"format-alt-click": "click-right",
"max-length": 10
},
"mpd": {
"format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}",
"format-disconnected": "ﱙ",
"format-stopped": "",
"interval": 10,
"consume-icons": {
"on": " " // Icon shows only when "consume" is on
},
"random-icons": {
"on": " "
},
"repeat-icons": {
"on": " "
},
"single-icons": {
"on": "1 "
},
"state-icons": {
"paused": "",
"playing": "",
},
"tooltip-format": "{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ",
"tooltip-format-disconnected": "MPD (disconnected)"
},
"custom/media": {
"format": "{icon}{}",
"format-alt-click": "right",
"return-type": "json",
"format-icons": {
"Playing": " ",
"Paused": " ",
},
"escape": true,
"max-length":70,
"exec": "playerctl -a metadata --format '{\"text\": \"\", \"tooltip\": \"{{playerName}} : {{markup_escape(title)}}\", \"alt\": \"{{status}}\", \"class\": \"{{status}}\"}' -F",
"exec-if": "command -v playerctl >/dev/null 2>&1",
"on-click": "playerctl play-pause",
"on-click-right": "playerctl stop",
},
"network": {
"format": "{ifname}",
"format-wifi": "{signalStrength}% ",
"format-ethernet": "{ipaddr}/{cidr} 󰈀",
"format-disconnected": "󰖪",
"tooltip-format": "{ifname} via {gwaddr} 󰈁",
"tooltip-format-wifi": "{essid}: {bandwidthDownBits}-{bandwidthUpBits} ({signalStrength}%)  {ifname}",
"tooltip-format-ethernet": "{ifname} 󰈀",
"tooltip-format-disconnected": "Disconnected",
"max-length": 50,
"on-click": "$TERMINAL start --class float nmtui",
// "on-click-right": "sudo rfkill toggle wlan"
},
"pulseaudio": {
"format": "{volume}% {icon}",
"format-bluetooth": "{volume}% {icon} ",
"format-muted": "",
"format-icons": {
"headphone": "",
"hands-free": "",
"headset": "󰋎",
"phone": "",
"portable": "",
"car": "",
"default": ["", ""]
},
"scroll-step": 1,
"on-click": "$TERMINAL start --class float pulsemixer",
"on-scroll-up": "pactl set-sink-volume @DEFAULT_SINK@ +1%",
"on-scroll-down": "pactl set-sink-volume @DEFAULT_SINK@ -1%"
},
"river/tags": {
"num-tags": 10,
"tag-labels": [ "", "", "", "", "", "", "", "", "", "" ]
},
"river/mode": {
"format": "{} ",
},
"river/window": {
"format": " {}",
"max-length": 70
},
"temperature": {
// "thermal-zone": 2,
"hwmon-path": "/sys/class/hwmon/hwmon5/temp1_input",
"critical-threshold": 80,
// "format-critical": "{temperatureC}° ",
"format": "{temperatureC}° ",
"on-click": "$TERMINAL start --class float watch sensors"
},
"tray": {
"icon-size": 21,
"spacing": 10
},
"custom/weather": {
"exec": "curl 'https://wttr.in/?format=%t'",
"exec-if": "command -v curl >/dev/null 2>&1",
"interval": 3600
},
"custom/wireguard": {
"format": "{icon}",
"format-icons": {
"default": "",
"pia": "󰖂",
"netbird": "󱗆"
},
"exec": "~/.config/waybar/modules/wireguard json",
"exec-if": "command -v nmcli >/dev/null 2>&1",
"return-type": "json",
"signal": 6,
"interval": 60,
},
"custom/vidl": {
"format": "{icon}{}",
"format-alt-click": "right",
"format-icons": {
"default": " "
},
"exec": "wc -l ~/.local/share/vidl/vidl_queue | cut -d' ' -f1",
"exec-if": "[ -f ~/.local/share/vidl/vidl_queue ]",
"interval": 5,
"on-click": "$TERMINAL start --class float nvim ~/.local/share/vidl/vidl_queue"
},
}

View file

@ -1,58 +0,0 @@
#!/bin/sh
#
# Check for available archupdates and return their number.
# Checks both repositories and aur,
# returns empty string when 0 packages are available, so
# that polybar simply displays nothing.
# Can be used to generate json-like output for waybar.
#
# dependencies: yay, (pacman-contrib optional)
# optional: jq
#
# Takes 2 arguments:
# Takes an optional integer argument, which is the minimum
# numer of package updates for an answer to be returned.
min_upd=${1:-0}
# Takes as second optional argument the output format
# Valid value is "json", everything else returns plain-text.
# json output requires jq.
format=${2:-plain}
# prefer checkupdates since it allows checking w/o partial upgrade
if command -v "checkupdates" >/dev/null; then
updates_repo="$(checkupdates 2>&1)"
fi
# fall back to yay, but be aware it will not find everything
# if checkupdates finds nothing or returns an error
if [ "$updates_repo" = "" ] || [ -z "${updates_repo##*==> ERROR: Cannot fetch updates*}" ]; then
updates_repo="$(yay -Qun 2>/dev/null)"
fi
updates_repo=$(echo "$updates_repo" | wc -l)
updates_aur="$(yay -Qum 2>/dev/null | wc -l)"
# updates_aur=$(cower -u 2> /dev/null | wc -l)
# updates_aur=$(trizen -Su --aur --quiet | wc -l)
# updates_aur=$(pikaur -Qua 2> /dev/null | wc -l)
# updates_aur=$(rua upgrade --printonly 2> /dev/null | wc -l)
updates=$((updates_repo + updates_aur))
text="${updates}"
alt="${updates_repo}|${updates_aur}"
tooltip="Repositories: ${updates_repo} | AUR: ${updates_aur}"
[ "$updates" -gt "$min_upd" ] && class="available" || class="empty"
if [ "$format" = "json" ]; then
printf "{\"text\": \"%s\", \"alt\": \"%s\", \"tooltip\": \"%s\", \"class\": \"%s\"}" \
"$text" \
"$alt" \
"$tooltip" \
"$class"
exit
fi
if [ "$updates" -gt "$min_upd" ]; then
echo "$updates"
else
echo ""
fi

View file

@ -1,39 +0,0 @@
#!/usr/bin/env python
# from https://gist.github.com/bjesus/178a9bd3453470d74803945dbbf9ed40
# List upcoming khal events in simple json container fit for waybar
#
# Hovering over the item displays all upcoming
# The icon changes if there are events today, and displays the
# closest upcoming one.
import datetime
import json
import subprocess
from html import escape
data = {}
today = datetime.date.today().strftime("%Y-%m-%d")
next_week = (datetime.date.today() + datetime.timedelta(days=10)).strftime("%Y-%m-%d")
output = subprocess.check_output("khal list now " + next_week, shell=True)
output = output.decode("utf-8")
lines = output.split("\n")
new_lines: list[str] = []
for line in lines:
clean_line = escape(line).split(" ::")[0]
if len(clean_line) and clean_line[0] not in ["0", "1", "2"]:
clean_line = "\n<b>" + clean_line + "</b>"
new_lines.append(clean_line)
output = "\n".join(new_lines).strip()
data["alt"] = "no-event"
data["tooltip"] = output
if today in output:
data["text"] = output.split("\n")[1]
data["alt"] = "event"
print(json.dumps(data))

View file

@ -1,165 +0,0 @@
#!/usr/bin/env bash
# nmcli WireGuard abstraction layer for use with my waybar module and rofi custom menu script
#
# requires nmcli on your path
# install to the same directory as wireguard-rofi.sh
#
# usage: ./wireguard.sh [menu|toggle NAME]
# no argument: print current connections
# json: print waybar-ready json output
# menu: print all connections
# toggle NAME: toggle connection NAME
if ! command -v nmcli >/dev/null 2>&1; then
echo "err: nmcli not found"
exit 1
fi
nargs=$#
showmenu="no"
dotoggle="no"
printjson="no"
if [[ $nargs == 1 ]]; then
if [[ $1 == "menu" ]]; then
showmenu="yes"
elif [[ $1 == "json" ]]; then
printjson="yes"
fi
elif [[ $nargs == 2 ]]; then
if [[ $1 == "toggle" ]]; then
dotoggle="yes"
conn="$2"
fi
fi
nmclicmd="nmcli connection"
wgconns="$nmclicmd show"
wgactive="$wgconns --active"
connected=()
available=()
function print_as_json() {
text="${1%% |*}" # prints out name of first vpn it finds
alt="${1%%:*}"
tooltip="${1}"
[ -n "$1" ] && class="connected" || class="disconnected"
printf "{\"text\": \"%s\", \"alt\": \"%s\", \"tooltip\": \"%s\", \"class\": \"%s\"}" \
"$text" \
"$alt" \
"$tooltip" \
"$class"
}
function get_conns {
while read -r name _ type device; do
if [[ $type != "wireguard" && ($type != "tun" || $device != "proton0") ]]; then
continue
fi
if [[ $device != "--" ]]; then
while read -r key value; do
if [[ $key != "ipv4.addresses:" ]]; then
continue
fi
connected+=("$name: $value")
done < <($wgconns "$name")
else
available+=("$name")
fi
done < <($1)
}
function get_pia {
if ! command -v piactl >/dev/null 2>&1; then
return 1
fi
status=$(piactl get connectionstate)
if [[ $status = "Connected" ]]; then
connected+=("pia: $(piactl get vpnip)")
fi
}
function get_netbird {
if ! command -v netbird >/dev/null 2>&1 || [ "$(systemctl is-active netbird)" == "inactive" ]; then
return 1
fi
status="$(netbird status)"
if echo "$status" | grep -q "^Signal: Connected"; then
connected+=("netbird:$(echo "$status" | grep "^NetBird IP:" | cut -d':' -f2)")
fi
}
function print_conns {
local first="yes"
local array_print="$1[@]"
local array_print=("${!array_print}")
if [[ $2 == "list" ]]; then
for c in "${array_print[@]}"; do
output="$1: $c"
done
else
output=""
for c in "${array_print[@]}"; do
if [[ "$first" != "yes" ]]; then
output+=" | "
fi
output+="$c"
first="no"
done
fi
if [[ "$printjson" == "yes" ]]; then
print_as_json "$output"
else
echo "$output"
fi
}
function array_contains {
local array_has="$1[@]"
local array_has=("${!array_has}")
local element="$2"
for e in "${array_has[@]}"; do
if [[ "$e" == *"$element"* ]]; then
echo "yes"
return
fi
done
echo "no"
}
if [[ $nargs == 0 ]] || [[ $printjson = "yes" ]]; then
get_pia
get_netbird
get_conns "$wgactive"
print_conns connected
elif [[ $showmenu == "yes" ]]; then
get_pia
get_netbird
get_conns "$wgconns"
print_conns connected "list"
print_conns available "list"
elif [[ $dotoggle == "yes" ]]; then
get_pia
get_netbird
get_conns "$wgconns"
if [[ "$(array_contains connected "$conn")" == "yes" ]]; then
$nmclicmd down "$conn"
elif [[ "$(array_contains available "$conn")" == "yes" ]]; then
$nmclicmd up "$conn"
else
echo "err: connection not found"
exit 1
fi
else
echo "err: wrong args"
exit 1
fi

View file

@ -1,162 +0,0 @@
* {
border: none;
border-radius: 0;
min-height: 0;
font-family: Cantarell, Signika, Iosevka Nerd Font, Iosevka, monospace;
}
window#waybar {
font-size: 15px;
color: @base0F;
background-color: @base00;
border-bottom: 1px solid @base01;
transition-property: background-color;
transition-duration: .5s;
}
window#waybar.hidden {
opacity: 0.2;
}
#tags button {
font-size:17px;
font-weight:900;
background-color: transparent;
color: @base03;
margin: 0px;
padding: 0px 5px;
/* Use box-shadow instead of border so the text isn't offset */
}
/* /1* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect *1/ */
#tags button:hover {
background: rgba(0, 0, 0, 0.2);
/* box-shadow: inset 0 -1px #d5c4a1; */
box-shadow: inset 0 0;
}
#tags button.occupied {
font-weight: 400;
color: @base05;
}
#tags button.focused {
font-weight: 400;
color: @base0D;
}
#tags button.urgent {
color: @base0C;
}
#clock,
#battery,
#cpu,
#memory,
#disk,
#temperature,
#backlight,
#network,
#pulseaudio,
#tray,
#mode,
#idle_inhibitor,
#mpd,
#window,
#custom-archupdates,
#custom-wireguard,
#custom-events,
#custom-vidl,
#custom-media {
padding: 0 10px;
margin: 0 5px;
color: @base05;
background-color: @base01;
}
/* If workspaces is the leftmost module, omit left margin */
.modules-left > widget:first-child > #tags {
margin-left: 0;
}
/* If workspaces is the rightmost module, omit right margin */
.modules-right > widget:last-child > #tags {
margin-right: 0;
}
#battery.charging, #battery.plugged {
background-color: @base02;
}
/* Mark active output through highlighted window background */
#window {
background-color: transparent;
}
#window.focused {
background-color: @base01;
}
#battery.warning {
background-color: @base09;
color: @base00;
}
@keyframes blink {
to {
background-color: @base08;
color: @base00;
}
}
#battery.critical:not(.charging) {
color: @base05;
background-color: @base00;
animation-name: blink;
animation-duration: 0.5s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-direction: alternate;
}
#cpu.warning {
color: @base00;
background-color: @base0A;
}
#cpu.critical {
color: @base05;
background-color: @base08;
}
#custom-archupdates.empty {
background-color: transparent;
color: transparent;
font-size: 0;
margin: 0;
padding: 0;
}
#custom-wireguard.disconnected {
background-color: transparent;
color: transparent;
font-size: 0;
margin: 0;
padding: 0;
}
#temperature.critical {
background-color: @base08;
}
#tray > .passive {
-gtk-icon-effect: dim;
}
#tray > .needs-attention {
-gtk-icon-effect: highlight;
}
#mpd.disconnected {
background-color: transparent;
color: transparent;
font-size: 0;
margin: 0;
padding: 0;
}
@import "/home/marty/.local/state/waybar/colorscheme.css";

View file

@ -1,26 +0,0 @@
#!/usr/bin/env sh
picker=dmenu
if exist bemenu; then
picker=bemenu
elif exist wofi; then
picker=wofi
elif exist rofi; then
picker=rofi
fi
list=$(flavours list -l)
flavour=$(printf "%s\nrandom\nlight" "$list" | "$picker")
if [ -z "$flavour" ]; then
return
elif [ "$flavour" = "random" ]; then
flavours apply '*'
elif [ "$flavour" = "light" ]; then
flavours apply '*light'
else
flavours apply "$flavour"
fi
if [ "$1" = '-v' ]; then
notify-send "Theme set" "set to: $flavour"
fi

View file

@ -1,48 +0,0 @@
#!/usr/bin/env sh
# Take a screenshot on wayland
# By default takes a screenshot of the whole desktop
# If 'region' or 'area' command is passed in will allow selecting a region to screenshot.
# Example: `screenshot region`
TIME="$(date +%Y-%m-%d-%H-%M-%S)"
readonly TIME
readonly TMPSCREENSHOTDIR="$HOME/.cache/screenshot"
readonly TMPIMGPATH="$TMPSCREENSHOTDIR/img-$TIME.png"
FULLSCREEN=true
if [ "$1" = "area" ] || [ "$1" = "region" ]; then
FULLSCREEN=false
fi
main() {
prepare_cache
take_screenshot "$FULLSCREEN"
if [ -n "$SCREENSHOT_POSTPROCESS" ]; then
eval "$SCREENSHOT_POSTPROCESS"
else
postprocess
fi
}
prepare_cache() {
if [ ! -d "$TMPSCREENSHOTDIR" ]; then
mkdir -p "$TMPSCREENSHOTDIR"
fi
}
take_screenshot() {
if $1; then
grim "$TMPIMGPATH"
else
grim -g "$(slurp)" "$TMPIMGPATH"
fi
}
postprocess() {
notify-send -i "$TMPIMGPATH" "Screenshot taken" "$TMPIMGPATH"
echo "$TMPIMGPATH" | wl-copy
echo "$TMPIMGPATH"
}
main "$@"

View file

@ -1,94 +0,0 @@
# Wayland desktop environment
Contains:
[riverwm](https://github.com/riverwm/river)
[waybar](https://github.com/Alexays/Waybar)
mako -- notification daemon
font settings
kanshi -- display output setup
The thoughts below are overhauled and fairly old - they are still based on my first days and weeks on wayland.
Takeaway is this: I love the river wm, waybar is unexciting but does what it's supposed to and the wayland environment is totally worth it.
---
My first foray into wayland is based on river,
a tiling window manager somewhat based on bspwm.
This is only a very work-in-progress README file.
Since wayland handles key presses and so on completely differently
from X,
I can't for example use sxhkd anymore which is a shame.
On the other hand, there is an amazing key *re* binding tool
(which also works under X I've now found out)
`keyd` which takes care of some X functionality (xcape) at a lower level.
I have not found a good replacement for `clutter`
(which automatically hides your mouse cursor after inactivity)
which is independent from the window manager.
I believe `swaywm` would include similar functionality, but `river` does not.
## River
River is set up to come close to my old i3 setup.
Of course, some mappings are different
(especially those for movement between windows),
but overall the keys map to the old ones.
Since the window manager now also takes over the task of compositor
and does not pass through all keys to all programs,
it takes over the role of `sxhkd` as well and summons other programs.
I am not entirely sure how I feel about this bundling of tasks into one application,
but so far it works.
Since river is also, mimicking bspwm, using an executable file
(any executable file)
as its configuration file it is also reasonable that the setup can be tamed and refactored better than a single i3 configuration file.
## Waybar
Waybar replaces the old [polybar](https://gitlab.com/marty-oehme/dotfiles/-/tree/89d1402b3e711c4aa473386e47e84f3593e5ae56/polybar) setup.
It displays the first 10 tags on its left,
with tags highlighted that are either occupied by windows or currently in focus.
In the center it displays a clock which can be clicked to open a simple calendar.
![Simple waybar configuration](.assets/waybar/simple.png)
To the right is where most of the info modules are:
If there are upcoming events listed for the khal application, it will display a calendar module here.
If music is playing through an mpris-compatible player, its status is shown here.
If a connection through wireguard or over a vpn tunnel is established, it is shown here.
Then, from left to right, audio, brightness, wifi, cpu, ram, temperature, and battery information are displayed.
Some displays have alternative display states, with for example the battery showing remaining time and ram information showing used and total available.
Clicking on:
* audio opens pulsemixer
* network opens nmtui
* cpu opens top (or glances on right-click)
* temperature shows sensors
## keyd
keyd is set up within `/etc/` and not in the dotfiles themselves.
If using the included `./install.sh` file, there is an option to also set up files outside the home directory, including keyd options.
It is configured through `/etc/keyd/default.cfg`.
Currently, it takes care of mapping `capslock` to both control and escape (depending on if its used alone or with other keys),
as well as adding some German characters that I am otherwise missing on my en_US keyboard.
Lastly, it allows easy clipboard pasting with the `insert` key.
## Swaybg
`swaybg` is used to set the wallpaper from the river configuration file.
## Missing
things not yet set up:
* [-] modes: media, academia (worth?)
* [ ] display current desktop mode in status bar

View file

@ -1 +0,0 @@
../udiskie.service

View file

@ -1,9 +0,0 @@
[Unit]
Description=Automated mounting of removable devices (udisks)
[Service]
ExecStart=/usr/bin/udiskie --config %h/.config/udiskie/config.yml
Restart=always
[Install]
WantedBy=default.target

View file

@ -1,9 +0,0 @@
program_options:
tray: auto
automount: true
notify: true
device_config:
# ignore any snap loopback devices
# see https://github.com/coldfix/udiskie/issues/180
- id_type: squashfs
ignore: true

View file

@ -1,9 +0,0 @@
# Removable disk configuration
This simple unit depends on `udiskie2` being installed and enables auto-mounting of any inserted removable media.
It will additionally *ignore* any snaps managed by `snapd`, since they would otherwise be detected as loopback devices.
Automatically installs a `systemd` service which is also enabled to start up on system start (as a user service).
The end result is `udiskie` running in the background and automatically mounting any inserted media,
which will then also show its tray icon so that it can be quickly unmounted as well.

433
dunst/.config/dunst/dunstrc Normal file
View file

@ -0,0 +1,433 @@
[global]
### Display ###
# Which monitor should the notifications be displayed on.
monitor = 0
# Display notification on focused monitor. Possible modes are:
# mouse: follow mouse pointer
# keyboard: follow window with keyboard focus
# none: don't follow anything
#
# "keyboard" needs a window manager that exports the
# _NET_ACTIVE_WINDOW property.
# This should be the case for almost all modern window managers.
#
# If this option is set to mouse or keyboard, the monitor option
# will be ignored.
follow = mouse
# The geometry of the window:
# [{width}]x{height}[+/-{x}+/-{y}]
# The geometry of the message window.
# The height is measured in number of notifications everything else
# in pixels. If the width is omitted but the height is given
# ("-geometry x2"), the message window expands over the whole screen
# (dmenu-like). If width is 0, the window expands to the longest
# message displayed. A positive x is measured from the left, a
# negative from the right side of the screen. Y is measured from
# the top and down respectively.
# The width can be negative. In this case the actual width is the
# screen width minus the width defined in within the geometry option.
geometry = "300x5-30+20"
# Show how many messages are currently hidden (because of geometry).
indicate_hidden = yes
# Shrink window if it's smaller than the width. Will be ignored if
# width is 0.
shrink = no
# The transparency of the window. Range: [0; 100].
# This option will only work if a compositing window manager is
# present (e.g. xcompmgr, compiz, etc.).
transparency = 20
# The height of the entire notification. If the height is smaller
# than the font height and padding combined, it will be raised
# to the font height and padding.
notification_height = 0
# Draw a line of "separator_height" pixel height between two
# notifications.
# Set to 0 to disable.
separator_height = 2
# Padding between text and separator.
padding = 8
# Horizontal padding.
horizontal_padding = 8
# Defines width in pixels of frame around the notification window.
# Set to 0 to disable.
frame_width = 3
# Defines color of the frame around the notification window.
frame_color = "#aaaaaa"
# Define a color for the separator.
# possible values are:
# * auto: dunst tries to find a color fitting to the background;
# * foreground: use the same color as the foreground;
# * frame: use the same color as the frame;
# * anything else will be interpreted as a X color.
separator_color = auto
# Sort messages by urgency.
sort = yes
# Don't remove messages, if the user is idle (no mouse or keyboard input)
# for longer than idle_threshold seconds.
# Set to 0 to disable.
# A client can set the 'transient' hint to bypass this. See the rules
# section for how to disable this if necessary
idle_threshold = 120
### Text ###
font = Monospace 10
# The spacing between lines. If the height is smaller than the
# font height, it will get raised to the font height.
line_height = 0
# Possible values are:
# full: Allow a small subset of html markup in notifications:
# <b>bold</b>
# <i>italic</i>
# <s>strikethrough</s>
# <u>underline</u>
#
# For a complete reference see
# <http://developer.gnome.org/pango/stable/PangoMarkupFormat.html>.
#
# strip: This setting is provided for compatibility with some broken
# clients that send markup even though it's not enabled on the
# server. Dunst will try to strip the markup but the parsing is
# simplistic so using this option outside of matching rules for
# specific applications *IS GREATLY DISCOURAGED*.
#
# no: Disable markup parsing, incoming notifications will be treated as
# plain text. Dunst will not advertise that it has the body-markup
# capability if this is set as a global setting.
#
# It's important to note that markup inside the format option will be parsed
# regardless of what this is set to.
markup = full
# The format of the message. Possible variables are:
# %a appname
# %s summary
# %b body
# %i iconname (including its path)
# %I iconname (without its path)
# %p progress value if set ([ 0%] to [100%]) or nothing
# %n progress value if set without any extra characters
# %% Literal %
# Markup is allowed
format = "<b>%s</b>\n%b"
# Alignment of message text.
# Possible values are "left", "center" and "right".
alignment = left
# Show age of message if message is older than show_age_threshold
# seconds.
# Set to -1 to disable.
show_age_threshold = 60
# Split notifications into multiple lines if they don't fit into
# geometry.
word_wrap = yes
# When word_wrap is set to no, specify where to make an ellipsis in long lines.
# Possible values are "start", "middle" and "end".
ellipsize = middle
# Ignore newlines '\n' in notifications.
ignore_newline = no
# Stack together notifications with the same content
stack_duplicates = true
# Hide the count of stacked notifications with the same content
hide_duplicate_count = false
# Display indicators for URLs (U) and actions (A).
show_indicators = yes
### Icons ###
# Align icons left/right/off
icon_position = off
# Scale larger icons down to this size, set to 0 to disable
max_icon_size = 32
# Paths to default icons.
icon_path = /usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/
### History ###
# Should a notification popped up from history be sticky or timeout
# as if it would normally do.
sticky_history = yes
# Maximum amount of notifications kept in history
history_length = 20
### Misc/Advanced ###
# dmenu path.
dmenu = /usr/bin/dmenu -p dunst:
# Browser for opening urls in context menu.
browser = xdg-open
# Always run rule-defined scripts, even if the notification is suppressed
always_run_script = true
# Define the title of the windows spawned by dunst
title = Dunst
# Define the class of the windows spawned by dunst
class = Dunst
# Print a notification on startup.
# This is mainly for error detection, since dbus (re-)starts dunst
# automatically after a crash.
startup_notification = false
# Manage dunst's desire for talking
# Can be one of the following values:
# crit: Critical features. Dunst aborts
# warn: Only non-fatal warnings
# mesg: Important Messages
# info: all unimportant stuff
# debug: all less than unimportant stuff
verbosity = mesg
# Define the corner radius of the notification window
# in pixel size. If the radius is 0, you have no rounded
# corners.
# The radius will be automatically lowered if it exceeds half of the
# notification height to avoid clipping text and/or icons.
corner_radius = 1
### Legacy
# Use the Xinerama extension instead of RandR for multi-monitor support.
# This setting is provided for compatibility with older nVidia drivers that
# do not support RandR and using it on systems that support RandR is highly
# discouraged.
#
# By enabling this setting dunst will not be able to detect when a monitor
# is connected or disconnected which might break follow mode if the screen
# layout changes.
force_xinerama = false
### mouse
# Defines action of mouse event
# Possible values are:
# * none: Don't do anything.
# * do_action: If the notification has exactly one action, or one is marked as default,
# invoke it. If there are multiple and no default, open the context menu.
# * close_current: Close current notification.
# * close_all: Close all notifications.
mouse_left_click = close_current
mouse_middle_click = close_all
mouse_right_click = do_action
# Experimental features that may or may not work correctly. Do not expect them
# to have a consistent behaviour across releases.
[experimental]
# Calculate the dpi to use on a per-monitor basis.
# If this setting is enabled the Xft.dpi value will be ignored and instead
# dunst will attempt to calculate an appropriate dpi value for each monitor
# using the resolution and physical size. This might be useful in setups
# where there are multiple screens with very different dpi values.
per_monitor_dpi = false
[shortcuts]
# Shortcuts are specified as [modifier+][modifier+]...key
# Available modifiers are "ctrl", "mod1" (the alt-key), "mod2",
# "mod3" and "mod4" (windows-key).
# Xev might be helpful to find names for keys.
# Close notification.
close = ctrl+space
# Close all notifications.
close_all = ctrl+shift+space
# Redisplay last message(s).
# On the US keyboard layout "grave" is normally above TAB and left
# of "1". Make sure this key actually exists on your keyboard layout,
# e.g. check output of 'xmodmap -pke'
history = ctrl+grave
# Context menu.
context = ctrl+shift+period
[urgency_low]
# IMPORTANT: colors have to be defined in quotation marks.
# Otherwise the "#" and following would be interpreted as a comment.
background = "#222222"
foreground = "#888888"
timeout = 10
# Icon for notifications with low urgency, uncomment to enable
#icon = /path/to/icon
[urgency_normal]
background = "#285577"
foreground = "#ffffff"
timeout = 10
# Icon for notifications with normal urgency, uncomment to enable
#icon = /path/to/icon
[urgency_critical]
background = "#900000"
foreground = "#ffffff"
frame_color = "#ff0000"
timeout = 0
# Icon for notifications with critical urgency, uncomment to enable
#icon = /path/to/icon
# Every section that isn't one of the above is interpreted as a rules to
# override settings for certain messages.
#
# Messages can be matched by
# appname (discouraged, see desktop_entry)
# body
# category
# desktop_entry
# icon
# match_transient
# msg_urgency
# stack_tag
# summary
#
# and you can override the
# background
# foreground
# format
# frame_color
# fullscreen
# new_icon
# set_stack_tag
# set_transient
# timeout
# urgency
#
# Shell-like globbing will get expanded.
#
# Instead of the appname filter, it's recommended to use the desktop_entry filter.
# GLib based applications export their desktop-entry name. In comparison to the appname,
# the desktop-entry won't get localized.
#
# SCRIPTING
# You can specify a script that gets run when the rule matches by
# setting the "script" option.
# The script will be called as follows:
# script appname summary body icon urgency
# where urgency can be "LOW", "NORMAL" or "CRITICAL".
#
# NOTE: if you don't want a notification to be displayed, set the format
# to "".
# NOTE: It might be helpful to run dunst -print in a terminal in order
# to find fitting options for rules.
# Disable the transient hint so that idle_threshold cannot be bypassed from the
# client
#[transient_disable]
# match_transient = yes
# set_transient = no
#
# Make the handling of transient notifications more strict by making them not
# be placed in history.
#[transient_history_ignore]
# match_transient = yes
# history_ignore = yes
# fullscreen values
# show: show the notifications, regardless if there is a fullscreen window opened
# delay: displays the new notification, if there is no fullscreen window active
# If the notification is already drawn, it won't get undrawn.
# pushback: same as delay, but when switching into fullscreen, the notification will get
# withdrawn from screen again and will get delayed like a new notification
#[fullscreen_delay_everything]
# fullscreen = delay
[fullscreen_show_critical]
msg_urgency = critical
fullscreen = show
#[espeak]
# summary = "*"
# script = dunst_espeak.sh
#[script-test]
# summary = "*script*"
# script = dunst_test.sh
#[ignore]
# # This notification will not be displayed
# summary = "foobar"
# format = ""
#[history-ignore]
# # This notification will not be saved in history
# summary = "foobar"
# history_ignore = yes
#[skip-display]
# # This notification will not be displayed, but will be included in the history
# summary = "foobar"
# skip_display = yes
#[signed_on]
# appname = Pidgin
# summary = "*signed on*"
# urgency = low
#
#[signed_off]
# appname = Pidgin
# summary = *signed off*
# urgency = low
#
#[says]
# appname = Pidgin
# summary = *says*
# urgency = critical
#
#[twitter]
# appname = Pidgin
# summary = *twitter.com*
# urgency = normal
#
#[stack-volumes]
# appname = "some_volume_notifiers"
# set_stack_tag = "volume"
#
# vim: ft=cfg
# Base16 tomorrow-night - dunst color config
frame_color = "#c5c8c6"
separator_color = "#c5c8c6"
[base16_low]
msg_urgency = low
background = "#282a2e"
foreground = "#969896"
[base16_normal]
msg_urgency = normal
background = "#373b41"
foreground = "#c5c8c6"
[base16_critical]
msg_urgency = critical
background = "#cc6666"
foreground = "#e0e0e0"
# Base16End tomorrow-night - dunst color config

View file

@ -1,6 +1,7 @@
<?xml version='1.0'?> <?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'> <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig> <fontconfig>
<!-- Replacements from http://bohoomil.com/doc/05-fonts/ (until ibfonts-meta-extended) -->
<alias> <alias>
<family>serif</family> <family>serif</family>
<prefer><family>Heuristica</family></prefer> <prefer><family>Heuristica</family></prefer>
@ -11,7 +12,7 @@
</alias> </alias>
<alias> <alias>
<family>monospace</family> <family>monospace</family>
<prefer><family>Iosevka Nerd Font</family></prefer> <prefer><family>Iosevka</family></prefer>
</alias> </alias>
<alias> <alias>
<family>fantasy</family> <family>fantasy</family>
@ -21,27 +22,40 @@
<family>cursive</family> <family>cursive</family>
<prefer><family>Comic Neue</family></prefer> <prefer><family>Comic Neue</family></prefer>
</alias> </alias>
<!-- more advanced replacements (replacing many fonts with open alternatives) see spark/fonts/local.conf -->
<match target="font"> <match target="font">
<edit name="antialias" mode="assign"> <edit name="antialias" mode="assign">
<bool>true</bool> <bool>true</bool>
</edit> </edit>
</match>
<match target="font">
<edit name="rgba" mode="assign"> <edit name="rgba" mode="assign">
<const>rgb</const> <const>rgb</const>
</edit> </edit>
</match>
<match target="font">
<edit name="lcdfilter" mode="assign"> <edit name="lcdfilter" mode="assign">
<const>lcddefault</const> <const>lcddefault</const>
</edit> </edit>
</match>
<match target="font">
<edit name="hinting" mode="assign"> <edit name="hinting" mode="assign">
<bool>true</bool> <bool>true</bool>
</edit> </edit>
</match>
<match target="font">
<edit name="hintstyle" mode="assign"> <edit name="hintstyle" mode="assign">
<const>hintfull</const> <const>hintfull</const>
</edit> </edit>
</match>
<match target="font">
<edit name="autohint" mode="assign"> <edit name="autohint" mode="assign">
<bool>false</bool> <bool>false</bool>
</edit> </edit>
</match>
<match target="pattern">
<edit name="dpi" mode="assign"> <edit name="dpi" mode="assign">
<double>93</double> <double>92</double>
</edit> </edit>
</match> </match>
</fontconfig> </fontconfig>

18
git/.config/git/config Normal file
View file

@ -0,0 +1,18 @@
[user]
email = marty.oehme@gmail.com
name = Marty Oehme
signingkey = 0CCB0526EFB9611A
[filter "lfs"]
clean = git-lfs clean -- %f
smudge = git-lfs smudge -- %f
process = git-lfs filter-process
required = true
[alias]
ignore = "!gitignore -f"
pushmerge = "push -o merge_request.merge_when_pipeline_succeeds" # see https://docs.gitlab.com/ce/user/project/push_options.html#merge-when-pipeline-succeeds-alias
[url "git@github.com:"]
insteadOf = https://github.com
[url "git@gitlab.com:"]
insteadOf = https://gitlab.com
[commit]
gpgsign = true

View file

@ -0,0 +1,58 @@
#!/usr/bin/env sh
# git alias
if exist git; then
alias g='git'
alias ga='git add'
alias gaa='git add --all'
alias gai='git add -i'
alias gb='git branch'
alias gbd='git branch -d'
alias gc='git commit -v'
alias gc!='git commit -v --amend'
alias gcn!='git commit -v --no-edit --amend'
alias gcm='git checkout master'
alias gcd='git checkout develop'
alias gcb='git checkout -b'
alias gco='git checkout'
alias gd='git diff'
alias gds='git diff --staged'
alias gi='git ignore'
alias glog='git log --stat'
alias glg='git log --oneline --decorate --graph'
alias glga='git log --oneline --decorate --graph --remotes --all'
alias glgp='git log --stat -p'
alias gf='git fetch'
alias gl='git pull'
alias gpn='git push --dry-run'
alias gp='git push'
alias gpf!='git push --force'
alias gpm='git pushmerge'
alias grv='git remote -v'
alias grs='git restore --staged'
alias grs!='git restore'
alias grbi='git rebase -i'
alias grbc='git rebase --continue'
alias gst='git status'
autoload -Uz is-at-least
if is-at-least 2.13 "$(git --version 2>/dev/null | awk '{print $3}')"; then
alias gsta='git stash push'
else
alias gsta='git stash save'
fi
alias gstp='git stash pop'
alias gstl='git stash list'
fi

30
git/README.md Normal file
View file

@ -0,0 +1,30 @@
# Git module
[git](https://git-scm.com/) - a distributed version control system
## What's in this module
[[_TOC_]]
## Global git settings
This is probably the first thing that needs to be customized, since it points to a different identity for each git user.
## Basic git command aliases
This module contains a heap of aliases to every-day git commands.
Most of them follow a two-to-three letter combination of things to do which corresponds to the mnemonic of the longer git command.
As such, they are mostly similar to those found in the Oh My Zsh [git plugin](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git)
Examples of some common aliases are `alias ga=git add`, `alias gst=git status`, `alias gp=git push`, `alias gl=git pull`.
## Gitignore generation script
Adds a `gitignore` script which pulls relevant .gitignore lines from [gitignore.io](https://www.gitignore.io) and sends them to standard out, or creates a .gitignore file in the current directory.
[![asciicast](https://asciinema.org/a/298616.svg)](https://asciinema.org/a/298616)
To show usage of the script run `gitignore -h`. It is fully equipped with zsh auto completions, which will pull a list of all available ignore modules from the website to complete with.
It can alternatively be run through git itself by invoking `git ignore`, which will always generate a .gitignore file in the current directory.
When fzf is installed invoke the script without any arguments to generate a fzf-searchable list of git definitions to create. Select multiple definitions with <tab>.

View file

@ -0,0 +1,20 @@
root:
askformore: false
autoclip: true
autoprint: false
autoimport: true
autosync: false
check_recipient_hash: false
cliptimeout: 45
concurrency: 1
editrecipients: false
nocolor: false
noconfirm: true
nopager: false
notifications: true
path: gpgcli-gitcli-fs+file:///home/marty/.local/share/gopass/passwords
recipient_hash:
.gpg-id: 353145383639394133414439344537334641363830434541313341433036443341444345413339410a423038433639313143453343313539463643373831324546334641423133324534463946343433390aa69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26
safecontent: false
usesymbols: false
mounts: {}

13
home/.bash_profile Normal file
View file

@ -0,0 +1,13 @@
#
# ~/.bash_profile
#
if [ -d $XDG_CONFIG_HOME/shell/login.d ]; then
for file in $XDG_CONFIG_HOME/shell/login.d/*.sh; do
source $file
done
fi
[[ -f ~/.bashrc ]] && . ~/.bashrc
export PATH="$HOME/.cargo/bin:$PATH"

23
home/.bashrc Normal file
View file

@ -0,0 +1,23 @@
#
# ~/.bashrc
#
# If not running interactively, don't do anything
[[ $- != *i* ]] && return
# Load files from rc.d
if [ -d $XDG_CONFIG_HOME/shell/rc.d ]; then
for file in $XDG_CONFIG_HOME/shell/rc.d/*.sh; do
source $file
done
fi
# Load files from bashrc.d
if [ -d $XDG_CONFIG_HOME/shell/bashrc.d ]; then
for file in $XDG_CONFIG_HOME/shell/bashrc.d/*.bash; do
source $file
done
fi
alias ls='ls --color=auto'
PS1='[\u@\h \W]\$ '

View file

@ -3,4 +3,4 @@
# make zsh source the correct directory # make zsh source the correct directory
export XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-"$HOME/.config"} export XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-"$HOME/.config"}
ZDOTDIR="${XDG_CONFIG_HOME:-"$HOME/.config"}/zsh" ZDOTDIR="$XDG_CONFIG_HOME/zsh"

236
i3/.config/i3/config Normal file
View file

@ -0,0 +1,236 @@
# This file has been auto-generated by i3-config-wizard(1).
# It will not be overwritten, so edit it as you like.
#
# Should you change your keyboard layout some time, delete
# this file and re-run i3-config-wizard(1).
#
# i3 config file (v4)
#
# Please see https://i3wm.org/docs/userguide.html for a complete reference!
set $mod Mod4
set $modemod Mod1
set $font "pango:Fira Code 8"
# Font for window titles. Will also be used by the bar unless a different font
# is used in the bar {} block below.
#font pango:monospace 8
font $font
workspace_auto_back_and_forth yes
# This font is widely installed, provides lots of unicode glyphs, right-to-left
# text rendering and scalability on retina/hidpi displays (thanks to pango).
#font pango:DejaVu Sans Mono 8
# Before i3 v4.8, we used to recommend this one as the default:
# font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
# The font above is very space-efficient, that is, it looks good, sharp and
# clear in small sizes. However, its unicode glyph coverage is limited, the old
# X core fonts rendering does not support right-to-left and this being a bitmap
# font, it doesnt scale on retina/hidpi displays.
# Use Mouse+$mod to drag floating windows to their wanted position
floating_modifier $mod
# kill focused window
bindsym $mod+Shift+c kill
# change focus
bindsym $mod+h focus left
bindsym $mod+j focus down
bindsym $mod+k focus up
bindsym $mod+l focus right
# alternatively, you can use the cursor keys:
bindsym $mod+Left focus left
bindsym $mod+Down focus down
bindsym $mod+Up focus up
bindsym $mod+Right focus right
# move focused window
bindsym $mod+Shift+h move left
bindsym $mod+Shift+j move down
bindsym $mod+Shift+k move up
bindsym $mod+Shift+l move right
# alternatively, you can use the cursor keys:
bindsym $mod+Shift+Left move left
bindsym $mod+Shift+Down move down
bindsym $mod+Shift+Up move up
bindsym $mod+Shift+Right move right
# split in horizontal orientation
bindsym $mod+Shift+s split v
# split in vertical orientation
bindsym $mod+s split h
# enter fullscreen mode for the focused container
bindsym $mod+f fullscreen toggle
# change container layout (stacked, tabbed, toggle split)
bindsym $mod+Shift+w layout stacking
bindsym $mod+w layout tabbed
bindsym $mod+e layout toggle split
# toggle tiling / floating
bindsym $mod+Shift+v floating toggle
# change focus between tiling / floating windows
bindsym $mod+v focus mode_toggle
# focus the parent/child container
bindsym $mod+Shift+a focus parent
bindsym $mod+a focus child
# make a (floating) window stick to all workspaces
bindsym $mod+ctrl+v sticky toggle
# set up scratch pad for todo and 'drop-down' terminal
# call scratchpads to current workspace -- scratchpads started on i3 starting (see end of file)
bindsym $mod+t [class="Alacritty" instance="scratchpad" title="todo.md"] scratchpad show
bindsym $mod+Shift+Return [class="Alacritty" instance="scratchpad" title="dropdown"] scratchpad show
# GAP MANAGEMENT
# disable titles and borders, necessary for i3gaps to work apparently
for_window [class="^.*"] border pixel 0
# by default set no gaps when multiple windows are on the workspace
gaps inner 0
gaps outer 0
# increase/decrease inner gapping
bindsym $mod+shift+g gaps inner current plus 10
bindsym $mod+g gaps inner current minus 10
# increase/decrease outer gapping
bindsym $mod+shift+b gaps outer current plus 10
bindsym $mod+b gaps outer current minus 10
# Define names for default workspaces for which we configure key bindings later on.
# We use variables to avoid repeating the names in multiple places.
set $ws1 "1"
set $ws2 "2"
set $ws3 "3"
set $ws4 "4"
set $ws5 "5"
set $ws6 "6"
set $ws7 "7"
set $ws8 "8"
set $ws9 "9"
set $ws10 "10"
# switch to workspace
bindsym $mod+1 workspace $ws1
bindsym $mod+2 workspace $ws2
bindsym $mod+3 workspace $ws3
bindsym $mod+4 workspace $ws4
bindsym $mod+5 workspace $ws5
bindsym $mod+6 workspace $ws6
bindsym $mod+7 workspace $ws7
bindsym $mod+8 workspace $ws8
bindsym $mod+9 workspace $ws9
bindsym $mod+0 workspace $ws10
# move focused container to workspace
bindsym $mod+Shift+1 move container to workspace $ws1
bindsym $mod+Shift+2 move container to workspace $ws2
bindsym $mod+Shift+3 move container to workspace $ws3
bindsym $mod+Shift+4 move container to workspace $ws4
bindsym $mod+Shift+5 move container to workspace $ws5
bindsym $mod+Shift+6 move container to workspace $ws6
bindsym $mod+Shift+7 move container to workspace $ws7
bindsym $mod+Shift+8 move container to workspace $ws8
bindsym $mod+Shift+9 move container to workspace $ws9
bindsym $mod+Shift+0 move container to workspace $ws10
# resize window (you can also use the mouse for that)
mode "resize" {
# These bindings trigger as soon as you enter the resize mode
# Pressing left will shrink the windows width.
# Pressing right will grow the windows width.
# Pressing up will shrink the windows height.
# Pressing down will grow the windows height.
bindsym h resize shrink width 10 px or 10 ppt
bindsym Shift+h resize shrink width 30 px or 30 ppt
bindsym j resize grow height 10 px or 10 ppt
bindsym Shift+j resize grow height 30 px or 30 ppt
bindsym k resize shrink height 10 px or 10 ppt
bindsym Shift+k resize shrink height 30 px or 30 ppt
bindsym l resize grow width 10 px or 10 ppt
bindsym Shift+l resize grow width 30 px or 30 ppt
# same bindings, but for the arrow keys
bindsym Left resize shrink width 10 px or 10 ppt
bindsym Down resize grow height 10 px or 10 ppt
bindsym Up resize shrink height 10 px or 10 ppt
bindsym Right resize grow width 10 px or 10 ppt
# back to normal: Enter or Escape or $mod+r
bindsym Return mode "default"
bindsym Escape mode "default"
bindsym $modemod+r mode "default"
}
set $mode_media "Media"
mode $mode_media {
# Pressing left will move 5s back
bindsym h exec playerctl position 5-
bindsym Shift+h exec playerctl position 15-
# Pressing down will move to the next file
bindsym j exec playerctl next
# Pressing up will move to the previous file
bindsym k exec playerctl previous
# Pressing right will move 5s forward
bindsym l exec playerctl position 5+
bindsym Shift+l exec playerctl position 30+
# Pressing p will play/pause current track
bindsym p exec playerctl play-pause
# Pressing p will play/pause current track
bindsym s exec playerctl stop
#TODO add option to open file, loop, shuffle, show/select players
# back to normal
bindsym Return mode "default"
bindsym Escape mode "default"
bindsym $modemod+m mode "default"
}
bindsym $modemod+r mode "resize"
bindsym $modemod+m mode $mode_media
# reload the configuration file
bindsym $mod+Shift+y reload
# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
bindsym $mod+Shift+r restart
# set a pretty wallpaper
exec_always --no-startup-id feh --bg-scale ~/pictures/wall.jpg
# launch polybar (script ensures only 1 instance existing at a time)
exec_always --no-startup-id polybar-launch simple-top
# default workspaces for most used apps
# assign [class="^qutebrowser$"] → number 1
# spotify needs for_window, see https://i3wm.org/docs/userguide.html#assign_workspace
assign [class="^spotify$"] → 10
assign [class="^Spotify$"] → 10
#fix for spotify not moving to workspace 10
for_window [class="^spotify$"] move to workspace 10
# set up scratch pad for todo and 'drop-down' terminal
# to be called to current workspace when needed
exec_always --no-startup-id alacritty --title "todo.md" --class scratchpad,Alacritty -e nvim ~/todo.md
exec_always --no-startup-id alacritty --title "dropdown" --class scratchpad,Alacritty
for_window [class="Alacritty" instance="scratchpad"] floating enable
for_window [class="Alacritty" instance="scratchpad"] move scratchpad
# autostart often used apps
# needs to be done like this to both automatically start the apps on correct workspace
# and not confine them there forever
exec $XDG_CONFIG_HOME/i3/scripts/i3-applications-autostart

View file

@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Wait for program coming up
wait_for_program() {
n=0
while true; do
# PID of last background command
if xdotool search --onlyvisible --pid $! 2>/dev/null; then
break
else
if [ $n -eq 200 ]; then
notify-send -u critical "Error during start: last program $! did not started fast enough"
break
else
n=$($n + 1)
sleep 0.1
fi
fi
done
}
i3-msg "workspace number 2"
alacritty &
wait_for_program
i3-msg "workspace number 10"
spotify &
wait_for_program
i3-msg "workspace number 9"
keybase &
wait_for_program
i3-msg "workspace number 1"
qutebrowser &
wait_for_program
i3-msg "workspace number 3"

View file

@ -2,137 +2,90 @@
# #
# install.sh # install.sh
# #
# Installs dotfiles and packages for my setup. # Installs dotfiles and packages for my setup
# Needs to be invoked from containing dotfile directory to work correctly.
# #
# Will first install yay, then all my used packages (read from bootstrap/packages.txt) # Will first install yay, then all my used packages (read from bootstrap/packages.csv)
# #
# Finally, symlinks all dotfiles into their correct locations using dotter # Finally, symlinks all dotfiles into their correct locations using stow
bootstrap_dir="${DOT_BOOTSTRAP_DIR:-./bootstrap}" bootstrap_dir="${BOOTSTRAP_DIRECTORY:-./_bootstrap}"
unattended_install="${DOT_UNATTENDED_INSTALL:-false}"
link_systemfiles="${DOT_LINK_SYSTEMFILES:-true}"
help() {
printf "Usage: install [-f|--force][-v|--version][-h|--help]\n\n-f Do not ask for any confirmations but force update and installation.\n"
exit "${1:-0}"
}
main() { main() {
local cmd="" local cmd=""
local ret=0 local ret=0
case "$1" in
-v | --version)
printf "Personal system bootstrap script.\n\nby Marty Oehme\n\nv0.2\n"
;;
-h | --help)
help 0
;;
-f | --force)
unattended_install=true
;;
*)
install
;;
esac
shift
$cmd "$@" case "$1" in
ret=$((ret + $?)) -v | --version)
exit $ret printf "Personal system bootstrap script.\n\n©Marty Oehme\n\nVersion: 0.1.1\n"
;;
-h | --help)
printf "Usage: install [-f|--force][-v|--version][-h|--help]\n\n-f Do not ask for any confirmations but force update and installation.\n"
;;
-f | --force)
install true
;;
*)
install false
;;
esac
shift
$cmd "$@"
ret=$((ret + $?))
exit $ret
} }
# takes default value (y/n), question, abort message as arguments
# automatically answers yes if unattended install
check_consent() { check_consent() {
if [ "$unattended_install" == "true" ]; then echo "This will take a while, install many packages and link dotfiles all over the place. Proceed [y/N]?"
true read -r yes
else if [[ "$yes" != y* ]]; then
[[ "$1" == "y" ]] && default_consent="[Y/n]" || default_consent="[y/N]" echo "Exiting."
printf "%b %b " "$2" "$default_consent" exit
read -r answer fi
if [[ "$1" == "n" ]] && [[ "$answer" != y* ]]; then
printf "%s\n" "$3"
false
elif [[ "$1" == "y" ]] && [[ "$answer" == n* ]]; then
printf "%s\n" "$3"
false
else
true
fi
fi
}
entry_question() {
check_consent n "This will take a while and install many packages and link dotfiles all over the place depending on your selections.\nYou need to be in the base directory of the dotfiles repository.\nProceed?" "Aborting." || exit
} }
enable_git_hooks() { enable_git_hooks() {
check_consent y "Should we enable git hooks for this repository, so that missing or additionally installed packages are automatically compared to the repository when committing?" "Not changing repository settings." || return if [ "$1" == "false" ]; then
git config --local core.hooksPath .githooks/ echo "Should we enable git hooks for this repository, so that installed packages are automatically compared when committing? [Y/n]"
echo "Changed repository settings." read -r no
} if [[ "$no" == n* ]]; then
echo "Not changing repository settings."
manage_dotfiles() { return
check_consent y "Link dot files?" "Not linking dotfiles." || return fi
check_consent n "Link system settings files? This will require sudo access but will not overwrite existing files." "Not touching system files." || link_systemfiles=false fi
if [ "$link_systemfiles" == "false" ]; then git config --local core.hooksPath .githooks/
dotter deploy echo "Changed repository settings."
echo "Linked dotfiles."
else
if [ -e "/etc/pacman.conf" ]; then
check_consent n "Found an existing pacman.conf file, installation will error if it exists. Remove file?" && run_elevated rm "/etc/pacman.conf"
fi
dotter deploy -l .dotter/systemwide.toml
echo "Linked dotfiles and system files."
fi
}
run_elevated() {
if command -v doas >/dev/null 2>&1; then
doas "$@"
elif command -v sudo >/dev/null 2>&1; then
sudo "$@"
fi
}
install_packages() {
check_consent n "Install pre-designated packages? This will take a while, install a lot of packages and require super user privileges." "Not installing packages." || return
if [ "$unattended_install" == "true" ]; then
"$bootstrap_dir"/install_packages.sh -f
else
"$bootstrap_dir"/install_packages.sh
fi
echo "Installed packages."
}
headline() {
len="${#1}"
target_len=85
side_len=$(((target_len - len) / 2))
for ((i = 1; i <= side_len; i++)); do printf '='; done
printf " %s " "$1"
for ((i = 1; i <= side_len; i++)); do printf '='; done
printf "\n"
} }
install() { install() {
if [ "$unattended_install" == false ] ; then unattended=$1
entry_question if ! "$unattended"; then
fi check_consent
fi
echo "====================== BEGINNING INSTALLATION ============================="
if ! "$unattended"; then
export BOOTSTRAP_PACKAGES="_bootstrap/packages.txt"
"$bootstrap_dir"/install_packages.sh
else
export BOOTSTRAP_PACKAGES="_bootstrap/packages.txt"
"$bootstrap_dir"/install_packages.sh -f
fi
unset BOOTSTRAP_PACKAGES
headline "BEGINNING PACKAGE INSTALLATION" echo "=================== BEGINNING DOTFILE MANAGEMENT =========================="
install_packages # get all top level directories, remove their slashes and dots
# finally get rid of .dot-directories, since they are for the repo not for my homedir
targets="$(find . -maxdepth 1 -type d | sed -e 's/^\.\/\(.*\)$/\1/' | sed -e '/^\./d')"
headline "BEGINNING DOTFILE MANAGEMENT" # shellcheck disable=2086
manage_dotfiles # -- for some reason stow only works with unqoted var expansion
stow -R ${targets} 2> >(grep -v 'Absolute/relative mismatch between Stow dir' 1>&2)
headline "ENABLING GIT REPOSITORY HOOKS" echo "================== ENABLING GIT REPOSITORY HOOKS =========================="
enable_git_hooks enable_git_hooks "$unattended"
echo "INSTALLATION FINISHED" echo "====================== INSTALLATION FINISHED =============================="
exit 0 exit 0
} }
main "$@" main "$@"

View file

@ -0,0 +1,193 @@
# Configuration file for libinput-gestures.
#
# The default configuration file exists at /etc/libinput-gestures.conf
# but a user can create a personal custom configuration file at
# ~/.config/libinput-gestures.conf.
#
# Lines starting with '#' and blank lines are ignored. Currently
# "gesture" and "device" configuration keywords are supported as
# described below. The keyword can optionally be appended with a ":" (to
# maintain compatibility with original format configuration files).
#
# Each gesture line has 3 [or 4] arguments separated by whitespace:
#
# action motion [finger_count] command
#
# where action and motion is either:
# swipe up
# swipe down
# swipe left
# swipe right
# pinch in
# pinch out
#
# command is the remainder of the line and is any valid shell command +
# arguments.
#
# finger_count is a single numeric digit and is optional (and is
# typically 3 or 4). If specified then the command is executed when
# exactly that number of fingers is used in the gesture. If not
# specified then the command is executed when that gesture is executed
# with any number of fingers. Gesture lines specified with finger_count
# have priority over the same gesture specified without any
# finger_count.
#
# Typically command will be xdotool, or wmctrl. See "man xdotool" for
# the many things you can action with that tool. Note that unfortunately
# xdotool does not work with native Wayland clients.
###############################################################################
# SWIPE GESTURES:
###############################################################################
# Gestures with 4 fingers: Move around desktops
# next dekstop
gesture swipe right 4 _internal ws_up
# previous desktop
gesture swipe left 4 _internal ws_down
# hide all windows (show desktop)
gesture swipe down 4 xdotool key Control_L+F12
# show all open windows
gesture swipe up 4 xdotool key Control_L+F10
# show desktop grid
gesture swipe right_down 3 xdotool key Control_L+F8
# show activity manager
gesture swipe left_down 3 xdotool key Super_L+q
# Show all open windows of desktop
gesture swipe up 3 xdotool key Control_L+F9
# minimize window (Super_L = Meta; Next = PgDown)
gesture swipe down 3 xdotool key Super_L+Next
# 45degree Gestures with 3 fingers: control tab & browsing behavior
# next tab
gesture swipe right 3 xdotool key Control_L+Tab
# previous tab
gesture swipe left 3 xdotool key Control_L+Shift+Tab
# new tab
gesture swipe right_up 3 xdotool key Control_L+t
# close tab
gesture swipe left_up 3 xdotool key Control_L+w
# Note the default is an "internal" command that uses wmctrl to switch
# workspaces and, unlike xdotool, works on both Xorg and Wayland (via
# XWayland). It also can be configured for vertical and horizontal
# switching over tabular workspaces, as per the example below. You can
# also add "-w" to the internal command to allow wrapping workspaces.
# Move to next workspace (works for GNOME/KDE/etc on Wayland and Xorg)
# gesture swipe up _internal ws_up
# NOTE ABOUT FINGER COUNT:
# The above command will configure this command for all fingers (i.e. 3
# for 4) but to configure it for 3 fingers only, change it to:
# gesture swipe up 3 _internal ws_up
# Then you can configure something else for 4 fingers or leave 4 fingers
# unconfigured. You can configure an explicit finger count like this for
# all example commands in this configuration file.
#
# gesture swipe up xdotool key super+Page_Down
# Move to prev workspace (works for GNOME/KDE/etc on Wayland and Xorg)
# gesture swipe down _internal ws_down
# gesture swipe down xdotool key super+Page_Up
# Browser go forward (works only for Xorg, and Xwayland clients)
# gesture swipe left xdotool key alt+Right
# Browser go back (works only for Xorg, and Xwayland clients)
# gesture swipe right xdotool key alt+Left
# NOTE: If you don't use "natural" scrolling direction for your touchpad
# then you may want to swap the above default left/right and up/down
# configurations.
# Optional extended swipe gestures, e.g. for browser tab navigation:
#
# Jump to next open browser tab
# gesture swipe right_up xdotool key control+Tab
#
# Jump to previous open browser tab
# gesture swipe left_up xdotool key control+shift+Tab
#
# Close current browser tab
# gesture swipe left_down xdotool key control+w
#
# Reopen and jump to last closed browser tab
# gesture swipe right_down xdotool key control+shift+t
# Example of 8 static workspaces, e.g. using KDE virtual-desktops,
# arranged in 2 rows of 4 across using swipe up/down/left/right to
# navigate in fixed planes. Must match how you have configured your
# virtual desktops.
# gesture swipe up _internal --col=2 ws_up
# gesture swipe down _internal --col=2 ws_down
# gesture swipe left _internal --row=4 ws_up
# gesture swipe right _internal --row=4 ws_down
# Example virtual desktop switching for Ubuntu Unity/Compiz. The
# _internal command does not work for Compiz but you can explicitly
# configure the swipe commands to work for a Compiz virtual 2
# dimensional desktop as follows:
# gesture swipe up xdotool key ctrl+alt+Up
# gesture swipe down xdotool key ctrl+alt+Down
# gesture swipe left xdotool key ctrl+alt+Left
# gesture swipe right xdotool key ctrl+alt+Right
# Example to change audio volume:
# Note this only works on an Xorg desktop (not Wayland).
# gesture swipe up xdotool key XF86AudioRaiseVolume
# gesture swipe down xdotool key XF86AudioLowerVolume
###############################################################################
# PINCH GESTURES:
###############################################################################
# GNOME SHELL open/close overview (works for GNOME on Xorg only)
#gesture pinch in xdotool key super+s
#gesture pinch out xdotool key super+s
# KDE Plasma open/close overview
# gesture pinch in xdotool key ctrl+F9
# gesture pinch out xdotool key ctrl+F9
# GNOME SHELL open/close overview (works for GNOME on Wayland and Xorg)
# Note since GNOME 3.24 on Wayland this is implemented natively so no
# real point configuring for Wayland.
# gesture pinch in dbus-send --session --type=method_call --dest=org.gnome.Shell /org/gnome/Shell org.gnome.Shell.Eval string:'Main.overview.toggle();'
# gesture pinch out dbus-send --session --type=method_call --dest=org.gnome.Shell /org/gnome/Shell org.gnome.Shell.Eval string:'Main.overview.toggle();'
# Optional extended pinch gestures:
# gesture pinch clockwise <whatever command>
# gesture pinch anticlockwise <whatever command>
###############################################################################
# This application normally determines your touchpad device
# automatically. Some users may have multiple touchpads but by default
# we use only the first one found. However, you can choose to specify
# the explicit device name to use. Run "libinput list-devices" to work
# out the name of your device (from the "Device:" field). Then add a
# device line specifying that name, e.g:
#
# device DLL0665:01 06CB:76AD Touchpad
#
# If the device name starts with a '/' then it is instead considered as
# the explicit device path although since device paths can change
# through reboots this is best to be a symlink. E.g. instead of specifying
# /dev/input/event12, use the corresponding full path link under
# /dev/input/by-path/*.
#
# You can choose to use ALL touchpad devices by setting the device name
# to "all". E.g. Do this if you have multiple touchpads which you want
# to use in parallel. This reduces performance slightly so only set this
# if you have to.
#
# device all
###############################################################################
# You can set a minimum travel distance threshold before swipe gestures
# are actioned using the swipe_threshold configuration command.
# Specify this value in dots. The default is 0.
# E.g. set it to 100 dots with "swipe_threshold 100".
# swipe_threshold 0

View file

@ -1,118 +0,0 @@
# much of this such as the whitelist, canonical list for lasgenre
# is stolen from https://github.com/montchr/beets-config/ with much gratitude
directory: ~/media/audio/music
library: ~/.local/share/beets/library.db
threaded: true
art_filename: albumart
# Use the album's original date instead of the release's date
original_date: yes
# Use safer pathnames
asciify_paths: yes
max_filename_length: 255
# Long format - I don't need all the extra info for each invocation
#format_item: '[$id] [$album_id] [$singleton] $albumartist - $title - $album - $original_year - [$format - $bitrate $length $filesize]'
#format_album: '[$id] $albumartist - $album - $original_year [$catalognum]'
clutter:
- Thumbs.db
- .DS_Store
- '*.m3u'
- '*.pls'
- '*.db'
import:
copy: false
move: true
write: true
bell: true
# incremental: true
languages:
- en
log: ~/.cache/beets.log
quiet_fallback: skip
timid: false
ignore_hidden: yes
paths:
default: "%the{$albumartist}/$album/$track $title"
singleton: "singletons/%the{$artist - $title}"
comp: compilations/$album/$track $title
albumtype:soundtrack: soundtracks/$album/$track $title
item_fields:
multidisc: 1 if disctotal > 1 else 0
artist_differs: 1 if albumartist != artist else 0
musicbrainz:
extra_tags: [year, catalognum, country, media, label]
user: {{multimedia_beets_musicbrainz_user}}
pass: {{multimedia_beets_musicbrainz_pass}}
auto: yes
remove: yes
match:
preferred:
countries: ["US", "UK|GB", "DE", "NL", "SE"]
media: ["Digital Media|File", "CD"]
strong_rec_thresh: 0.15
medium_red_thresh: 0.25
rec_gap_thresh: 0.25
plugins:
- bandcamp
- chroma
- deezer
- describe
- edit
- embedart
- export
- fetchart
- fromfilename
- ftintitle
- fuzzy
- importadded
- info
- inline
- lastgenre
- lastimport
- lyrics
- mbcollection
- mbsync
- missing
- spotify
- the
- ydl
edit:
itemfields: track title artist album
albumfields: album albumartist albumtype
ignore_fields: id path
fetchart:
sources: filesystem coverart itunes discogs amazon albumart
store_source: yes
lastgenre:
auto: true
canonical: ~/.config/beets/lastgenre_canonicallist.yaml
count: 4
fallback: ""
force: yes
min_weight: 6
prefer_specific: false
separator: "; "
source: album
whitelist: ~/.config/beets/lastgenre_whitelist.txt
lastfm:
user: schmitzkater
lyrics:
sources: musixmatch genius
fallback: ''
bandcamp:
art: true

View file

@ -1,783 +0,0 @@
- 2-step
- acapella
- acid
- acid house
- acid jazz
- acid techno
- adult contemporary
- african
- african blues
- african heavy metal
- african hip hop
- afrobeat
- aggrotech
- alternative country
- alternative metal
- alternative rock
- ambient
- ambient dub
- ambient house
- ambient space jazz
- ambient techno
- american folk revival
- americana
- anison
- anti-folk
- apala
- arab pop
- asian underground
- atlanta hip hop:
- snap music
- australian country music
- avant-garde
- avant-garde jazz
- axé
- bachata
- baithak gana
- bakersfield sound
- balearic beat
- ballet
- baltimore club
- barbershop
- baroque pop
- baroque:
- baroque music
- bebop
- benga
- berlin school:
- berlin school of electronic music
- berlin-school
- big band
- big beat
- bikutsi
- black metal:
- viking metal
- blue-eyed soul
- bluegrass:
- progressive bluegrass
- reactionary bluegrass
- blues
- blues country
- blues rock
- blues shouter
- bolero
- bongo flava
- boogie
- boogie-woogie
- bossa nova
- bounce music
- brazilian
- brazilian rock
- breakbeat:
- 4-beat
- acid breaks
- breakbeat hardcore
- broken beat
- florida breaks
- nu skool breaks
- breakcore
- brega
- british blues
- british folk revival
- britpop:
- post-britpop
- bubblegum pop
- c-pop:
- cantopop
- cajun:
- cajun fiddle tunes
- calypso
- canadian blues
- cantata
- cape jazz
- celtic music
- chamber jazz
- chamber music:
- string quartet
- chanson
- chicago blues
- chicago house
- chillwave:
- chill wave
- chimurenga
- chiptune:
- bitpop
- game boy music
- nintendocore
- video game music
- yorkshire bleeps and bass
- choro
- christian country music
- christian hip hop
- christian metal
- christian pop
- christian rock
- chutney
- chutney soca
- classic country
- classical crossover
- classical:
- classical music
- orchestra:
- orchestral
- symphonic
- symphony
- close harmony
- coldwave
- comedy:
- comedy music
- comedy rock
- humor
- parody music
- stand-up
- compas
- computer music
- concerto:
- concerto grosso
- contemporary folk
- contemporary r&b
- continental jazz
- cool jazz
- country
- country blues
- country pop
- country rap
- country rock
- country soul
- country-rap
- coupé-décalé
- cowpunk
- crunkcore
- cybergrind
- dance-punk
- dance-rock
- dancehall
- dansband music
- dark ambient
- dark electro
- darkwave:
- dark wave
- death industrial
- death metal:
- goregrind
- deconstructed club
- deep house
- deep techno
- delta blues
- detroit blues
- detroit techno
- digital hardcore:
- bouncy house
- bouncy techno
- hardstyle
- jumpstyle
- makina
- uk hardcore
- disco:
- disco polo:
- euro disco
- nu-disco
- diva house
- dixieland
- doo wop
- doom metal
- doomcore
- downtempo:
- chill out
- ethnic electronica
- moombahton
- nu jazz
- dream pop
- drone metal
- drone:
- drone music
- drum and bass:
- darkcore
- darkstep
- drumfunk
- drumstep
- hardstep
- intelligent drum and bass
- jump-up
- liquid funk
- neurofunk
- raggacore
- sambass
- techstep
- dub poetry
- dub techno
- dub:
- dub music
- dubstep
- dubtronica
- dungeon synth
- dutch house
- east coast hip hop:
- brick city club
- hardcore hip hop
- mafioso rap
- new jersey hip hop
- easy listening:
- background music
- beautiful music
- elevator music
- furniture music
- middle of the road
- ebm:
- electronic body music:
- futurepop
- edm:
- electronic dance music
- electric blues
- electro
- electro house
- electro-grime
- electro-industrial
- electroacoustic:
- acousmatic music
- electroacoustic improvisation
- live electronics
- electroclash
- electrofunk
- electronic rock:
- alternative dance:
- baggy
- madchester
- electronicore
- ethereal wave
- new rave
- electropop
- electropunk
- emo
- enka
- eurodance:
- bubblegum dance
- italo dance
- turbofolk
- europop:
- austropop
- balkan pop
- french pop
- latin pop
- laïkó
- nederpop
- russian pop
- experimental pop
- experimental rock
- experimental:
- experimental music
- fann at-tanbura
- field recording
- fijiri
- filmi
- folk metal:
- celtic metal
- medieval metal
- folk punk:
- celtic punk
- gypsy punk
- folk rock
- folk:
- filk music
- folk music
- folktronica
- footwork
- forró
- fourth world:
- ethnic ambient
- tribal ambient
- franco-country
- freak folk
- free jazz
- free funk
- free improvisation
- freestyle house
- freestyle rap
- freestyle:
- freestyle music
- french house
- frevo
- fuji music
- funk carioca
- funk metal
- funk:
- deep funk
- go-go
- funky house
- g-funk
- gabber
- gamelan
- gangsta rap
- garage rock
- garage:
- 4x4
- bassline
- breakstep
- funky
- speed garage
- genge
- ghetto house
- ghettotech
- glam metal
- glam rock
- glitch-hop
- glitch:
- clicks 'n' cuts
- goa:
- dark psytranceon
- goa trance
- psybreaks
- psyprog
- gospel blues
- goth rock:
- gothic rock
- gothic metal
- grime
- grindcore:
- crustgrind
- noisegrind
- grunge:
- post-grunge
- gulf and western
- gypsy jazz
- happy hardcore
- hard bop
- hard rock
- hardbag
- hardcore punk:
- street punk
- hellbilly music
- hi-nrg:
- eurobeat
- hard nrg
- new beat
- highlife
- hill country blues
- hip house
- hip-hop:
- alternative hip hop
- avant-garde hip hop
- chap hop
- chicago hip hop
- conscious hip hop
- detroit hip hop
- hip hop
- hip hop soul
- hip pop
- horrorcore
- hyphy
- jazz rap
- low bap
- lyrical hip hop
- merenrap
- motswako
- new jack swing
- new school hip hop
- old school hip hop
- political hip hop
- rap opera
- songo-salsa
- st. louis hip hop
- twin cities hip hop
- underground hip hop
- urban pasifika
- hiplife
- hokum
- hokum blues
- hong kong english pop
- honky tonk
- horror punk
- house
- houston hip hop:
- chopped and screwed
- idm
- illbient
- indian pop
- indie folk
- indie pop:
- dunedin sound
- twee pop
- indie rock
- indietronica
- industrial
- industrial dance
- industrial folk
- industrial hip hop
- industrial metal:
- neue deutsche härte
- industrial rock
- instrumental country
- instrumental hip hop
- iranian pop
- isicathamiya
- isolationism
- italo disco
- italo house
- j-pop
- jazz blues
- jazz fusion:
- fusion
- fusion jazz
- jazz rock
- jazz-funk
- jazz:
- british dance band
- crossover jazz
- cubop
- ethno jazz
- european free jazz
- m-base
- mainstream jazz
- novelty ragtime
- orchestral jazz
- shibuya-kei
- stride jazz
- third stream
- trad jazz
- vocal jazz
- west coast gypsy jazz
- west coast jazz
- jit
- jump blues
- jungle:
- oldschool jungle:
- darkside jungle
- ragga jungle
- jùjú
- k-pop:
- korean pop
- kansas city blues
- kansas city jazz
- kapuka
- kayōkyoku
- khaliji
- kizomba
- kosmische:
- kraut rock
- krautrock
- kuduro
- kwaito
- kwela
- lambada
- latin house
- latin jazz
- latin:
- chicha
- criolla
- cumbia
- huayno
- mariachi
- ranchera
- tejano
- live coding
- liwa
- lo-fi
- louisiana blues
- lounge:
- lounge music
- lovers rock
- lowercase
- lubbock sound
- luk thung:
- luk krung
- makossa
- maloya
- mambo
- mandopop
- manila sound
- maracatu
- marrabenta
- martial industrial
- mass
- math rock
- mbalax
- mbaqanga
- mbube
- melodic death metal
- memphis blues
- metal:
- heavy metal
- metalcore:
- deathcore
- mathcore:
- djent
- mexican pop
- miami bass
- minimal house
- minimal techno
- minimal wave
- modal jazz
- modern classical:
- contemporary classical
- morlam
- morna
- museve
- musique concrète:
- tape music
- méringue:
- merengue
- música popular brasileira
- música sertaneja
- nashville sound
- neo soul
- neo-bop jazz
- neo-psychedelia
- neo-swing
- neofolk
- neotraditional country
- nerdcore
- new age:
- new age music
- new-age
- new-age music
- new wave
- no wave
- noise pop
- noise rock
- noise:
- harsh noise
- japanoise
- noise music
- northern soul
- nu metal
- onkyokei
- opera
- oratorio
- organum
- outlaw country
- p-funk
- pagode
- palm-wine
- piano blues
- piedmont blues
- pinoy pop
- pop punk
- pop rock
- pop sunda
- pop:
- jangle pop
- latin ballad
- levenslied
- louisiana swamp pop
- motorpop
- new romanticism
- pop rap
- popera
- schlager
- sophisti-pop
- sunshine pop
- traditional pop music
- vispop
- wonky pop
- post-bop
- post-disco:
- dance-pop
- post-hardcore
- post-punk
- post-punk revival
- post-rock:
- post-metal
- power electronics
- power metal
- power noise
- powerviolence
- progressive country
- progressive electronic:
- progressive breaks
- progressive drum & bass
- progressive house/trance:
- disco house
- dream house
- space house
- progressive techno
- progressive folk
- progressive house
- progressive metal
- progressive rock:
- canterbury scene
- new prog
- rock in opposition
- psychedelic folk
- psychedelic pop
- psychedelic rock:
- acid rock
- freakbeat
- raga rock
- psychobilly
- psychobilly
- punk blues
- punk jazz
- punk:
- anarcho punk:
- crust punk:
- d-beat
- art punk
- christian punk
- deathrock
- garage punk
- skate punk
- punta
- punta rock
- r&b:
- rhythm and blues
- ragga:
- raggamuffin
- ragini
- ragtime
- rap rock:
- rap metal
- rapcore
- rasin
- rave:
- rave music
- raï
- red dirt
- reggae:
- 2 tone
- reggae en español:
- reggae 110
- reggae bultrón
- romantic flow
- spanish reggae
- reggae fusion
- reggaeton
- requiem
- riot grrrl
- rock and roll
- rock:
- art rock
- beat music
- chinese rock
- dark cabaret
- desert rock
- paisley underground
- power pop
- visual kei:
- nagoya kei
- rockabilly
- rocksteady
- roots reggae
- sacred music:
- cantique
- gregorian chant
- sadcore
- sakara
- salsa
- samba
- samba rock
- sawt
- screamo
- sega
- seggae
- semba
- sertanejo
- shoegaze
- ska
- ska jazz
- ska punk:
- ska-core
- slowcore
- sludge metal
- smooth jazz
- soca
- soft rock
- son
- sonata
- soukous
- soul
- soul blues
- soul jazz
- south and southeast asian:
- baila
- bhangra
- bhojpuri
- dangdut
- lavani
- southern hip hop
- southern rock
- space age pop
- space disco:
- cosmic disco
- space rock
- speed metal
- speedcore
- st. louis blues
- stoner metal
- stoner rock
- straight-ahead jazz
- sufi rock
- sung poetry
- surf pop
- surf rock
- swamp blues
- swing
- swing house
- symphonic metal
- synthcore
- synthpop
- synthpunk
- taarab
- taiwanese pop
- tech house
- technical death metal
- techno-folk
- techno:
- free tekno
- nortec
- schranz
- techno-dnb
- tecno brega
- toytown techno
- technopop
- tecnobrega
- teen pop
- terrorcore
- texas blues
- texas country
- thai pop
- thrash metal:
- crossover thrash
- groove metal
- thrash
- thrashcore
- timba
- traditional country music
- trance:
- acid trance
- classic trance
- dream trance
- hard trance
- progressive trance
- psychedelic trance
- psytrance
- tech trance
- uplifting trance:
- orchestral uplifting
- vocal trance
- trap
- trip-hop:
- trip hop
- tropicalia
- truck-driving country
- turkish pop
- turntablism
- twoubadou
- uk garage
- uk hard house
- us garage
- vaporwave
- vocal house
- west coast blues
- west coast hip hop:
- chicano rap
- jerkin'
- western swing
- witch house
- world:
- world music
- worldbeat
- world fusion
- zouglou
- zouk
- zouk-lambada
- zydeco

View file

@ -1,491 +0,0 @@
2-step
acapella
acid
acid house
acid jazz
acid techno
adult contemporary
african
african blues
african heavy metal
african hip hop
afrobeat
aggrotech
alternative country
alternative metal
alternative rock
ambient
ambient dub
ambient house
ambient space jazz
ambient techno
american folk revival
americana
anison
anti-folk
apala
arab pop
asian underground
atlanta hip hop
australian country music
avant-garde
avant-garde jazz
axé
bachata
baithak gana
bakersfield sound
balearic beat
ballet
baltimore club
barbershop
baroque pop
baroque
bebop
benga
berlin school
big band
big beat
bikutsi
black metal
blue-eyed soul
bluegrass
blues
blues country
blues rock
blues shouter
bolero
bongo flava
boogie
boogie-woogie
bossa nova
bounce music
brazilian
brazilian rock
breakbeat
breakcore
brega
british blues
british folk revival
britpop
bubblegum pop
c-pop
cajun
calypso
canadian blues
cantata
cape jazz
celtic music
chamber jazz
chamber music
chanson
chicago blues
chicago house
chillwave
chimurenga
chiptune
choro
christian country music
christian hip hop
christian metal
christian pop
christian rock
chutney
chutney soca
classic country
classical crossover
classical
close harmony
coldwave
comedy
compas
computer music
concerto
contemporary folk
contemporary r&b
continental jazz
cool jazz
country
country blues
country pop
country rap
country rock
country soul
country-rap
coupé-décalé
cowpunk
crunkcore
cybergrind
dance-punk
dance-rock
dancehall
dansband music
dark ambient
dark electro
darkwave
death industrial
death metal
deconstructed club
deep house
deep techno
delta blues
detroit blues
detroit techno
digital hardcore
disco
diva house
dixieland
doo wop
doom metal
doomcore
downtempo
dream pop
drone metal
drone
drum and bass
dub poetry
dub techno
dub
dubstep
dubtronica
dungeon synth
dutch house
east coast hip hop
easy listening
ebm
edm
electric blues
electro
electro house
electro-grime
electro-industrial
electroacoustic
electroclash
electrofunk
electronic rock
electropop
electropunk
emo
enka
eurodance
europop
experimental pop
experimental rock
experimental
fann at-tanbura
field recording
fijiri
filmi
folk metal
folk punk
folk rock
folk
folktronica
footwork
forró
fourth world
franco-country
freak folk
free jazz
freestyle house
freestyle rap
freestyle
french house
frevo
fuji music
funk carioca
funk metal
funk
funky house
g-funk
gabber
gamelan
gangsta rap
garage rock
garage
genge
ghetto house
ghettotech
glam metal
glam rock
glitch-hop
glitch
goa
gospel blues
goth rock
gothic metal
grime
grindcore
grunge
gulf and western
gypsy jazz
happy hardcore
hard bop
hard rock
hardbag
hardcore punk
hellbilly music
hi-nrg
highlife
hill country blues
hip house
hip-hop
hiplife
hokum
hokum blues
hong kong english pop
honky tonk
horror punk
house
houston hip hop
idm
illbient
indian pop
indie folk
indie pop
indie rock
indietronica
industrial
industrial dance
industrial folk
industrial hip hop
industrial metal
industrial rock
instrumental country
instrumental hip hop
iranian pop
isicathamiya
isolationism
italo disco
italo house
j-pop
jazz blues
jazz fusion
jazz rock
jazz-funk
jazz
jit
jump blues
jungle
jùjú
k-pop
kansas city blues
kansas city jazz
kapuka
kayōkyoku
khaliji
kizomba
kosmische
kuduro
kwaito
kwela
lambada
latin house
latin jazz
latin
live coding
liwa
lo-fi
louisiana blues
lounge
lovers rock
lowercase
lubbock sound
luk thung
makossa
maloya
mambo
mandopop
manila sound
maracatu
marrabenta
martial industrial
mass
math rock
mbalax
mbaqanga
mbube
melodic death metal
memphis blues
metal
metalcore
mexican pop
miami bass
minimal house
minimal techno
minimal wave
modal jazz
modern classical
morlam
morna
museve
musique concrète
méringue
música popular brasileira
música sertaneja
nashville sound
neo soul
neo-bop jazz
neo-psychedelia
neo-swing
neofolk
neotraditional country
nerdcore
new age
new wave
no wave
noise pop
noise rock
noise
northern soul
nu metal
onkyokei
opera
oratorio
organum
outlaw country
p-funk
pagode
palm-wine
piano blues
piedmont blues
pinoy pop
pop punk
pop rock
pop sunda
pop
post-bop
post-disco
post-hardcore
post-punk
post-punk revival
post-rock
power electronics
power metal
power noise
powerviolence
progressive country
progressive electronic
progressive folk
progressive house
progressive metal
progressive rock
psychedelic folk
psychedelic pop
psychedelic rock
psychobilly
psychobilly
punk blues
punk jazz
punk
punta
punta rock
r&b
ragga
ragini
ragtime
rap rock
rasin
rave
raï
red dirt
reggae
reggaeton
requiem
riot grrrl
rock and roll
rock
rockabilly
rocksteady
roots reggae
sacred music
sadcore
sakara
salsa
samba
samba rock
sawt
screamo
sega
seggae
semba
sertanejo
shoegaze
ska
ska jazz
ska punk
slowcore
sludge metal
smooth jazz
soca
soft rock
son
sonata
soukous
soul
soul blues
soul jazz
south and southeast asian
southern hip hop
southern rock
space age pop
space disco
space rock
speed metal
speedcore
st. louis blues
stoner metal
stoner rock
straight-ahead jazz
sufi rock
sung poetry
surf pop
surf rock
swamp blues
swing
swing house
symphonic metal
synthcore
synthpop
synthpunk
taarab
taiwanese pop
tech house
technical death metal
techno-folk
techno
technopop
tecnobrega
teen pop
terrorcore
texas blues
texas country
thai pop
thrash metal
thrashcore
timba
traditional country music
trance
trap
trip-hop
tropicalia
truck-driving country
turkish pop
turntablism
twoubadou
uk garage
uk hard house
us garage
vaporwave
vocal house
west coast blues
west coast hip hop
western swing
witch house
world
worldbeat
world fusion
gregorian chant
zouglou
zouk
zouk-lambada
zydeco

View file

@ -1,20 +0,0 @@
[options]
background = #080808
overlay = false
overlay_position_bottom = true
overlay_font = monospace:12
overlay_text_color = #c6c6c6
overlay_background_color = #1c1c1c
overlay_background_alpha = ff
[binds]
n = next
p = prev
o = overlay
<Shift+K> = zoom 5
<Shift+J> = zoom -5
<Shift+R> = rotate by 90
z = flip horizontal
<Shift+Z> = flip vertical
y = exec wl-copy "$imv_current_file"
Y = exec wl-copy < "$imv_current_file"

View file

@ -1,266 +0,0 @@
# For further information about options in this file see:
# https://docs.mopidy.com/
#
# The initial commented out values reflect the defaults as of:
# Mopidy 3.4.1
# Mopidy-Bandcamp 1.1.5
# Mopidy-File 3.4.1
# Mopidy-HTTP 3.4.1
# Mopidy-Iris 3.65.0
# Mopidy-Local 3.2.1
# Mopidy-M3U 3.4.1
# Mopidy-MPD 3.3.0
# Mopidy-MPRIS 3.0.3
# Mopidy-Scrobbler 2.0.1
# Mopidy-SoftwareMixer 3.4.1
# Mopidy-SomaFM 2.0.2
# Mopidy-Spotify 4.1.1
# Mopidy-Stream 3.4.1
# Mopidy-YouTube 3.5
#
# Available options and defaults might have changed since then,
# run `mopidy config` to see the current effective config and
# `mopidy --version` to check the current version.
[core]
#cache_dir = $XDG_CACHE_DIR/mopidy
#config_dir = $XDG_CONFIG_DIR/mopidy
#data_dir = $XDG_DATA_DIR/mopidy
#max_tracklist_length = 10000
#restore_state = false
[logging]
#verbosity = 0
#format = %(levelname)-8s %(asctime)s [%(process)d:%(threadName)s] %(name)s\n %(message)s
#color = true
#config_file =
[audio]
#mixer = software
#mixer_volume =
#output = autoaudiosink
#buffer_time =
[proxy]
#scheme =
#hostname =
#port =
#username =
#password =
[spotify]
enabled = false
#username =
#password =
#client_id =
#client_secret =
#bitrate = 160
#volume_normalization = true
#private_session = false
timeout = 5000
#allow_cache = true
#allow_network = true
#allow_playlists = true
#search_album_count = 20
#search_artist_count = 10
#search_track_count = 50
#toplist_countries =
[iris]
#enabled = true
#country = NZ
#locale = en_NZ
#verify_certificates = true
#snapcast_enabled = true
#snapcast_host = localhost
#snapcast_port = 1780
#snapcast_ssl = false
#snapcast_stream = Default
#spotify_authorization_url = https://jamesbarnsley.co.nz/iris/auth_spotify.php
#lastfm_authorization_url = https://jamesbarnsley.co.nz/iris/auth_lastfm.php
#genius_authorization_url = https://jamesbarnsley.co.nz/iris/auth_genius.php
#data_dir = $XDG_DATA_DIR/iris
[file]
enabled = false
#media_dirs =
# $XDG_MUSIC_DIR|Music
# ~/|Home
#excluded_file_extensions =
# .directory
# .html
# .jpeg
# .jpg
# .log
# .nfo
# .pdf
# .png
# .txt
# .zip
#show_dotfiles = false
#follow_symlinks = false
#metadata_timeout = 1000
[http]
#enabled = true
#hostname = 127.0.0.1
#port = 6680
#zeroconf = Mopidy HTTP server on $hostname
#allowed_origins =
#csrf_protection = true
#default_app = mopidy
[m3u]
#enabled = true
#base_dir = $XDG_MUSIC_DIR
#default_encoding = latin-1
#default_extension = .m3u8
#playlists_dir =
[softwaremixer]
#enabled = true
[stream]
#enabled = true
#protocols =
# http
# https
# mms
# rtmp
# rtmps
# rtsp
#metadata_blacklist =
#timeout = 5000
[mpd]
#enabled = true
#hostname = 127.0.0.1
#port = 6600
#password =
#max_connections = 20
#connection_timeout = 60
#zeroconf = Mopidy MPD server on $hostname
#command_blacklist =
# listall
# listallinfo
#default_playlist_scheme = m3u
[local]
enabled = false
#max_search_results = 100
media_dir = $XDG_MUSIC_DIR
scan_timeout = 5000
#scan_flush_threshold = 100
#scan_follow_symlinks = false
#included_file_extensions =
#excluded_file_extensions =
# .cue
# .directory
# .html
# .jpeg
# .jpg
# .log
# .nfo
# .pdf
# .png
# .txt
# .zip
#directories =
# Albums local:directory?type=album
# Artists local:directory?type=artist
# Composers local:directory?type=artist&role=composer
# Genres local:directory?type=genre
# Performers local:directory?type=artist&role=performer
# Release Years local:directory?type=date&format=%25Y
# Tracks local:directory?type=track
# Last Week's Updates local:directory?max-age=604800
# Last Month's Updates local:directory?max-age=2592000
#timeout = 10
#use_artist_sortname = false
#album_art_files =
# *.jpg
# *.jpeg
# *.png
[subidy]
url={{multimedia_mopidy_subidy_url}}
username={{multimedia_mopidy_subidy_user}}
password={{multimedia_mopidy_subidy_pass}}
[mpris]
#enabled = true
#bus_type = session
[scrobbler]
#enabled = true
#username =
#password =
[somafm]
#enabled = true
#encoding = mp3
#quality = fast
dj_as_artist = false
[youtube]
#enabled = true
allow_cache = true
#youtube_api_key =
#search_results = 15
#playlist_max_videos = 20
#api_enabled = false
#channel_id =
#musicapi_enabled = false
#musicapi_cookie =
#autoplay_enabled = false
#strict_autoplay = false
#max_autoplay_length = 600
#max_degrees_of_separation = 3
youtube_dl_package = yt-dlp
[bandcamp]
enabled = false
#discover_pages = 1
#collection_items = 50
discover_genres =
# All
# Electronic
# Rock
# Metal
# Alternative
# Hip-Hop/Rap
# Experimental
# Punk
# Folk
# Pop
# Ambient
# Soundtrack
# World
# Jazz
# Acoustic
# Funk
# R&B/Soul
# Devotional
# Classical
# Reggae
# Podcasts
# Country
# Spoken Word
# Comedy
# Blues
# Kids
# Audiobooks
# Latin
discover_tags =
Outrun
Future Funk
Alternative Hip-Hop
Cozy Synth
Post Metal
Post Punk
# Tokyo, Japan
#image_sizes =
# 10
# 5
# 2
#identity =

View file

@ -1,52 +0,0 @@
q quit
l seek 5
L seek 60
h seek -5
H seek -60
p cycle pause # play/pause
J playlist-next
K playlist-prev
k add volume 5
j add volume -5
+ add volume 2
- add volume -2
a add speed 0.1
A add speed -0.1
d add audio-delay 0.100 # for unsynched audio video
D add audio-delay -0.100
u add sub-delay -0.1 # subtract 100 ms delay from subs
U add sub-delay +0.1 # add
s cycle sub # choose subtitles
S cycle sub down # choose subtitles (reverse)
f cycle fullscreen # toggle fullscreen
F5 async screenshot # take a screenshot
Shift+F5 async screenshot video # screenshot without subtitles
i script-message playlistmanager show playlist toggle # toggle advanced playlist
I script-message playlistmanager show filename
R cycle-values video-aspect "16:9" "4:3" "3.25:1" "no" "-1" # cycle aspect ratios
# uosc definitions and menu
o script-message-to uosc toggle-elements timeline
O script-binding uosc/toggle-ui
m script-binding uosc/menu
# script-binding uosc/open-file #! Open file
# script-binding uosc/load-subtitles #! Load subtitles
# script-binding uosc/subtitles #! Select subtitles
# script-binding uosc/audio #! Select audio
# async screenshot #! Utils > Screenshot
# script-binding uosc/playlist #! Utils > Playlist
# script-binding uosc/chapters #! Utils > Chapters
# script-binding uosc/open-config-directory #! Utils > Open config directory

View file

@ -1,156 +0,0 @@
## mostly cobbled together from:
## https://github.com/Tsubajashi/mpv-settings/blob/master/mpv.conf
## https://github.com/haasn/gentoo-conf/blob/d3fd304fd7d8d816de6e280daf626b1b49a69893/home/nand/.mpv/config
## with much gratitude
#### player settings
# do not open in fullscreen, do not create border
fullscreen=no
# if playing the last file in e.g. a playlist, simply pause after finishing
keep-open=yes
# allow remote operation through ipc, see https://mpv.io/manual/stable/#json-ipc
input-ipc-server=/tmp/mpv-socket
# display a little seek bar in term
term-osd-bar=yes
# colorful term output
msg-color=yes
# add module names to term output
msg-module=yes
### screenshots
screenshot-directory="${XDG_PICTURES_DIR:-~/media/pictures}/screenshots"
# filename_HH-MM-SS
screenshot-template="screen_%F_%wH-%wM-%wS"
screenshot-format=png
# default compression rate (0 is no compression)
screenshot-png-compression=7
screenshot-tag-colorspace=yes
### OSD
# 2 options necessary for uosc, see https://github.com/darsain/uosc
osc=no
osd-bar=no
osd-font='Iosevka Nerd Font'
osd-font-size=15
### Subtitles
## options and compatibility
# vsfilter backward compatibility
sub-ass-vsfilter-blur-compat=yes
sub-ass-scale-with-window=no
# custom ass style params
sub-ass-force-style=Kerning=yes
# fuzzy-search available subs in folder
sub-auto=fuzzy
# search for external subs in these relative subdirectories
sub-file-paths-append=ass:srt:sub:subs:subtitles
# make sure when seeking through mkv we try to display subs
demuxer-mkv-subtitle-preroll=yes
# use fonts embedded in the container if available
embeddedfonts=yes
# don't meddle with subtitle timing by default
sub-fix-timing=no
# do not blend subtitles, so that we can display them beyond the video borders
blend-subtitles=no
## look and style
sub-ass-override=scale
sub-scale=0.5
sub-font="Liberation Sans"
sub-font-size=70
# put them a bit above seekbar -- not necessary imo
# sub-margin-y=50
sub-color="#FFFFFFFF"
sub-border-color="#FF151515"
sub-border-size=6
sub-shadow-offset=1
sub-shadow-color="#33000000"
sub-spacing=0.5
### Audio
volume=80
volume-max=150
# find audio files even if slightly mismatched
audio-file-auto=fuzzy
# playing at different speed will pitch-correct
audio-pitch-correction=yes
### Video
hwdec=auto
profile=opengl-hq
opengl-early-flush=auto
opengl-pbo=no
# ever so slightly up saturation
saturation=12
# interpolation options, will take some more cpu
interpolation=yes
video-sync=display-resample
### Cache
# use cache if it seems like a networked connection
cache=auto
### youtube-dl setup
ytdl=yes
# never go beyond 1080p if it is avoidable
ytdl-format=(bestvideo[vcodec=vp9.2][height<=1080]/bestvideo[vcodec=vp9][fps>30][height<=1080]/bestvideo[vcodec=vp9][height<=1080]/bestvideo[fps>30][height<=1080]/bestvideo[height>720])+(bestaudio[acodec=opus]/bestaudio)/best
### Languages
# prefer english subtitles, use german if you have to
slang=en,eng,de,deu,ger
# prefer original language, use dub if necessary
alang=ja,jp,jpn,en,eng,de,deu,ger
### Protocol configuration
[network]
# don't wait for buffering to be complete to show the window
force-window=immediate
cache=yes
# create a huge cache to buffer most of videos
demuxer-max-bytes=3000MiB
demuxer-readahead-secs=500
[protocol.http]
profile=network
[protocol.https]
profile=network
[protocol.ytdl]
profile=network
[extension.gif]
interpolation=no
loop-file=yes
# for those yt playlists that are created in reverse order
[reverse]
ytdl-raw-options=playlist-reverse=
[lowquality]
scale=bilinear
cscale=ewa_lanczossharp
interpolation=no
video-sync=audio
[highquality]
scale=ewa_lanczossharp
cscale=ewa_lanczossharp
video-sync=display-resample
interpolation=yes
tscale=oversample
# default to hq
profile=highquality

View file

@ -1,23 +0,0 @@
#navigation keybindings force override only while playlist is visible
#if "no" then you can display the playlist by any of the navigation keys
dynamic_binds=yes
#dynamic keybind keys, they should not be re-bound in input.conf
#to bind multiple keys separate them by a space
key_moveup=UP
key_movedown=DOWN
key_selectfile=RIGHT LEFT
key_unselectfile=
key_playfile=ENTER
key_removefile=BS
key_closeplaylist=ESC
#Use ~ for home directory. Leave as empty to use mpv/playlists
playlist_savepath=~/.local/share/mpv/playlists
#2 shows playlist, 1 shows current file(filename strip applied), 0 shows nothing
show_playlist_on_fileload=1
#call youtube-dl to resolve the titles of urls in the playlist
resolve_titles=yes

View file

@ -1,2 +0,0 @@
timeline_size_max=20
timeline_size_min=1

View file

@ -1,2 +0,0 @@
# use fork instead
ytdl_path=yt-dlp

View file

@ -1,268 +0,0 @@
-- This script automatically loads playlist entries before and after the
-- the currently played file. It does so by scanning the directory a file is
-- located in when starting playback. It sorts the directory entries
-- alphabetically, and adds entries before and after the current file to
-- the internal playlist. (It stops if it would add an already existing
-- playlist entry at the same position - this makes it "stable".)
-- Add at most 5000 * 2 files when starting a file (before + after).
--[[
To configure this script use file autoload.conf in directory script-opts (the "script-opts"
directory must be in the mpv configuration directory, typically ~/.config/mpv/).
Example configuration would be:
disabled=no
images=no
videos=yes
audio=yes
--]]
MAXENTRIES = 5000
local msg = require("mp.msg")
local options = require("mp.options")
local utils = require("mp.utils")
o = {
disabled = false,
images = true,
videos = true,
audio = true,
}
options.read_options(o)
function Set(t)
local set = {}
for _, v in pairs(t) do
set[v] = true
end
return set
end
function SetUnion(a, b)
local res = {}
for k in pairs(a) do
res[k] = true
end
for k in pairs(b) do
res[k] = true
end
return res
end
EXTENSIONS_VIDEO = Set({
"mkv",
"avi",
"mp4",
"ogv",
"webm",
"rmvb",
"flv",
"wmv",
"mpeg",
"mpg",
"m4v",
"3gp",
})
EXTENSIONS_AUDIO = Set({
"mp3",
"wav",
"ogm",
"flac",
"m4a",
"wma",
"ogg",
"opus",
})
EXTENSIONS_IMAGES = Set({
"jpg",
"jpeg",
"png",
"tif",
"tiff",
"gif",
"webp",
"svg",
"bmp",
})
EXTENSIONS = Set({})
if o.videos then
EXTENSIONS = SetUnion(EXTENSIONS, EXTENSIONS_VIDEO)
end
if o.audio then
EXTENSIONS = SetUnion(EXTENSIONS, EXTENSIONS_AUDIO)
end
if o.images then
EXTENSIONS = SetUnion(EXTENSIONS, EXTENSIONS_IMAGES)
end
function add_files_at(index, files)
index = index - 1
local oldcount = mp.get_property_number("playlist-count", 1)
for i = 1, #files do
mp.commandv("loadfile", files[i], "append")
mp.commandv("playlist-move", oldcount + i - 1, index + i - 1)
end
end
function get_extension(path)
match = string.match(path, "%.([^%.]+)$")
if match == nil then
return "nomatch"
else
return match
end
end
table.filter = function(t, iter)
for i = #t, 1, -1 do
if not iter(t[i]) then
table.remove(t, i)
end
end
end
-- splitbynum and alnumcomp from alphanum.lua (C) Andre Bogus
-- Released under the MIT License
-- http://www.davekoelle.com/files/alphanum.lua
-- split a string into a table of number and string values
function splitbynum(s)
local result = {}
for x, y in (s or ""):gmatch("(%d*)(%D*)") do
if x ~= "" then
table.insert(result, tonumber(x))
end
if y ~= "" then
table.insert(result, y)
end
end
return result
end
function clean_key(k)
k = (" " .. k .. " "):gsub("%s+", " "):sub(2, -2):lower()
return splitbynum(k)
end
-- compare two strings
function alnumcomp(x, y)
local xt, yt = clean_key(x), clean_key(y)
for i = 1, math.min(#xt, #yt) do
local xe, ye = xt[i], yt[i]
if type(xe) == "string" then
ye = tostring(ye)
elseif type(ye) == "string" then
xe = tostring(xe)
end
if xe ~= ye then
return xe < ye
end
end
return #xt < #yt
end
local autoloaded = nil
function find_and_add_entries()
local path = mp.get_property("path", "")
local dir, filename = utils.split_path(path)
msg.trace(("dir: %s, filename: %s"):format(dir, filename))
if o.disabled then
msg.verbose("stopping: autoload disabled")
return
elseif #dir == 0 then
msg.verbose("stopping: not a local path")
return
end
local pl_count = mp.get_property_number("playlist-count", 1)
-- check if this is a manually made playlist
if
(pl_count > 1 and autoloaded == nil)
or (pl_count == 1 and EXTENSIONS[string.lower(get_extension(filename))] == nil)
then
msg.verbose("stopping: manually made playlist")
return
else
autoloaded = true
end
local pl = mp.get_property_native("playlist", {})
local pl_current = mp.get_property_number("playlist-pos-1", 1)
msg.trace(("playlist-pos-1: %s, playlist: %s"):format(pl_current, utils.to_string(pl)))
local files = utils.readdir(dir, "files")
if files == nil then
msg.verbose("no other files in directory")
return
end
table.filter(files, function(v, k)
if string.match(v, "^%.") then
return false
end
local ext = get_extension(v)
if ext == nil then
return false
end
return EXTENSIONS[string.lower(ext)]
end)
table.sort(files, alnumcomp)
if dir == "." then
dir = ""
end
-- Find the current pl entry (dir+"/"+filename) in the sorted dir list
local current
for i = 1, #files do
if files[i] == filename then
current = i
break
end
end
if current == nil then
return
end
msg.trace("current file position in files: " .. current)
local append = { [-1] = {}, [1] = {} }
for direction = -1, 1, 2 do -- 2 iterations, with direction = -1 and +1
for i = 1, MAXENTRIES do
local file = files[current + i * direction]
local pl_e = pl[pl_current + i * direction]
if file == nil or file[1] == "." then
break
end
local filepath = dir .. file
if pl_e then
-- If there's a playlist entry, and it's the same file, stop.
msg.trace(pl_e.filename .. " == " .. filepath .. " ?")
if pl_e.filename == filepath then
break
end
end
if direction == -1 then
if pl_current == 1 then -- never add additional entries in the middle
msg.info("Prepending " .. file)
table.insert(append[-1], 1, filepath)
end
else
msg.info("Adding " .. file)
table.insert(append[1], filepath)
end
end
end
add_files_at(pl_current + 1, append[1])
add_files_at(pl_current, append[-1])
end
mp.register_event("start-file", find_and_add_entries)

View file

@ -1,37 +0,0 @@
-- If the laptop is on battery, the profile 'lq' will be loaded; otherwise 'hq' is used
local mp = require("mp")
local SHOULD_ADJUST = false
local lqprofile = "lowquality"
local hqprofile = "highquality"
local function powerstate()
local f = io.open("/sys/class/power_supply/AC/online")
if f == nil then
return
end
local t = f:read("*n")
f:close()
return t
end
local function adjust()
if not SHOULD_ADJUST then
return
end
local state = powerstate()
-- this actually overrides automatically applied profiles
-- like 'protocol.http'
if state == 0 then
mp.set_property("profile", lqprofile)
mp.msg.info("[quality] running battery, setting low-quality options.")
mp.osd_message("[quality] LQ")
else
mp.set_property("profile", hqprofile)
mp.msg.info("[quality] running ac, setting high-quality options.")
mp.osd_message("[quality] HQ")
end
end
mp.add_hook("on_load", 1, adjust)

View file

@ -1,83 +0,0 @@
local mp = require("mp")
require("mp.msg")
-- Copy the current time of the video to clipboard.
WINDOWS = 2
UNIX = 3
KEY_BIND = "y"
local function platform_type()
local utils = require("mp.utils")
local workdir = utils.to_string(mp.get_property_native("working-directory"))
if string.find(workdir, "\\") then
return WINDOWS
else
return UNIX
end
end
local function command_exists(cmd)
local pipe = io.popen("type " .. cmd .. ' > /dev/null 2> /dev/null; printf "$?"', "r")
if not pipe then
return
end
local exists = pipe:read() == "0"
pipe:close()
return exists
end
local function get_clipboard_cmd()
if command_exists("xclip") then
return "xclip -silent -in -selection clipboard"
elseif command_exists("wl-copy") then
return "wl-copy"
elseif command_exists("pbcopy") then
return "pbcopy"
else
mp.msg.error("No supported clipboard command found")
return false
end
end
local function divmod(a, b)
return a / b, a % b
end
local function set_clipboard(text)
if platform == WINDOWS then
mp.commandv("run", "powershell", "set-clipboard", text)
return true
elseif platform == UNIX and clipboard_cmd then
local pipe = io.popen(clipboard_cmd, "w")
if not pipe then
return
end
pipe:write(text)
pipe:close()
return true
else
mp.msg.error("Set_clipboard error")
return false
end
end
local function copyTime()
local time_pos = mp.get_property_number("time-pos")
local minutes, remainder = divmod(time_pos, 60)
local hours, minutes = divmod(minutes, 60)
local seconds = math.floor(remainder)
local milliseconds = math.floor((remainder - seconds) * 1000)
local time = string.format("%02d:%02d:%02d.%03d", hours, minutes, seconds, milliseconds)
if set_clipboard(time) then
mp.osd_message(string.format("[copytime] %s", time))
else
mp.osd_message("[copytime] failed")
end
end
platform = platform_type()
if platform == UNIX then
clipboard_cmd = get_clipboard_cmd()
end
mp.add_key_binding(KEY_BIND, "copyTime", copyTime)

View file

@ -1,33 +0,0 @@
-- gallery-dl_hook.lua
--
-- load online image galleries as playlists using gallery-dl
-- https://github.com/mikf/gallery-dl
--
-- to use, prepend the gallery url with: gallery-dl://
-- e.g.
-- `mpv gallery-dl://https://imgur.com/....`
local mp = require("mp")
local utils = require("mp.utils")
local msg = require("mp.msg")
local function exec(args)
local ret = utils.subprocess({ args = args })
return ret.status, ret.stdout, ret
end
mp.add_hook("on_load", 15, function()
local fn = mp.get_property("stream-open-filename", "")
if fn:find("gdl://") ~= 1 then
msg.debug("not a gdl:// url: " .. fn)
return
end
local url = string.gsub(url, "gdl://", "")
local es, urls, result = exec({ "gallery-dl", "-g", url })
if (es < 0) or (urls == nil) or (urls == "") then
msg.error("failed to get album list.")
end
mp.commandv("loadlist", "memory://" .. urls)
end)

File diff suppressed because it is too large Load diff

View file

@ -1,97 +0,0 @@
-- sponsorblock_minimal.lua
--
-- This script skips sponsored segments of YouTube videos
-- using data from https://github.com/ajayyy/SponsorBlock
--
-- original from https://codeberg.org/jouni/mpv_sponsorblock_minimal
-- adapted for local playback skipping and some refactoring by me
local mp = require("mp")
local options = {
API = "https://sponsor.ajay.app/api/skipSegments",
-- Categories to fetch and skip
categories = '"sponsor","intro","outro","interaction","selfpromo"',
}
local function getranges()
local args = {
"curl",
"-s",
"-d",
"videoID=" .. Youtube_id,
"-d",
"categories=[" .. options.categories .. "]",
"-G",
options.API,
}
local sponsors = mp.command_native({
name = "subprocess",
capture_stdout = true,
playback_only = false,
args = args,
})
if string.match(sponsors.stdout, "%[(.-)%]") then
Ranges = {}
for i in string.gmatch(string.sub(sponsors.stdout, 2, -2), "%[(.-)%]") do
local k, v = string.match(i, "(%d+.?%d*),(%d+.?%d*)")
Ranges[k] = v
end
end
end
local function skip_ads(_, pos)
if pos ~= nil then
for k, v in pairs(Ranges) do
if tonumber(k) <= pos and tonumber(v) > pos then
-- this message may sometimes be wrong
-- it only seems to be a visual thing though
mp.osd_message(
"[sponsorblock] skipping forward " .. math.floor(tonumber(v) - mp.get_property("time-pos")) .. "s"
)
-- need to do the +0.01 otherwise mpv will start spamming skip sometimes
-- example: https://www.youtube.com/watch?v=4ypMJzeNooo
mp.set_property("time-pos", tonumber(v) + 0.01)
return
end
end
end
end
local function file_loaded()
local video_path = mp.get_property("path")
local youtube_id1 = string.match(video_path, "https?://youtu%.be/([%w-_]+).*")
local youtube_id2 = string.match(video_path, "https?://w?w?w?%.?youtube%.com/v/([%w-_]+).*")
local youtube_id3 = string.match(video_path, "/watch.*[?&]v=([%w-_]+).*")
local youtube_id4 = string.match(video_path, "/embed/([%w-_]+).*")
local localytfile = string.match(video_path, "-([%a%d%-_]+)%.[mw][kpe][v4b][m]?$")
Youtube_id = youtube_id1 or youtube_id2 or youtube_id3 or youtube_id4 or localytfile
if not Youtube_id or string.len(Youtube_id) < 11 then
return
end
Youtube_id = string.sub(Youtube_id, 1, 11)
getranges()
if Ranges then
ON = true
mp.add_key_binding("b", "sponsorblock", toggle)
mp.observe_property("time-pos", "native", skip_ads)
end
return
end
local function toggle()
if ON then
mp.unobserve_property(skip_ads)
mp.osd_message("[sponsorblock] off")
ON = false
return
end
mp.observe_property("time-pos", "native", skip_ads)
mp.osd_message("[sponsorblock] on")
ON = true
return
end
mp.register_event("file-loaded", file_loaded)

View file

@ -1,940 +0,0 @@
-- thumbfast.lua
--
-- High-performance on-the-fly thumbnailer
--
-- Built for easy integration in third-party UIs.
--[[
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
]]
local options = {
-- Socket path (leave empty for auto)
socket = "",
-- Thumbnail path (leave empty for auto)
thumbnail = "",
-- Maximum thumbnail generation size in pixels (scaled down to fit)
-- Values are scaled when hidpi is enabled
max_height = 200,
max_width = 200,
-- Scale factor for thumbnail display size (requires mpv 0.38+)
-- Note that this is lower quality than increasing max_height and max_width
scale_factor = 1,
-- Apply tone-mapping, no to disable
tone_mapping = "auto",
-- Overlay id
overlay_id = 42,
-- Spawn thumbnailer on file load for faster initial thumbnails
spawn_first = false,
-- Close thumbnailer process after an inactivity period in seconds, 0 to disable
quit_after_inactivity = 0,
-- Enable on network playback
network = false,
-- Enable on audio playback
audio = false,
-- Enable hardware decoding
hwdec = false,
-- Windows only: use native Windows API to write to pipe (requires LuaJIT)
direct_io = false,
-- Custom path to the mpv executable
mpv_path = "mpv"
}
mp.utils = require "mp.utils"
mp.options = require "mp.options"
mp.options.read_options(options, "thumbfast")
local properties = {}
local pre_0_30_0 = mp.command_native_async == nil
local pre_0_33_0 = true
function subprocess(args, async, callback)
callback = callback or function() end
if not pre_0_30_0 then
if async then
return mp.command_native_async({name = "subprocess", playback_only = true, args = args}, callback)
else
return mp.command_native({name = "subprocess", playback_only = false, capture_stdout = true, args = args})
end
else
if async then
return mp.utils.subprocess_detached({args = args}, callback)
else
return mp.utils.subprocess({args = args})
end
end
end
local winapi = {}
if options.direct_io then
local ffi_loaded, ffi = pcall(require, "ffi")
if ffi_loaded then
winapi = {
ffi = ffi,
C = ffi.C,
bit = require("bit"),
socket_wc = "",
-- WinAPI constants
CP_UTF8 = 65001,
GENERIC_WRITE = 0x40000000,
OPEN_EXISTING = 3,
FILE_FLAG_WRITE_THROUGH = 0x80000000,
FILE_FLAG_NO_BUFFERING = 0x20000000,
PIPE_NOWAIT = ffi.new("unsigned long[1]", 0x00000001),
INVALID_HANDLE_VALUE = ffi.cast("void*", -1),
-- don't care about how many bytes WriteFile wrote, so allocate something to store the result once
_lpNumberOfBytesWritten = ffi.new("unsigned long[1]"),
}
-- cache flags used in run() to avoid bor() call
winapi._createfile_pipe_flags = winapi.bit.bor(winapi.FILE_FLAG_WRITE_THROUGH, winapi.FILE_FLAG_NO_BUFFERING)
ffi.cdef[[
void* __stdcall CreateFileW(const wchar_t *lpFileName, unsigned long dwDesiredAccess, unsigned long dwShareMode, void *lpSecurityAttributes, unsigned long dwCreationDisposition, unsigned long dwFlagsAndAttributes, void *hTemplateFile);
bool __stdcall WriteFile(void *hFile, const void *lpBuffer, unsigned long nNumberOfBytesToWrite, unsigned long *lpNumberOfBytesWritten, void *lpOverlapped);
bool __stdcall CloseHandle(void *hObject);
bool __stdcall SetNamedPipeHandleState(void *hNamedPipe, unsigned long *lpMode, unsigned long *lpMaxCollectionCount, unsigned long *lpCollectDataTimeout);
int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
]]
winapi.MultiByteToWideChar = function(MultiByteStr)
if MultiByteStr then
local utf16_len = winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, MultiByteStr, -1, nil, 0)
if utf16_len > 0 then
local utf16_str = winapi.ffi.new("wchar_t[?]", utf16_len)
if winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, MultiByteStr, -1, utf16_str, utf16_len) > 0 then
return utf16_str
end
end
end
return ""
end
else
options.direct_io = false
end
end
local file
local file_bytes = 0
local spawned = false
local disabled = false
local force_disabled = false
local spawn_waiting = false
local spawn_working = false
local script_written = false
local dirty = false
local x, y
local last_x, last_y
local last_seek_time
local effective_w, effective_h = options.max_width, options.max_height
local real_w, real_h
local last_real_w, last_real_h
local script_name
local show_thumbnail = false
local filters_reset = {["lavfi-crop"]=true, ["crop"]=true}
local filters_runtime = {["hflip"]=true, ["vflip"]=true}
local filters_all = {["hflip"]=true, ["vflip"]=true, ["lavfi-crop"]=true, ["crop"]=true}
local tone_mappings = {["none"]=true, ["clip"]=true, ["linear"]=true, ["gamma"]=true, ["reinhard"]=true, ["hable"]=true, ["mobius"]=true}
local last_tone_mapping
local last_vf_reset = ""
local last_vf_runtime = ""
local last_rotate = 0
local par = ""
local last_par = ""
local last_crop = nil
local last_has_vid = 0
local has_vid = 0
local file_timer
local file_check_period = 1/60
local allow_fast_seek = true
local client_script = [=[
#!/usr/bin/env bash
MPV_IPC_FD=0; MPV_IPC_PATH="%s"
trap "kill 0" EXIT
while [[ $# -ne 0 ]]; do case $1 in --mpv-ipc-fd=*) MPV_IPC_FD=${1/--mpv-ipc-fd=/} ;; esac; shift; done
if echo "print-text thumbfast" >&"$MPV_IPC_FD"; then echo -n > "$MPV_IPC_PATH"; tail -f "$MPV_IPC_PATH" >&"$MPV_IPC_FD" & while read -r -u "$MPV_IPC_FD" 2>/dev/null; do :; done; fi
]=]
local function get_os()
local raw_os_name = ""
if jit and jit.os and jit.arch then
raw_os_name = jit.os
else
if package.config:sub(1,1) == "\\" then
-- Windows
local env_OS = os.getenv("OS")
if env_OS then
raw_os_name = env_OS
end
else
raw_os_name = subprocess({"uname", "-s"}).stdout
end
end
raw_os_name = (raw_os_name):lower()
local os_patterns = {
["windows"] = "windows",
["linux"] = "linux",
["osx"] = "darwin",
["mac"] = "darwin",
["darwin"] = "darwin",
["^mingw"] = "windows",
["^cygwin"] = "windows",
["bsd$"] = "darwin",
["sunos"] = "darwin"
}
-- Default to linux
local str_os_name = "linux"
for pattern, name in pairs(os_patterns) do
if raw_os_name:match(pattern) then
str_os_name = name
break
end
end
return str_os_name
end
local os_name = mp.get_property("platform") or get_os()
local path_separator = os_name == "windows" and "\\" or "/"
if options.socket == "" then
if os_name == "windows" then
options.socket = "thumbfast"
else
options.socket = "/tmp/thumbfast"
end
end
if options.thumbnail == "" then
if os_name == "windows" then
options.thumbnail = os.getenv("TEMP").."\\thumbfast.out"
else
options.thumbnail = "/tmp/thumbfast.out"
end
end
local unique = mp.utils.getpid()
options.socket = options.socket .. unique
options.thumbnail = options.thumbnail .. unique
if options.direct_io then
if os_name == "windows" then
winapi.socket_wc = winapi.MultiByteToWideChar("\\\\.\\pipe\\" .. options.socket)
end
if winapi.socket_wc == "" then
options.direct_io = false
end
end
options.scale_factor = math.floor(options.scale_factor)
local mpv_path = options.mpv_path
if mpv_path == "mpv" and os_name == "darwin" and unique then
-- TODO: look into ~~osxbundle/
mpv_path = string.gsub(subprocess({"ps", "-o", "comm=", "-p", tostring(unique)}).stdout, "[\n\r]", "")
if mpv_path ~= "mpv" then
mpv_path = string.gsub(mpv_path, "/mpv%-bundle$", "/mpv")
local mpv_bin = mp.utils.file_info("/usr/local/mpv")
if mpv_bin and mpv_bin.is_file then
mpv_path = "/usr/local/mpv"
else
local mpv_app = mp.utils.file_info("/Applications/mpv.app/Contents/MacOS/mpv")
if mpv_app and mpv_app.is_file then
mp.msg.warn("symlink mpv to fix Dock icons: `sudo ln -s /Applications/mpv.app/Contents/MacOS/mpv /usr/local/mpv`")
else
mp.msg.warn("drag to your Applications folder and symlink mpv to fix Dock icons: `sudo ln -s /Applications/mpv.app/Contents/MacOS/mpv /usr/local/mpv`")
end
end
end
end
local function vo_tone_mapping()
local passes = mp.get_property_native("vo-passes")
if passes and passes["fresh"] then
for k, v in pairs(passes["fresh"]) do
for k2, v2 in pairs(v) do
if k2 == "desc" and v2 then
local tone_mapping = string.match(v2, "([0-9a-z.-]+) tone map")
if tone_mapping then
return tone_mapping
end
end
end
end
end
end
local function vf_string(filters, full)
local vf = ""
local vf_table = properties["vf"]
if (properties["video-crop"] or "") ~= "" then
vf = "lavfi-crop="..string.gsub(properties["video-crop"], "(%d*)x?(%d*)%+(%d+)%+(%d+)", "w=%1:h=%2:x=%3:y=%4")..","
local width = properties["video-out-params"] and properties["video-out-params"]["dw"]
local height = properties["video-out-params"] and properties["video-out-params"]["dh"]
if width and height then
vf = string.gsub(vf, "w=:h=:", "w="..width..":h="..height..":")
end
end
if vf_table and #vf_table > 0 then
for i = #vf_table, 1, -1 do
if filters[vf_table[i].name] then
local args = ""
for key, value in pairs(vf_table[i].params) do
if args ~= "" then
args = args .. ":"
end
args = args .. key .. "=" .. value
end
vf = vf .. vf_table[i].name .. "=" .. args .. ","
end
end
end
if (full and options.tone_mapping ~= "no") or options.tone_mapping == "auto" then
if properties["video-params"] and properties["video-params"]["primaries"] == "bt.2020" then
local tone_mapping = options.tone_mapping
if tone_mapping == "auto" then
tone_mapping = last_tone_mapping or properties["tone-mapping"]
if tone_mapping == "auto" and properties["current-vo"] == "gpu-next" then
tone_mapping = vo_tone_mapping()
end
end
if not tone_mappings[tone_mapping] then
tone_mapping = "hable"
end
last_tone_mapping = tone_mapping
vf = vf .. "zscale=transfer=linear,format=gbrpf32le,tonemap="..tone_mapping..",zscale=transfer=bt709,"
end
end
if full then
vf = vf.."scale=w="..effective_w..":h="..effective_h..par..",pad=w="..effective_w..":h="..effective_h..":x=-1:y=-1,format=bgra"
end
return vf
end
local function calc_dimensions()
local width = properties["video-out-params"] and properties["video-out-params"]["dw"]
local height = properties["video-out-params"] and properties["video-out-params"]["dh"]
if not width or not height then return end
local scale = properties["display-hidpi-scale"] or 1
if width / height > options.max_width / options.max_height then
effective_w = math.floor(options.max_width * scale + 0.5)
effective_h = math.floor(height / width * effective_w + 0.5)
else
effective_h = math.floor(options.max_height * scale + 0.5)
effective_w = math.floor(width / height * effective_h + 0.5)
end
local v_par = properties["video-out-params"] and properties["video-out-params"]["par"] or 1
if v_par == 1 then
par = ":force_original_aspect_ratio=decrease"
else
par = ""
end
end
local info_timer = nil
local function info(w, h)
local rotate = properties["video-params"] and properties["video-params"]["rotate"]
local image = properties["current-tracks/video"] and properties["current-tracks/video"]["image"]
local albumart = image and properties["current-tracks/video"]["albumart"]
disabled = (w or 0) == 0 or (h or 0) == 0 or
has_vid == 0 or
(properties["demuxer-via-network"] and not options.network) or
(albumart and not options.audio) or
(image and not albumart) or
force_disabled
if info_timer then
info_timer:kill()
info_timer = nil
elseif has_vid == 0 or (rotate == nil and not disabled) then
info_timer = mp.add_timeout(0.05, function() info(w, h) end)
end
local json, err = mp.utils.format_json({width=w * options.scale_factor, height=h * options.scale_factor, scale_factor=options.scale_factor, disabled=disabled, available=true, socket=options.socket, thumbnail=options.thumbnail, overlay_id=options.overlay_id})
if pre_0_30_0 then
mp.command_native({"script-message", "thumbfast-info", json})
else
mp.command_native_async({"script-message", "thumbfast-info", json}, function() end)
end
end
local function remove_thumbnail_files()
if file then
file:close()
file = nil
file_bytes = 0
end
os.remove(options.thumbnail)
os.remove(options.thumbnail..".bgra")
end
local activity_timer
local function spawn(time)
if disabled then return end
local path = properties["path"]
if path == nil then return end
if options.quit_after_inactivity > 0 then
if show_thumbnail or activity_timer:is_enabled() then
activity_timer:kill()
end
activity_timer:resume()
end
local open_filename = properties["stream-open-filename"]
local ytdl = open_filename and properties["demuxer-via-network"] and path ~= open_filename
if ytdl then
path = open_filename
end
remove_thumbnail_files()
local vid = properties["vid"]
has_vid = vid or 0
local args = {
mpv_path, "--no-config", "--msg-level=all=no", "--idle", "--pause", "--keep-open=always", "--really-quiet", "--no-terminal",
"--load-scripts=no", "--osc=no", "--ytdl=no", "--load-stats-overlay=no", "--load-osd-console=no", "--load-auto-profiles=no",
"--edition="..(properties["edition"] or "auto"), "--vid="..(vid or "auto"), "--no-sub", "--no-audio",
"--start="..time, allow_fast_seek and "--hr-seek=no" or "--hr-seek=yes",
"--ytdl-format=worst", "--demuxer-readahead-secs=0", "--demuxer-max-bytes=128KiB",
"--vd-lavc-skiploopfilter=all", "--vd-lavc-software-fallback=1", "--vd-lavc-fast", "--vd-lavc-threads=2", "--hwdec="..(options.hwdec and "auto" or "no"),
"--vf="..vf_string(filters_all, true),
"--sws-scaler=fast-bilinear",
"--video-rotate="..last_rotate,
"--ovc=rawvideo", "--of=image2", "--ofopts=update=1", "--o="..options.thumbnail
}
if not pre_0_30_0 then
table.insert(args, "--sws-allow-zimg=no")
end
if os_name == "darwin" and properties["macos-app-activation-policy"] then
table.insert(args, "--macos-app-activation-policy=accessory")
end
if os_name == "windows" or pre_0_33_0 then
table.insert(args, "--input-ipc-server="..options.socket)
elseif not script_written then
local client_script_path = options.socket..".run"
local script = io.open(client_script_path, "w+")
if script == nil then
mp.msg.error("client script write failed")
return
else
script_written = true
script:write(string.format(client_script, options.socket))
script:close()
subprocess({"chmod", "+x", client_script_path}, true)
table.insert(args, "--scripts="..client_script_path)
end
else
local client_script_path = options.socket..".run"
table.insert(args, "--scripts="..client_script_path)
end
table.insert(args, "--")
table.insert(args, path)
spawned = true
spawn_waiting = true
subprocess(args, true,
function(success, result)
if spawn_waiting and (success == false or (result.status ~= 0 and result.status ~= -2)) then
spawned = false
spawn_waiting = false
options.tone_mapping = "no"
mp.msg.error("mpv subprocess create failed")
if not spawn_working then -- notify users of required configuration
if options.mpv_path == "mpv" then
if properties["current-vo"] == "libmpv" then
if options.mpv_path == mpv_path then -- attempt to locate ImPlay
mpv_path = "ImPlay"
spawn(time)
else -- ImPlay not in path
if os_name ~= "darwin" then
force_disabled = true
info(real_w or effective_w, real_h or effective_h)
end
mp.commandv("show-text", "thumbfast: ERROR! cannot create mpv subprocess", 5000)
mp.commandv("script-message-to", "implay", "show-message", "thumbfast initial setup", "Set mpv_path=PATH_TO_ImPlay in thumbfast config:\n" .. string.gsub(mp.command_native({"expand-path", "~~/script-opts/thumbfast.conf"}), "[/\\]", path_separator).."\nand restart ImPlay")
end
else
mp.commandv("show-text", "thumbfast: ERROR! cannot create mpv subprocess", 5000)
if os_name == "windows" then
mp.commandv("script-message-to", "mpvnet", "show-text", "thumbfast: ERROR! install standalone mpv, see README", 5000, 20)
mp.commandv("script-message", "mpv.net", "show-text", "thumbfast: ERROR! install standalone mpv, see README", 5000, 20)
end
end
else
mp.commandv("show-text", "thumbfast: ERROR! cannot create mpv subprocess", 5000)
-- found ImPlay but not defined in config
mp.commandv("script-message-to", "implay", "show-message", "thumbfast", "Set mpv_path=PATH_TO_ImPlay in thumbfast config:\n" .. string.gsub(mp.command_native({"expand-path", "~~/script-opts/thumbfast.conf"}), "[/\\]", path_separator).."\nand restart ImPlay")
end
end
elseif success == true and (result.status == 0 or result.status == -2) then
if not spawn_working and properties["current-vo"] == "libmpv" and options.mpv_path ~= mpv_path then
mp.commandv("script-message-to", "implay", "show-message", "thumbfast initial setup", "Set mpv_path=ImPlay in thumbfast config:\n" .. string.gsub(mp.command_native({"expand-path", "~~/script-opts/thumbfast.conf"}), "[/\\]", path_separator).."\nand restart ImPlay")
end
spawn_working = true
spawn_waiting = false
end
end
)
end
local function run(command)
if not spawned then return end
if options.direct_io then
local hPipe = winapi.C.CreateFileW(winapi.socket_wc, winapi.GENERIC_WRITE, 0, nil, winapi.OPEN_EXISTING, winapi._createfile_pipe_flags, nil)
if hPipe ~= winapi.INVALID_HANDLE_VALUE then
local buf = command .. "\n"
winapi.C.SetNamedPipeHandleState(hPipe, winapi.PIPE_NOWAIT, nil, nil)
winapi.C.WriteFile(hPipe, buf, #buf + 1, winapi._lpNumberOfBytesWritten, nil)
winapi.C.CloseHandle(hPipe)
end
return
end
local command_n = command.."\n"
if os_name == "windows" then
if file and file_bytes + #command_n >= 4096 then
file:close()
file = nil
file_bytes = 0
end
if not file then
file = io.open("\\\\.\\pipe\\"..options.socket, "r+b")
end
elseif pre_0_33_0 then
subprocess({"/usr/bin/env", "sh", "-c", "echo '" .. command .. "' | socat - " .. options.socket})
return
elseif not file then
file = io.open(options.socket, "r+")
end
if file then
file_bytes = file:seek("end")
file:write(command_n)
file:flush()
end
end
local function draw(w, h, script)
if not w or not show_thumbnail then return end
if x ~= nil then
local scale_w, scale_h = options.scale_factor ~= 1 and (w * options.scale_factor) or nil, options.scale_factor ~= 1 and (h * options.scale_factor) or nil
if pre_0_30_0 then
mp.command_native({"overlay-add", options.overlay_id, x, y, options.thumbnail..".bgra", 0, "bgra", w, h, (4*w), scale_w, scale_h})
else
mp.command_native_async({"overlay-add", options.overlay_id, x, y, options.thumbnail..".bgra", 0, "bgra", w, h, (4*w), scale_w, scale_h}, function() end)
end
elseif script then
local json, err = mp.utils.format_json({width=w, height=h, scale_factor=options.scale_factor, x=x, y=y, socket=options.socket, thumbnail=options.thumbnail, overlay_id=options.overlay_id})
mp.commandv("script-message-to", script, "thumbfast-render", json)
end
end
local function real_res(req_w, req_h, filesize)
local count = filesize / 4
local diff = (req_w * req_h) - count
if (properties["video-params"] and properties["video-params"]["rotate"] or 0) % 180 == 90 then
req_w, req_h = req_h, req_w
end
if diff == 0 then
return req_w, req_h
else
local threshold = 5 -- throw out results that change too much
local long_side, short_side = req_w, req_h
if req_h > req_w then
long_side, short_side = req_h, req_w
end
for a = short_side, short_side - threshold, -1 do
if count % a == 0 then
local b = count / a
if long_side - b < threshold then
if req_h < req_w then return b, a else return a, b end
end
end
end
return nil
end
end
local function move_file(from, to)
if os_name == "windows" then
os.remove(to)
end
-- move the file because it can get overwritten while overlay-add is reading it, and crash the player
os.rename(from, to)
end
local function seek(fast)
if last_seek_time then
run("async seek " .. last_seek_time .. (fast and " absolute+keyframes" or " absolute+exact"))
end
end
local seek_period = 3/60
local seek_period_counter = 0
local seek_timer
seek_timer = mp.add_periodic_timer(seek_period, function()
if seek_period_counter == 0 then
seek(allow_fast_seek)
seek_period_counter = 1
else
if seek_period_counter == 2 then
if allow_fast_seek then
seek_timer:kill()
seek()
end
else seek_period_counter = seek_period_counter + 1 end
end
end)
seek_timer:kill()
local function request_seek()
if seek_timer:is_enabled() then
seek_period_counter = 0
else
seek_timer:resume()
seek(allow_fast_seek)
seek_period_counter = 1
end
end
local function check_new_thumb()
-- the slave might start writing to the file after checking existance and
-- validity but before actually moving the file, so move to a temporary
-- location before validity check to make sure everything stays consistant
-- and valid thumbnails don't get overwritten by invalid ones
local tmp = options.thumbnail..".tmp"
move_file(options.thumbnail, tmp)
local finfo = mp.utils.file_info(tmp)
if not finfo then return false end
spawn_waiting = false
local w, h = real_res(effective_w, effective_h, finfo.size)
if w then -- only accept valid thumbnails
move_file(tmp, options.thumbnail..".bgra")
real_w, real_h = w, h
if real_w and (real_w ~= last_real_w or real_h ~= last_real_h) then
last_real_w, last_real_h = real_w, real_h
info(real_w, real_h)
end
if not show_thumbnail then
file_timer:kill()
end
return true
end
return false
end
file_timer = mp.add_periodic_timer(file_check_period, function()
if check_new_thumb() then
draw(real_w, real_h, script_name)
end
end)
file_timer:kill()
local function clear()
file_timer:kill()
seek_timer:kill()
if options.quit_after_inactivity > 0 then
if show_thumbnail or activity_timer:is_enabled() then
activity_timer:kill()
end
activity_timer:resume()
end
last_seek_time = nil
show_thumbnail = false
last_x = nil
last_y = nil
if script_name then return end
if pre_0_30_0 then
mp.command_native({"overlay-remove", options.overlay_id})
else
mp.command_native_async({"overlay-remove", options.overlay_id}, function() end)
end
end
local function quit()
activity_timer:kill()
if show_thumbnail then
activity_timer:resume()
return
end
run("quit")
spawned = false
real_w, real_h = nil, nil
clear()
end
activity_timer = mp.add_timeout(options.quit_after_inactivity, quit)
activity_timer:kill()
local function thumb(time, r_x, r_y, script)
if disabled then return end
time = tonumber(time)
if time == nil then return end
if r_x == "" or r_y == "" then
x, y = nil, nil
else
x, y = math.floor(r_x + 0.5), math.floor(r_y + 0.5)
end
script_name = script
if last_x ~= x or last_y ~= y or not show_thumbnail then
show_thumbnail = true
last_x, last_y = x, y
draw(real_w, real_h, script)
end
if options.quit_after_inactivity > 0 then
if show_thumbnail or activity_timer:is_enabled() then
activity_timer:kill()
end
activity_timer:resume()
end
if time == last_seek_time then return end
last_seek_time = time
if not spawned then spawn(time) end
request_seek()
if not file_timer:is_enabled() then file_timer:resume() end
end
local function watch_changes()
if not dirty or not properties["video-out-params"] then return end
dirty = false
local old_w = effective_w
local old_h = effective_h
calc_dimensions()
local vf_reset = vf_string(filters_reset)
local rotate = properties["video-rotate"] or 0
local resized = old_w ~= effective_w or
old_h ~= effective_h or
last_vf_reset ~= vf_reset or
(last_rotate % 180) ~= (rotate % 180) or
par ~= last_par or last_crop ~= properties["video-crop"]
if resized then
last_rotate = rotate
info(effective_w, effective_h)
elseif last_has_vid ~= has_vid and has_vid ~= 0 then
info(effective_w, effective_h)
end
if spawned then
if resized then
-- mpv doesn't allow us to change output size
local seek_time = last_seek_time
run("quit")
clear()
spawned = false
spawn(seek_time or mp.get_property_number("time-pos", 0))
file_timer:resume()
else
if rotate ~= last_rotate then
run("set video-rotate "..rotate)
end
local vf_runtime = vf_string(filters_runtime)
if vf_runtime ~= last_vf_runtime then
run("vf set "..vf_string(filters_all, true))
last_vf_runtime = vf_runtime
end
end
else
last_vf_runtime = vf_string(filters_runtime)
end
last_vf_reset = vf_reset
last_rotate = rotate
last_par = par
last_crop = properties["video-crop"]
last_has_vid = has_vid
if not spawned and not disabled and options.spawn_first and resized then
spawn(mp.get_property_number("time-pos", 0))
file_timer:resume()
end
end
local function update_property(name, value)
properties[name] = value
end
local function update_property_dirty(name, value)
properties[name] = value
dirty = true
if name == "tone-mapping" then
last_tone_mapping = nil
end
end
local function update_tracklist(name, value)
-- current-tracks shim
for _, track in ipairs(value) do
if track.type == "video" and track.selected then
properties["current-tracks/video"] = track
return
end
end
end
local function sync_changes(prop, val)
update_property(prop, val)
if val == nil then return end
if type(val) == "boolean" then
if prop == "vid" then
has_vid = 0
last_has_vid = 0
info(effective_w, effective_h)
clear()
return
end
val = val and "yes" or "no"
end
if prop == "vid" then
has_vid = 1
end
if not spawned then return end
run("set "..prop.." "..val)
dirty = true
end
local function file_load()
clear()
spawned = false
real_w, real_h = nil, nil
last_real_w, last_real_h = nil, nil
last_tone_mapping = nil
last_seek_time = nil
if info_timer then
info_timer:kill()
info_timer = nil
end
calc_dimensions()
info(effective_w, effective_h)
end
local function shutdown()
run("quit")
remove_thumbnail_files()
if os_name ~= "windows" then
os.remove(options.socket)
os.remove(options.socket..".run")
end
end
local function on_duration(prop, val)
allow_fast_seek = (val or 30) >= 30
end
mp.observe_property("current-tracks/video", "native", function(name, value)
if pre_0_33_0 then
mp.unobserve_property(update_tracklist)
pre_0_33_0 = false
end
update_property(name, value)
end)
mp.observe_property("track-list", "native", update_tracklist)
mp.observe_property("display-hidpi-scale", "native", update_property_dirty)
mp.observe_property("video-out-params", "native", update_property_dirty)
mp.observe_property("video-params", "native", update_property_dirty)
mp.observe_property("vf", "native", update_property_dirty)
mp.observe_property("tone-mapping", "native", update_property_dirty)
mp.observe_property("demuxer-via-network", "native", update_property)
mp.observe_property("stream-open-filename", "native", update_property)
mp.observe_property("macos-app-activation-policy", "native", update_property)
mp.observe_property("current-vo", "native", update_property)
mp.observe_property("video-rotate", "native", update_property)
mp.observe_property("video-crop", "native", update_property)
mp.observe_property("path", "native", update_property)
mp.observe_property("vid", "native", sync_changes)
mp.observe_property("edition", "native", sync_changes)
mp.observe_property("duration", "native", on_duration)
mp.register_script_message("thumb", thumb)
mp.register_script_message("clear", clear)
mp.register_event("file-loaded", file_load)
mp.register_event("shutdown", shutdown)
mp.register_idle(watch_changes)

View file

@ -1,405 +0,0 @@
{
"a": "阿啊呵腌嗄锕錒",
"ai": "爱唉挨碍哀矮埃哎艾癌隘蔼嗳皑霭捱暧瑷娭砹锿嫒薆䔽㤅鴱㗨藹㕌磑礙硋䑂愛壒㘷叆靉䨠毐塧靄璦㱯䶣瞹䀳濭溰溾曖昹啀噯嘊㗒㝶䝽敱敳賹懓懝㢊銰鑀鱫鎄皧皚馤躷䅬㿄凒娾嬡伌㑸僾餲䬵譪譺",
"an": "安按案暗岸氨俺铵胺鞍黯庵桉谙鮟鹌咹犴广厂埯揞菴蓭荌萻葊隌㸩䮗㱘鵪豻貋腤雸堓垵䎨玵䁆洝晻唵啽㽢罯㟁屵䯥峖鞌䅁錌銨䅖馣痷鶕闇媕㜝盫儑侒䬓偣韽盦䎏䜙諳誝",
"ang": "昂肮盎䩕䒢䭹䭺䀚昻㦹㼜骯岇醠㭿枊䍩仰",
"ao": "傲熬凹遨嗷奥拗澳袄懊坳敖翱螯鳌鏖岙媪鏊骜艹聱獒廒蔜芺隞隩䮯厫磝䦋奡镺䐿䞝垇㘬墺㘭璈嗸嶅䫨㥿驁鰲鷔䵅摮嫯鼇謷䁱滶澚㕭軪䯠㟼㠂㠗岰慠㤇爊襖䥝獓翶擙抝䚫梎柪翺嶴䴈奧㿰㜜媼㜩㑃謸䜒",
"ba": "把八吧巴爸罢拔霸坝叭芭扒跋疤靶耙粑笆钯伯茇菝灞岜鲅捌魃䩻䩗夿䳊䃻㔜胈鼥壩垻豝玐㶚蚆㖠跁䟦哵罷軷㞎炦鈀鲃䥯䰾鮁䳁䱝魞釟抜㧊扷覇柭欛朳叐矲䆉羓䇑丷妭颰癹仈弝詙",
"bai": "白百摆败拜柏呗掰伯稗捭佰薭䒔㼣㓦瓸㗗㗑贁㠔䢙敗韛粨庍粺䙓襬猈拝㼟擺䳆挀㿟㧳栢䴽竡絔",
"ban": "办般半班板伴版搬斑扮颁瓣拌扳绊坂阪舨瘢柈钣癍靽䕰㚘瓪湴昄蝂岅肦怑粄䉽魬鈑鉡㩯㸞秚褩螌辦㪵闆辬姅頒鳻攽䬳絆斒",
"bang": "帮邦膀棒傍榜绑梆磅蚌旁镑谤浜蒡䧛䂜幚邫垹鞤幇幫䎧塝玤蜯䖫䟺髈䰷鎊挷捠搒㯁㭋㮄棓牓稖艕㔙㾦綁縍謗彭",
"bao": "保报包胞宝暴抱薄剥炮爆饱堡孢豹瀑刨鲍苞雹葆曝褒鸨褓煲龅趵勹蕔菢藵犦髱䨌䨔㙅靌報堢㙸虣珤㻄齙㵡㿺曓㫧蚫骲鳵怉䎂寳寚寶䴐宲窇䥤鑤㲒鮑䳈鉋铇勽䤖枹䈏㲏忁笣䪨闁媬儤賲䳰佨飹飽䭋駂鴇剝緥袌裦襃",
"bei": "被北备背倍悲贝杯辈臂卑碑呗狈惫钡悖孛蓓焙陂碚褙勃鞴鐾庳鹎邶䔒鞁藣苝犕㸬㸽牬盃愂䎬䎱琲㰆珼䁅輩䩀㻗㶔昁蛽䠙唄䡶㽡郥骳貝㤳糒禙鋇䰽狽㔨鉳㼎鵯揹柸桮梖椑㸢㓈㾱鄁軰㛝僃備憊㷶偹俻偝㣁䋳誖",
"ben": "本奔笨苯贲坌夯畚锛奙逩坋㱵渀漰泍㤓㡷錛撪㨧捹桳㮺翉楍栟犇倴䬱",
"beng": "崩蹦绷甭迸泵嘣甏菶䩬鞛奟䳞埲䨻塴埄琫㱶琣嗙嵭㷯䙀祊鏰镚甮揼逬䭰痭閍伻㑟綳䋽繃絣蚌",
"bi": "比必笔毕避壁秘闭鼻币彼逼辟臂泌碧弊蔽鄙毙弼痹庇陛璧婢敝匕俾裨荸吡哔蓖贲襞铋秕毖愎髀篦睥畀妣筚薜萆芘荜滗濞跸嬖狴箅舭鞸䩛蓽㳼萞苾䕗䎵聛䧗驆駜䮡夶髲䭮觱㗉皕䏢腷毴貏䏶賁堛䟆㙄㘩㻫豍珌㱸㻶㹃睤䁹䀣湢滭幤㵥獘斃鄨幣鷩潷䨆沘㡀畢鷝㪤䖩螕蜌啚蹕䟤躃䠋嗶咇罼奰㘠貱䯗畁㡙㠲贔赑怶愊韠䪐躄繴㵨鼊怭屄邲煏熚廦䊧粃襅袐襣禆䃾鲾鏎鐴鉍鰏鮅獙鎞㧙魓㪏柀楅䣥㯇㮿柲榌㮰䵄朼梐䫁篳馝䇷箆筆䄶閉閇㓖閟痺䦘疕疪㚰妼鵖嬶佊偪朇佖䬛䫾饆飶㢰䋔㢶弻彃縪鄪䌟綼㿫毞坒粊㢸䘡詖诐佛拂",
"bian": "变便边遍编辩辨鞭扁贬辫蝙匾卞鳊汴砭弁苄碥忭煸褊窆笾缏䒪鞕䛒藊萹䪻鴘㺹玣㻞䁵㳎覍汳㝸㴜昪䡢峅貶惼炞糄鯾鯿獱猵鍽㣐抃揙㭓牑邉邊釆籩艑䉸箯徧稨閞㵷㦚辡辧辮辯緶編㲢甂変諚變",
"biao": "表标彪裱婊飚飙镖膘鳔俵骠镳飑髟瘭䔸藨蔈骉驫飆猋嫑磦脿爂臕墂㯱滮淲瀌贆幖㟽㠒飊熛褾錶鑣鏢㧼摽㯹標檦穮儦飇颩颮颷飈諘謤䞄",
"bie": "别憋瘪鳖蹩虌莂䏟蟞鱉龞彆鼈蛂䠥別襒䋢徶䭱䉲癟㿜㢼",
"bin": "宾滨斌彬濒缤鬓槟殡摈膑邠玢份频髌豳镔傧髩鬢鬂臏䐔霦豩璸瑸殯頻虨瀕濱濵汃髕賓顮䚔賔鑌擯檳梹椕儐繽",
"bing": "并病兵冰饼丙柄炳秉禀屏槟摒邴鞆鞞苪䓑陃靐垪眪昞昺蛃䗒怲庰寎窉鈵鮩鋲鉼掤抦㨀棅栤䴵幷䈂並竝偋倂併仒傡餠餅仌䋑氷稟誁",
"bo": "波伯播剥博玻勃拨柏脖卜搏泊驳膊舶簿渤簸菠箔跛薄钵铂僰帛礴饽钹亳啵檗鹁踣擘䪇葧萡蘗蔔㹀䂍䮂䮀駁駮驋礡盋䰊䫊㝿砵䶈肑胉䑈䞳郣鵓㪍䢌㱟碆浡㴾溊淿謈㬧㬍䗚䟛蹳嚗㗘㖕䯋髉髆㟑嶓懪孹糪愽㶿煿袹襮袯䙏襏鑮䥬鈸鋍鲌馎鮊鱍鉑鎛镈鉢狛猼瓟瓝㩭挬㩧撥欂桲秡䢪缽簙牔䭯馛馞䒄艊䍨䪬䍸癷侼癶仢僠䭦䬪餑餺紴䊿袰譒佛",
"bu": "不部步布补捕卜哺埔怖簿埠钚卟逋晡钸醭瓿䪁荹蔀䏽㘵埗㙛㻉歨歩堡䴝鳪䀯㳍吥咘踄轐峬䝵䪔悑庯䊇廍補鈈鈽錻鸔抪捗㨐柨鵏䴺䍌䒈䑰篰㾟勏郶䳝㚴佈䬏餔餢䋠誧",
"ca": "擦嚓礤遪礸䟃䵽攃",
"cai": "才采材财彩菜裁猜蔡踩睬䰂毝䐆埰䞗啋跴財㥒寀採棌䴭䣋㒲婇倸偲䌨綵䌽纔縩",
"can": "参残餐惨蚕灿掺惭璨孱粲骖黪薒䣟朁蠶叄參㕘叅驂䏼蝅蠺䗞䘉殘㱚㻮㣓䝳㛑澯湌㘔喰㽩黲慙䳻㨻㥇憯慘慚㦧燦爘䙁䗝㺑穇䅟䑶㿊䍼飡䫮㜗嬠傪儏䬫謲䛹",
"cang": "藏苍仓舱沧臧伧蒼㶓㵴濸滄螥嵢賶鑶獊欌艙䅮凔仺鸧傖倉鶬䢢",
"cao": "草操曹槽糙嘈漕螬艚蓸䏆艸騲䐬鼜䎭曺鄵嶆愺慅慒懆褿襙䄚鏪撡㯥肏䒑㜖",
"ce": "策测侧册厕栅恻拆䔴荝萴萗蓛厠䜺測畟冊㥽夨惻憡廁粣䊂㨲拺㩍敇筴䇲䈟笧筞簎箣側",
"cen": "参岑涔䃡䨙埁㻸嵾䯔㞥䲋䤁䅾篸笒",
"ceng": "层曾蹭噌驓䁬㬝嶒層䉕㣒竲",
"cha": "差察查茶插叉诧岔刹喳茬嚓楂杈碴汊搽衩姹槎馇镲锸猹檫靫䕓䓭䒲䰈䑘垞䶪䁟嗏䟕蹅嵖㣾㤞㢒㢎㢉䆛銟䲦䤩鑔鍤扠剎挿揷査臿䊬秅䑡艖䡨疀奼侘偛餷詧紁㪯詫㛳㫅",
"chai": "差柴拆钗豺侪虿瘥茝芆䓱蠆䘍袃肞㼮祡㳗囆喍釵犲㾹儕㑪訍",
"chan": "产颤阐缠禅铲掺潺馋蝉搀蟾忏谄孱谗巉廛羼崭蒇骣觇澶躔冁婵单剗蕆䩶韂䵐苂䧯㹌䣑硟䐮䑎壥㙻㶣㙴刬䀡覘㢟䂁湹瀍瀺潹㵌灛滻浐㬄蟐蟬螹旵䠨囅丳嚵䡲磛䡪幝幨辿嵼懴䪜㦃懺煘鄽㢆燀裧襜䥀酁劖毚䤫䱿鑱镵㹽鋋鋓獑㺥鏟摻摲攙摌醦䤘䊲棎欃梴㯆䴼㸥艬簅闡閳産剷嬋儳饞儃緾繟纏纒產譂顫諂䜛讒誗讇斺",
"chang": "长常场厂唱昌肠偿尝倡畅倘敞淌猖怅嫦娼氅菖昶徜鲳惝苌鬯阊伥萇䩨䕋長䯴镸瓺兏厰腸膓㙊場鼚塲瑺瑒琩玚仧淐甞嘗㦂䗅暢㫤䠆䠀嚐畼悵韔廠焻裮鋹鲿錩锠鱨鯧椙閶倀仩僘償誯裳",
"chao": "朝超潮吵巢抄嘲剿炒钞绰晁焯耖怊焣㷅䏚䎐眧巣漅鼌鼂罺轈巐䬤煼㶤窲窼觘鈔䰫樔麨牊䄻鄛欩仯仦弨謿訬",
"che": "车彻撤扯澈掣尺屮砗坼莗㱌䧪聅䨁硨䞣䰩頙迠瞮䁤㵔蛼㬚唓車㥉爡烢䚢撦㨋硩㿭㯙䑲䒆勶徹㾝偖伡俥㔭䋲䛸䜠",
"chen": "称陈沉晨臣尘趁衬辰嗔琛抻伧谶碜宸郴谌忱龀榇茞蔯莀䢻莐薼䒞陳螴敶磣䣅㲀㫳䢈敐硶䫖夦䢅䐜墋趂霃齓齔瞋㴴鷐迧曟踸䟢趻㕴嚫軙贂賝䞋愖煁麎塵襯䆣鍖鈂䤟捵栕樄桭梣棽櫬䚘䑣瘎疢㽸㧱儭諶䜟謓訦諃讖沈",
"cheng": "成程称城承诚呈乘惩撑澄秤橙逞丞骋盛瞠铛塍柽埕琤净抢蛏裎铖酲枨荿䔲䧕阷㞼騁䮪騬郕䫆㼩碀脭爯頳䞓赪赬塖堘珹靗珵睈䀕䁎洆浾泟澂㲂牚瀓溗蟶晿䗊畻峸憆悜憕庱宬窚竀䆑䆵䆸䄇鋮鐣鏿鯎掁摚撐挰㨃揨檉棖檙橕棦朾乗筬稱罉穪䇸徎懲娍偁侱㐼饓僜絾緽誠椉",
"chi": "吃持池尺赤迟斥齿翅驰耻痴弛炽哧侈嗤叱敕啻饬笞踟柢呎茌褫鸱勅墀蚩蚩豉眵螭魑匙篪瘛媸傺荎䠠㔑䔟䧝妛恥欼馳䮻䮈肔胵腟胣䐤趩赿䞾灻垑漦雴鵄䜵䜻彨彲銐殦䶔齝齒歯瞝懘㳏湁蚇蚳喫噄䟷翤叺㽚㞿㞴貾㟂恜翄㓾遲翨杘遅遟憏迡烾㢁㶴粚㡿㢋熾裭䙙袳鴟㱀䤲鍉卶鉹㺈鉓瓻䰡抶摛攡㮛鶒慗鷘遫㓼麶勑䳵竾䑛䇪箎筂䈕䇼黐䪧痸癡侙䶵伬䬜飭㒆㘜䊼絺㢮訵㙜䜄謘袲誺䛂",
"chong": "重充冲虫崇涌宠憧忡舂铳种茺艟隀憃埫珫沖漴浺㳘蟲蝩蹖嘃罿㓽翀爞崈寵褈銃摏揰㧤䳯䖝衝㹐緟䌬",
"chou": "抽筹仇丑愁臭酬畴瞅绸稠踌惆帱瘳俦雠䓓薵菗䔏遚魗㦞㐜殠矁㵞躊吜疇幬㤽懤燽䊭裯䲖鮘㿧㩅皗搊㨶梼檮醻酧醜椆杽栦籌䇺臰篘䪮嬦㛶丒儔䀺偢犨讐雔雦犫讎䌧綢紬䌷絒詶",
"chu": "出处除初础助楚触畜储厨锄橱雏躇矗搐刍蜍怵滁黜绌杵蹰亍憷樗楮蒢蒭䢺㔘欪䧁䮞犓㕑㕏礎貙臅㙇埱趎耡䎤㼥䎝豠豖珿䜴璴齣齭齼敊䖏處泏濋㶆滀蟵䟞䠧躕䟣嘼㗰歜㡡幮岀㤕㤘廚䊰䙘䙕禇鶵芻雛鋤鉏㐥觸㹼摴斶櫉櫥䠂椘檚榋篨䅳処䦌竐竌閦媰俶儊儲傗絀諔鄐",
"chuai": "揣啜踹膪搋膗㪜㪓䦤䦟䦷",
"chuan": "传船穿川串喘椽氚钏舛遄舡巛荈堾玔瑏㱛䁣汌暷踳圌輲歂㼷賗釧猭㯌篅舩僢傳剶鶨",
"chuang": "创床窗闯疮怆磢䃥䚎刱䎫㵂噇䡴㡖愴窓窻摐牎牕䇬剙剏闖䚒牀瘡刅傸䭚創幢",
"chui": "吹垂锤椎炊捶槌陲棰菙㝽腄䞼䶴㓃錘鎚搥桘㩾䳠䍋埀䄲箠㥨龡倕顀",
"chun": "春纯唇醇蠢淳椿莼鹑蝽䔚䓐萶萅蓴蒓陙㸪犉脣䫃惷䐏䏝䐇䏛旾瑃睶㵮浱漘滣湻暙㖺輴賰䞐䄝䥎鰆鯙錞㿤鶞槆杶䣩䣨醕櫄橁箺䦮媋偆純㝄鶉㝇",
"chuo": "戳绰辍龊啜淖踔辶䓎歠䮕磭䃗辵趠繛齪逴涰嚽踀哾輟惙䆯鑡㚟㲋擉酫䂐䄪䍳䇍婥娖娕餟䋘綽",
"ci": "此次差词刺磁辞雌慈兹瓷赐伺疵呲糍祠茨鹚䓧㹂茦莿薋䦻㤵辝䰍䯸䂣礠㓨辭辤蛓趀䨏珁玼刾䧳㘹䖪㠿鮆鴜䳄飺泚濨蠀䗹螆跐㘂骴髊賜䛐㞖䲿㡹庛㢀皉㩞朿柌栨䆅䈘齹垐䳐餈鶿鷀甆嬨佌偨佽䭣縒絘詞",
"cong": "从匆丛聪葱囱淙熜琮苁骢璁枞藂䕺茐蔥蓯孮聦聰聡騘驄瑽瞛潈潀灇潨漗漎蟌暰䟲賩悰愡憁爜叢賨錝鍯怱鏓鏦欉樷樬樅棇徔悤囪徖䉘篵従從䳷㼻婃忩繱誴謥",
"cou": "凑腠辏楱湊㫶輳",
"cu": "促粗簇醋卒蹙猝蹴徂趣趋蔟殂䓚觕㗤顣䃚䢐脨趗鼀䠞踧踿䠓噈怚䎌憱麤䙯䥄麁䥘䟟㰗橻瘄瘯媨麄䬨縬蹵䛤誎",
"cuan": "窜篡攒蹿撺爨镩汆䰖㸑殩㵀躥㠝巑熶竄䆘鑹攛櫕欑㭫簒穳",
"cui": "催翠脆粹崔摧萃悴瘁璀啐淬毳榱䃀磪䂱膵膬䄟㯔臎脃脺趡墔琗㧘㱖㵏漼濢㳃啛嵟慛㥞忰翆㷃䊫粋㷪焠㝮襊竁鏙皠㯜槯䧽䆊凗疩伜倅紣縗缞綷顇衰",
"cun": "存村寸忖皴吋刌壿邨膥澊踆籿拵䍎竴侟",
"cuo": "错措挫搓撮磋锉蹉矬厝脞鹾鹾嵯痤蔖剒逪莡蒫莝遳蓌䂳䐣瑳䣜虘鹺睉䠡䟶㽨嵳㟇錯䱜鎈銼醝䴾酂酇㿷剉夎",
"da": "大打达答搭瘩嗒哒鞑沓耷惮靼跶褡怛笪妲荙韃䩢薘剳荅䃮迖羍迏䐛䐊垯墶㙮逹達溚蟽噠迚呾咑䵣䳴眔㟷燵炟匒鎝鐽鎉撘㯚笚䑽龖龘㾑㜓㿯畣繨詚亣畗",
"dai": "代带待袋戴呆贷逮歹岱傣玳怠黛殆迨甙棣呔诒埭毒大绐帶䒫貣㞭黱叇霴靆瑇帯㻖瀻蝳㫹曃蚮蹛跢軩軑轪軚獃懛廗襶䚟䚞鴏㯂簤艜䈆㿃垈帒貸柋㐲侢㶡紿緿",
"dan": "但单担弹蛋淡胆丹旦氮诞耽郸掸惮疸眈赕澹啖箪膻石萏聃殚瘅儋蓞䩥匰耼聸馾駳髧砃䃫㽎腅膽䨢霮䨵玬殫頕㴷単泹㵅鴠㫜啿㗖鄲單噉㕪啗嘾唌嚪黮黕黵帎賧贉刐饏疍憚憺㡺瓭沊㱽褝襌衴窞禫甔觛䱋狚㺗撣㲷抌擔撢酖柦䄷䉞蜑簞䉷躭癉癚媅妉僤伔䭛餤弾彈紞繵訑勯亶㔊誕",
"dang": "当党荡挡档裆铛宕噹菪砀凼谠蘯蕩礑碭䑗雼圵趤壋垱璫珰瞊澢灙盪璗䣊䣣當黨瓽潒逿蟷嵣氹愓襠鐺擋攩檔欓簜簹筜艡䦒闣㜭婸儅譡讜",
"dao": "到道导倒岛刀蹈稻盗捣叨悼祷焘氘捯纛刂忉菿陦隯﨩隝䧂䲽壔翿燾瓙盜螩翢嶹嶌嶋禱禂鱽島㠀魛釖擣搗椡槝檤朷稲軇艔衜舠衟㿒導噵䆃辺䌦",
"de": "的地得德嘚底锝㤫悳惪㥁䙸䙷淂㝵㥀鍀㯖棏徳恴",
"dei": "得嘚",
"deng": "等灯登邓瞪凳澄蹬噔磴戥嶝镫簦䒭隥䮴墱璒䠬燈鐙櫈艠竳嬁鄧㲪覴豋",
"di": "的地第提低底敌帝弟抵递滴迪堤蒂缔笛涤狄嘀谛娣嫡邸诋砥棣碲柢睇骶荻觌坻氐镝籴羝蔕䩘鞮靮䩚蔋苖菧慸遰菂苐蔐藡隄聜阺墬埅䮤馰牴㹍髢䯼磾厎奃䂡腣坘䞶趆覿䨤埞墑䶍豴玓珶眱䴞䀿坔滌螮蝃㼵䗖蝭旳踶䟡蹢嚁呧唙啲䵠軧䍕頔嶳埊廸岻怟鸐䊮䣌㡳焍袛祶禘鉪㪆䢑釱觝䏑鯳䱃䱱鏑摕逓遞掋拞䀸梊杕枤㭽梑樀楴㰅㣙彽秪䑭䑯糴䨀媂僀仾俤偙弤㢩締詆啇敵甋遆諦翟",
"dia": "嗲",
"dian": "点电典店淀颠殿垫奠甸碘佃滇惦巅癫掂踮玷靛钿癜阽坫簟蒧蕇䓦䧃驔厧磹㼭䟍顛㒹電墊琔齻奌敁㓠澱㵤㶘蜔蹎跕嚸㸃點敟巔嵮巓壂㞟㥆㝪鈿攧槙椣橂槇䍄癲瘨㚲婰婝傎顚扂",
"diao": "掉雕吊钓刁叼调碉凋貂鲷屌铞铫藋䔙蓧䂽奝䂪鼦雿琱㪕瞗汈蛁虭䵲彫鵰䘟窎窵鋽銱錭鑃鯛魡鮉銚釣㹿鈟扚䠼簓䉆竨瘹刟鳭㒛伄弔盄弴調訋",
"die": "爹跌叠蝶迭碟谍喋牒堞蹀垤耋鲽瓞㦶戜苵㲲䴑䮢镻胅䏲臷趃䞕耊褺䠟䲀䞇㻡殜眰眣蜨曡㬪螲㫼昳哋咥跮疂氎疊疉畳嵽峌幉㥈惵㦅恎㷸褋䘭㲳鰈䳀挕㩹㩸楪㭯鴩艓牃㑙絰绖諜詄佚",
"ding": "定顶丁订钉盯叮鼎锭啶腚仃町铤酊疔碇耵玎靪薡萣艼聢䦺矴磸碠鼑濎㴿㫀蝊虰帄嵿忊顁㝎鐤饤錠釘頂㼗㐉椗奵飣訂",
"diu": "丢铥丟銩",
"dong": "动东冬洞懂冻董咚栋侗峒恫胴氡鸫硐胨垌岽菄苳蕫駧䂢腖霘鼕䞒埬涷湩蝀昸㖦㗢戙迵㢥崬崠鯟鮗挏氭㨂東㼯鶇鶫棟動徚䅍箽笗㐑䳉䵔㓊凍䍶嬞姛㜱娻㑈倲働諌",
"dou": "都斗读豆抖兜陡逗窦蚪痘渎吋蔸篼钭䕱荳䕆阧脰郖毭㪷㐙鬦鬪鬥鬬鬭浢唗唞吺斣㞳㢄㷆竇䄈饾鈄㨮兠梪酘橷枓乧闘閗㛒餖䬦䛠",
"du": "度独读毒督渡杜肚堵赌嘟笃睹妒都镀竺犊渎牍蠹黩阇芏髑椟靯韇䪅匵䓯荰犢㸿騳䮷䀾䐗皾䢱蠧䲧覩剢瓄琽㱩殰殬裻錖瀆涜䟻黷䫳賭厾韣韥䙱䄍鑟鍍獨贕櫝醏螙篤牘䅊秺䈞凟闍㾄妬嬻豄讀讟読",
"duan": "断段短端锻缎煅椴簖葮碫腶塅㱭瑖躖䠪耑褍鍴鍛毈籪媏偳緞斷㫁",
"dui": "对队堆兑碓敦追怼镦憝䔪薱隊陮磓䨺䨴垖塠㙂㳔㵽濧瀩㬣轛䯟㠚㟋憞䊚對懟祋鐓䇤頧鴭痽䇏兊兌䬈䬽綐鐜対譵譈",
"dun": "盾顿吨蹲敦钝墩囤沌遁盹炖趸惇砘礅躉驐犜碷遯㬿逇頓潡蜳噸踲蹾㥫庉燉鈍䤜獤撴伅墪撉",
"duo": "多夺朵躲踱度堕惰哆舵跺垛咄掇铎剁哚柁裰缍䩔䩣䒳墮陏陊刴朶敠毲剟鵽敪鬌奲尮奪䐾垜㙍趓㙐埵㻧㻔畓㖼跥䠤喥嚉崜憜墯㥩剫䙃䙟䙤䤻鐸饳鈬䫂䤪挅㧷挆柮桗椯㔍軃躱䅜䑨㣞敚凙䍴痥㛆夛㛊敓飿綞嚲亸䯬隋",
"e": "额恶俄饿呃鹅扼厄蛾娥峨愕鳄鄂遏萼腭颚讹噩谔婀锷垩轭屙阿咹鹗苊莪锇䩹䳬䓊㼢蕚䔾䕏阨鵈娿阸騀頋阏砐砈㕎礘磀硆砨㼂妿䞩堨堮迗䝈豟堊蝁惡琧悪䫷㱦珴齶歺睋湂涐蚅歞噁卾㓵顎咢鶚遌覨㗁䣞遻㖾吪呝軛囮軶岋㡋崿㟧㠋㟯峉峩㦍㷈廅額頞䆓䄉鈪匎㔩鑩鍔䱮鰪鱷鰐䳗䳘魤鋨鈋擜搹㩵㼰皒搤㧖枙櫮㮙䙳齃頟䖸鵝鵞䑥䑪閼妸姶僫偔餓餩譌讍䛖諤戹誐訛哦",
"ei": "诶欸",
"en": "嗯恩摁蒽奀峎䊐煾䅰䭡䭓䬶",
"er": "而二儿尔耳饵迩洱贰鲕珥鸸铒佴荋貳弍薾聏陑毦隭刵䎶駬䮘髶髵耏鴯䏪胹兒趰弐貮邇爾児洏咡㖇唲輀轜峏粫袻鉺鮞㧫樲栮㮕栭䣵尓衈㛅䎟㜨㚷䎠㒃侕尒餌䋙䌺㢽䋩誀",
"fa": "发法乏罚伐阀筏砝珐垡䒥藅茷蕟髪髮䂲坺㘺墢琺沷㳒灋浌㕹罸罰峜彂鍅瞂䣹栰橃笩䇅冹疺閥㛲姂佱発發傠",
"fan": "反范饭犯翻繁凡泛番烦返贩帆藩梵樊蕃矾幡钒畈璠蘩燔蹯匥薠䒦㝃軬䮳颿䭵膰䐪墦䪤凣䀟㴀䀀氾滼瀿盕汎噃㕨輽䡊轓軓㠶販䪛㤆憣忛煩籵畨䊩襎㼝鱕㸋鐇㺕釩払䣲礬蠜䫶鐢棥橎柉杋笲䉊笵籓範勫飜鷭䉒舧舤凢瀪緐䌓㶗䋣㽹羳嬎㜶嬏奿仮飯飰繙䋦䛀旙旛訉拚",
"fang": "方放房防仿访芳纺妨肪坊彷舫鲂钫匚枋邡㯐牥䦈髣眆淓汸昘昉蚄趽㕫㤃錺魴䲱鈁㧍堏㑂倣鶭紡瓬䢍鴋旊訪",
"fei": "非飞费肥废肺匪菲沸啡妃吠斐翡诽绯蜚扉霏腓痱悱芾榧狒淝鲱镄镄篚萉蕜䕁䕠陫騑騛䰁厞朏蜰䑔鼣胇靅奜猆靟䩁剕㐟䨽棐婓餥渄濷㵒蟦暃昲曊䠊胐㥱屝飛飝䨾廃廢裶䚨䤵鯡鐨㩌杮㭭櫠䈈馡䆏䉬癈疿婔俷緋㔗費誹䛍",
"fen": "分份奋粉纷愤氛芬粪坟焚吩酚忿汾雰玢鼢瀵鲼棼偾蕡䩿棻蒶隫㸮奮膹朌鼖䴅墳豮豶瞓濆昐蚡㖹轒幩帉岎憤翂燌黺糞黂㥹衯鐼鱝魵獖鈖㮥橨梤燓㷊枌馩馚躮秎羵㿎朆竕羒妢僨弅餴饙蚠炃紛䯨訜",
"feng": "风封丰锋峰奉凤缝蜂冯逢疯讽枫沣烽俸砜葑唪酆䒠䩼飌蘴碸䏎堼犎霻靊堸鴌琒盽湗灃溄浲漨㵯沨渢䟪鄷豐崶㡝賵赗峯㦀焨煈寷䙜鎽鋒鏠猦摓檒桻覂楓麷夆蠭㷭篈艂馮瘋妦仹凮凨凬鳳僼鳯風偑綘縫諷",
"fo": "佛坲梻仏",
"fou": "否不缶鴀䳕雬殕缹缻妚紑",
"fu": "复服夫富府父负副福妇附符付幅伏浮腐腹傅扶辐肤抚覆辅赋赴甫缚弗咐俯俘孵拂斧敷脯腑袱芙氟孚蝠阜匐麸釜涪馥凫驸茯讣蝮蚨苻呋罘稃芾跗拊茀趺伕鄜莩菔莩阝砩郛滏蜉呒幞赙赙怫黻黼祓鳆鲋桴绂艴绋荂芣葍䕎䓛䔰萯荴蕧䧞䮛駙䭸䯱㬼䯽髴砆䩉㕊䂤㚕鵩胕䨗䞜䞯䞸䞞韨䘄㙏䨱垘坿䝾邞琈豧玞畐㽬鶝鬴巿玸鳺䫍膚虙㐢㜑澓洑泭㳇㫙蝜蜅蚹䗄蚥哹踾䟔䟮嘸㕮咈罦輻畉䡍䍖輔輹㟊賦帗賻㠅岪翇㤱䪙韍㤔烰粰糐焤炥冨䘠袚褔衭襆複袝襥䃽禣祔鍢鈇頫負鰒鳧鮲鮒鮄鍑鳬鉜鉘䎅捬撫郙棴尃酜枎盙乶椨榑椱覄栿柎麬麩麱柫旉懯箙筟㓡䫝甶䠵䘀蛗峊鴔簠秿復稪艀䒇䒀䑧䵗彿笰乀竎㵗癁䦣㾈娐妋嬔婏媍婦䵾怤姇釡俛偩俌颫紱綒綍䋹䌿刜㪄縛䌗緮䋨絥弣紨紼諨訃㚆詂佛",
"ga": "嘎伽尬噶旮咖夹尕尜钆嘠錷釓魀玍",
"gai": "改该概盖钙溉芥丐垓赅戤陔葢蓋荄䏗瓂豥㕢䀭漑晐畡乢峐賅䪱忋祴鈣匃匄㧉摡槩槪㮣姟侅絠絯郂㱾賌該",
"gan": "感赶敢甘杆干肝乾柑竿赣尴苷秆橄坩擀绀酐泔玕灨旰矸澉淦疳䔈芉皯䃭尷尲趕幹榦倝迀鳱䲺攼尶盰澸漧㽏汵䵟骭䯎忓粓衦鳡鱤㺂魐檊桿䇞簳稈筸贑䤗贛凎仠凲紺詌",
"gang": "刚钢港纲岗杠缸冈扛肛戆罡筻犅牨矼堽堈䴚㽘㟵崗㟠剛岡焵焹釭䚗鎠鋼摃㧏掆槓㭎棡罁疘冮戅戇綱",
"gao": "高告搞稿膏糕羔镐篙睾皋诰槁藁锆杲缟槔郜菒䔌藳㚏夰䗣鼛櫜峼韟祮祰禞鋯鎬鷎㚖皐槹橰檺勂吿臯鷱筶㾸餻縞髙槀稾稁誥",
"ge": "个合各革格歌哥隔割葛阁戈胳颌鸽搁咯疙蛤骼铬膈嗝镉圪鬲硌盖哿塥虼袼搿舸䪂䩐鞈䕻戓㦴茖呄䧄牫騔㷴䐙肐䨣䘁䪺䫦臵鞷㵧滆滒䗘蛒㗆嗰轕輵㠷愅韚韐裓㝓䆟觡鎘亇饹鴚鮯鎶獦鉻犵匌挌㨰擱槅戨㢦櫊䈓㪾敋箇笴閣鴿䢔個佫佮彁諽䛋䛿謌",
"gei": "给給",
"gen": "根跟亘艮茛哏亙㫔揯搄㮓䫀",
"geng": "更耕耿庚梗哽埂羹赓颈鲠绠莄菮堩刯郠浭畊骾峺焿鹒賡鶊䱍䱎鯁䱭䱴挭椩㾘羮絚綆䌄緪縆䋁",
"gong": "工公共功供攻宫贡巩弓恭拱躬龚汞蚣珙肱红廾觥龷慐貢㔶䢼拲㭟䂬鞏䡗㧬㼦碽厷髸塨䢚㺬㫒唝嗊輁幊愩㤨熕宮觵匔匑栱㯯杛篢躳䇨㓋龏龔侊糼糿",
"gou": "构够句购狗沟勾钩拘苟垢篝枸媾佝诟笱岣鞲遘觏彀缑冓覯芶䃓豿撀㜌㝅㨌坸耇耉耈玽溝㳶蚼㗕啂㽛購䝭䞀韝煹㝤褠袧雊鈎鉤夠㺃搆構簼䑦痀姤緱訽詬",
"gu": "古故固顾姑骨鼓股谷孤估雇咕呱辜菇沽锢贾钴梏臌箍蛄汩蛊轱诂牯崮鸪鹘瞽痼鲴毂菰牿嘏罟觚酤巭薣盬㠬䓢蓇苽巬㠫夃㚉䜼䮩尳鴣㼋䀇脵皷鼔堌㯏䅽皼榖穀糓轂䍍䐨䶜䀦䵻䀰濲瀔淈泒蠱啒唃唂軲䡩䍛罛軱鶻崓愲祻鈷錮馉鮕鯝鈲䀜㧽扢橭棝榾柧杚箛稒笟篐㒴㽽凅㾶羖嫴傦餶逧僱䊺縎詁顧",
"gua": "挂瓜寡刮褂呱卦剐胍鸹括栝诖䒷劀騧趏坬颪啩踻叧罣冎剮歄㒷煱掛桰鴰䈑颳絓緺詿",
"guai": "怪拐乖䂯㽇罫恠叏夬㷇㧔柺枴箉䊽",
"guan": "关观管官惯馆贯冠灌罐棺斡倌纶矜盥莞鳏鹳掼涫䩪䪀鸛觀雚蒄覌礶瓘璭琯矔卝泴㴦潅丱䗆䗰躀輨䏓䎚悺慣爟㮡悹䙮䘾䙛窤祼鑵鳤鱹鱞鰥䲘錧鏆摜欟樌罆観筦䦎癏瘝痯関關闗舘館䌯遦貫毌䝺",
"guang": "光广逛胱犷潢咣桄茪黆炗垙珖洸㫛炚輄臦臩廣烡広灮炛銧獷姯僙俇",
"gui": "规贵归鬼桂轨柜硅龟跪瑰闺诡傀匮圭刽桧鲑癸皈炅鳜珪匦眭晷刿庋宄簋妫茥鞼匭蓕蘬㔳陒雟㸵騩䰎厬胿䝿㙺攰邽㪈郌䳏䞨垝昋鬹規槼嫢璝鬶椝瓌劌瞡瞆瞶䁛氿湀㲹蟡蛫螝貴䠩軌䯣䞈巂嶲恑庪廆袿䙆襘祪禬鑎䣀㩻觤亀鐀鱖鮭䲅鱥䤥猤摫撌㨳㧪櫃槻樻槶椢櫷檜筀歸龜䇈攱閨䍷䍯癐䐴嬀姽媯劊佹䌆詭帰",
"gun": "滚棍辊衮磙丨鲧绲蓘蔉䎾䃂㙥㯻睔滾䵪輥惃鯀鮌袞緄緷㫎䜇謴",
"guo": "国过果郭锅裹蝈埚帼聒虢椁腘粿掴蜾崞猓馘菓蔮聝䂸㞅䆐腂膕䐸堝墎㳀㶁淉漍濄蟈褁㖪㕵嘓啯㗻國囯輠囻囶圀幗過惈慖䙨鈛鍋鐹馃㚍懖摑楇䴹槨簂瘑䤋䬎餜彉綶彍涡",
"ha": "哈蛤虾铪鉿紦",
"hai": "还海孩害嗨亥骇咳氦嗐骸胲醢㜾駴駭㦟塰咍䯐㤥烸䱺㺔㨟㧡酼䠽䠹䇋妎饚餀",
"han": "含汉喊寒汗旱韩函涵罕憾焊憨翰撼邯悍捍酣瀚鼾蚶颔晗菡犴旰顸焓厂邗撖䕿䓿㽉䓍蔊莟顄凾圅馯駻厈䫲丆䏷䶃䐄爳䨡䖔㙳頇㙈垾韓㲦螒鶾䮧雗㙔䎯䧲琀䁔睅甝㵄漢涆澏浫㵎浛暵蜬虷㪋晘蜭蛿㘕㖤哻㘚㘎唅輚䍐崡嵅屽䍑㟏㟔熯㶰㸁䗙䘶䤴䥁釬銲魽鋎猂㺖鋡㨔扞皔㮀梒䈄馠筨兯閈闬㽳嫨㜦娢傼佄㒈㑵谽豃頷㼨䌍㢨䛞譀",
"hang": "行航杭巷夯沆吭绗颃苀垳䀪蚢䣈䟘貥㤚裄䴂魧筕笐䘕䦳絎斻頏迒䲳",
"hao": "好号毫耗豪浩郝壕嚎皓镐蒿嗥濠昊貉薅颢灏蚝嚆薃䒵茠薧聕䧚䧫䝞毜㬶䝥㘪淏㵆灝澔滈昦㬔暤暭晧曍䯫顥暠蠔㙱䪽號㕺噑哠嘷㞻㠙乚悎鰝獆獔獋皞皡皥皜㩝椃秏籇竓恏㚪侴䬉䜰傐儫㝀䚽鄗譹皋",
"he": "和合何河呵核喝荷吓贺赫盒颌褐鹤禾嗬壑诃涸阂阖劾貉龢翮菏盖盍曷纥蠚鞨䕣萂䒩䓼㹇䃒碋礉盇賀䶅貈䞦䚂㷤靏靎垎靍鸖齕㕡龁澕渮㵑䳚㬞螛毼㔠鹖㓭䫘鶡㕰嚇啝咊㗿哬嗃䵱䢗峆䳽㥺䪚㦦翯煂熆爀焃㷎籺粭熇燺袔寉鶴鑉釛鲄饸魺狢鉌皬㿣抲㭱㪃㰤㮫楁覈柇㭘㮝麧䴳篕䎋惒盉䅂闔癋閤閡姀郃敆頜㪉欱餄紇鶮訶訸詥謞苛",
"hei": "黑嘿嗨潶黒",
"hen": "很恨狠痕鞎䓳拫㯊佷詪",
"heng": "衡横恒哼亨珩鸻蘅桁㔰䒛胻脝㶇涥啈䯒恆悙烆䄓鑅撗橫鴴鵆姮䬖䬝",
"hong": "红洪宏轰鸿哄虹烘弘泓竑訇讧闳薨蕻荭黉鞃䩑葓䲨葒苰䧆耾硔翃䫺硡䃔䂫㬴黌垬霟霐䞑䨎玒沗玜䀧鬨澒鴻汯渱潂浤渹晎叿吰呍嚝㖓䍔䡌軣轟輷䡏屸羾灴䉺㶹粠焢翝䆖宖銾鉷鈜魟鋐鍧撔揈篊閧闀閎䪦竤闂妅娂仜䫹谾䜫谹谼紅紘纮㢬彋綋紭訌",
"hou": "后候厚猴侯喉吼逅篌齁骺堠鲎糇後瘊茩葔䂉㸸㕈鱟䞧豞睺洉㫗㬋䗔㗋㖃吽帿翵㤧翭䙈矦鲘䪷鮜鯸䳧銗犼㺅鍭郈垕㮢鄇䫛餱",
"hu": "互乎护呼户忽胡湖虎糊弧狐壶沪蝴葫瑚浒惚唬扈琥瓠囫鹄唿斛祜滹鄠鹕醐猢和许核觳虍轷岵怙煳烀鹱槲笏冱戽䩴芐萀㸦蔛匢匫䔯苸蔰䕶㕆鬍鶘鶦䭌綔瓳㪶䎁怘䮸膴䞱豰壺嗀縠㺉螜壷垀雽䨥䨼戸䁫虖歑虝雐鍙瀫沍淴汻䲵泘滬滸䗂昒昈㗅䠒嘑嘝嚛喖䍓軤幠恗䪝䊀䉿焀熩粐㝬寣隺鍸䚛鳠錿鱯鸌鰗魱鯱曶㫚㹱乕摢抇搰㿥䰧㨭楜㯛枑槴箶衚頶鵠䧼䇘戶䈸䉉乯簄㾰頀媩嫮嫭婟俿䬍餬䭍䭅弖絗護謼帍鳸㦿䛎戏",
"hua": "化话花划画华滑哗桦猾铧骅砉華鷨蕐黊蘤㭉䔢蒊驊硴夻磆䏦埖㓰䶤澅螖嘩㕦䠉㕷㕲呚㠏崋㟆㦊㦎糀鏵錵觟釫釪鋘䱻㚌撶摦搳㩇樺椛槬㮯枠杹䅿舙嬅婲畵畫劃婳姡嫿繣譁誮諣諙䛡話譮豁",
"huai": "坏怀淮槐徊踝蘾蘹䃶壊耲壞䴜瀤咶㠢懐懷櫰䈭㜳褱褢",
"huan": "还环换欢缓患幻唤焕寰桓痪宦涣豢獾浣奂洹圜鬟鹮垸萑漶逭锾鲩擐缳荁萈酄歡藧㿪㕕驩䭴䮝㹖貛䝠貆肒堚豲瓛環瑍雈睆䀨䀓澣澴㶎㵹渙㬊㬇㼫嚾喛喚還轘嵈䯘峘鴅懽㦥愌㡲糫煥䴟鵍寏䆠鍰䥧鐶镮奐烉鰀鯶鯇獂狟犿攌換梙槵㣪䈠歓䍺闤阛羦䦡瘓㓉孉嬛緩絙繯綄讙㪱",
"huang": "黄皇荒慌晃煌惶簧谎恍蝗磺凰隍幌徨潢璜湟肓篁蟥遑鳇癀䪄黃鷬葟㞷䮲騜奛䐵㬻䐠䑟墴塃趪䞹堭瑝䁜兤滉曂晄喤㡆崲䍿愰怳㤺熿䊣熀炾䊗宺鐄鎤鱑鰉鍠锽獚皝皩䳨㿠㨪揘榥櫎楻穔䅣艎韹㾠㾮媓偟餭䌙縨謊朚巟㠵衁諻詤",
"hui": "会回挥灰汇绘恢辉毁慧惠悔溃徽讳卉秽贿晦诙彗晖蛔桧诲喙洄荟珲蕙烩茴睢迴麾咴隳恚虺蟪缋蘳蔧薉匯㰥䕇藱薈隓䜐䧥芔䃣㥣靧䩈㩓毀毇䏨噕璤恵豗㱱㻅璯睳顪翽瞺頮颒滙湏洃泋潓輝濊瀈蛕㬩暳蚘蜖暉嚖嘒噅䫭囬廽逥圚廻㞧屷賄囘翙屶懳㤬憓恛翚翬烠烣燬㷐㷄煇燴寭袆䙡䙌褘禈鏸鐬䤧灳鮰獩㨤㩨㨹拻撝揮櫘槥檓橞檅楎篲䂕穢鰴幑䇻䅏徻闠阓痐瘣㜇彚媈嬒婎㒑僡會㑹佪儶餯㑰繢彙絵繪譿詼譭䛼譓䜋䛛諱詯誨堕",
"hun": "婚混昏魂浑棍荤馄珲诨溷阍葷蔒䧰鼲䰟琿殙睴睧尡渾涽䫟圂慁轋䡣昬睯忶㥵惛焝觨䚠掍㨡棔䴷䅙䅱閽婫倱俒㑮餛䛰諢",
"huo": "和活或火获货伙惑霍祸豁夥蠖嚯镬藿劐耠灬钬锪攉㦯韄䰥蒦騞奯剨臛耯靃眓矆矐䂄䁨濩湱瀖沎漷曤嚄嚿喐咟吙㗲㘞䯏旤雘㦜邩㸌煷窢䄀禍䄑䄆鑊䱛鈥鍃獲掝擭捇㨯檴䣶㯉穫秮䉟秳艧秴癨䦚閄彠彟佸俰貨䋭謋",
"ji": "机几基己期济及级计即极技记集际积纪急激既继击奇季鸡迹剂辑绩吉寄疾挤肌籍祭寂脊饥忌冀藉稽畸棘鲫叽圾嫉姬讥妓汲系伎缉唧骥羁髻悸瘠箕暨矶麂岌蓟亟戟跻诘犄荠稷畿霁嵇嵴屐蒺觊笈玑楫偈鱀勣芨咭其齐芰蕺剞赍殛乩洎虮戢跽哜墼鲚掎笄彐佶齑䓫䩯蘎鞿蘻蘮葪薊茤旡蕀蔇虀薺䓽焏際隮㤂䲯﨤㹄䯂驥䮺鳮䰏㞆㚡朞卙䦇惎諅磼磯䐀鶏膌䐕䐚鷄雞叝䨖趌䟌䞘䟇塉郆霵賷坖䣢耤耭垍賫㙫㙨霽㒫䢋㱞㻷㻑璣璾䶩茍㦸䁒㭰㲺㴕㴉湒濈瀱漃㳵泲鹡鶺漈潗済濟䗁螏蝍暩蟣嗘踖躤踑蹟蹐䠏躋跡㘍㗊㖢喞㗱嘰嚌羇羈轚擊檕罽輯毄㚻繋撃䍤䝸覬㡇䶓嶯㠖㞦㠍㥛忣㠱㥍丮鵋㞛愱懻妀庴廭㸄㲅襀襋禝禨錤觙觭銈銡鱾䤠鍓魥鰿魝魢鯚鯽鰶鱭鑙犱鏶鐖鑇㔕撠刏鬾魕㰟裚揤曁旣皀卽皍擠㨈鸄覉覊極㮟樭橶枅䤒檝㮨梞槣槉楖㭲檵機櫅䇫彶䚐嵆徛簊稘筓積臮箿稩躸䪢刉艥䒁鷑穊穄穖穧兾㾊痵癪㽺㾒㾵癠塈堲䳭姞䢳伋亼偮㑧飢饑谻㞃僟亽雧級綨績緁緝紀彑䋟継紒㡮幾㡭繼計韲齏剤劑齎齌㧀記誋譤譏䜞给",
"jia": "家加价假架甲夹佳嫁驾嘉贾钾稼颊伽挟迦枷荚戛拮浃胛袈痂颉镓岬笳珈蛱跏瘕袷葭恝郏铗莢䩡䕛斚犌戞㕅郟夾頰鵊㼪脥駕毠乫㔖鴐腵貑鴶㪴耞圿豭玾頬䁍䀹䀫浹泇蛺䖬唊斝䑝幏叚忦糘麚䴥裌鋏鉫鉀鎵猳拁抸扴㮖榎梜賈椵榢槚檟徦㿓婽傢價䛟",
"jian": "间见建件坚简渐减检践健尖监艰键肩兼鉴浅箭碱剪剑舰奸歼俭拣荐贱茧柬捡煎溅涧谏睑堑腱毽笺缄饯硷翦犍謇鲣僭锏缣囝鞯菅蒹戋戬湔趼踺蹇裥搛枧楗笕鹣牮谫戔韉靬韀鞬堅䵖㔋監鋻鍳鑒㯺譼虃囏艱蔪繭薦藆蕑蕳葌菺䧖䮿礷碊礛鬋䶠䩆礀磵礆堿麉䶬趝墹䵤鳽雃戩臶幵瑊珔䵡豜豣殱殲瑐蠒玪鹸鹻鹼見瞷睷瞼㓺瀳減洊瀐䤔漸濺瀽㶕澗湕㳨瀸暕鵑踐䟰跈轞䟅䭕賤䯛䯡賎帴㦗惤熞熸糋寋弿襺袸襉襇鑑鑬鳒鏩鰹鰔鰜鰎鑳㺝猏鐗鐧䥜鍵鐱鑯㨴挸揀擶揃㨵撿樫檻椷栫榗梘㰄椾検檢櫼箋㣤㔓䄯牋筧䅐馢籛䇟篯艦簡䉍徤䵛覵間覸冿鶼姧姦俴剣劍劎剱劒劔餞䬻䭠餰䭈㦰倹儉緘絸繝彅縑諓䛳譛鵳諫譾謭旔詃槛",
"jiang": "将讲江降奖蒋港匠疆浆姜僵酱桨缰绛犟强茳礓耩豇洚糨匞韁薑顜葁蔣䕬㹔膙塂壃䞪䙹畺殭䁰滰疅畕嵹翞糡鳉鱂摪摾橿櫤㯍夅䉃䒂奨醤㢡奬獎醬漿螀螿槳將傋䋌䥒繮勥謽絳弜弶講",
"jiao": "教叫较交觉角脚焦胶郊缴骄娇轿搅浇嚼校剿礁椒矫狡绞蕉酵窖饺跤佼侥皎蛟茭醮姣铰湫鲛峤艽噍挢敫徼僬鹪茮斠藠驕膠腳膲趭璬珓䂃䣤䴛䁶㳅灚澆漖䀊滘潐㬭曒蟜暞晈蟭䠛踋劋嘂嘄噭呌嘦轇轎較嶠㠐峧賋嶕嶣䪒憿憍煍烄燋䘨䆗窌䚩鱎鮫䥞獥鉸鐎㩰敎皭攪撹皦撟捁挍摷㰾譥釂㭂敽鷮敿矯徺臫笅穚簥筊㽲㽱虠䢒䴔鵁勦嬓嬌孂㚣僥龣儌餃鷦燞繳纐絞訆譑䜈",
"jie": "结解接阶界价节介姐借街揭届洁杰截皆戒捷竭劫桔藉诫秸睫楷芥婕拮孑诘疥嗟颉疖桀碣羯讦偈蚧毑袷家她卩喈骱鲒䕙鞊鞂蓵䔿菨莭㔾階卪岊犗礍䂝䯰䂶㛃镼砎䃈脻丯刦刧刼頡㔛劼㓤迼堺堦䣠琾疌玠䀷䁓潔尐滐蠽湝昅蛶蠘蜐蛣䗻蝔唶踕跲喼吤畍嶻崨幯㠹巀嵥岕悈屆㞯㦢㸅庎煯㝌衱袺褯衸㝏䥛觧鉣㘶鍻鎅鮚䰺䱄䲙魪狤擮㨗掲擑㨩掶搩杢㮮楬楐檞桝榤㮞椄徣䂒䅥節蠞稭㓗㾏㿍楶癤痎䇒媎媫嫅媘㑘倢偼䲸傑飷結䌖鶛誡訐詰誱謯䛺",
"jin": "进金今近仅紧尽禁劲津斤晋锦浸筋巾谨襟靳矜瑾烬噤缙觐馑堇荩卺赆廑衿钅槿妗蓳荕菫緊覲㝻歏黅藎䒺巹㹏矝厪㰹砛䐶墐壗晉㬜琎瑨殣琻勁珒璶璡齽䶖鹶漌溍浕濅堻濜㴆㬐䗯唫嚍䝲贐惍㶦煡燼寖䘳䆮祲觔釿錦釒㨷劤搢䖐䤐枃䫴㱈㯲㯸䑤凚嫤㶳盡䀆賮嬧僅仐侭伒僸饉䭙儘進縉䋮䌝紟謹䥆",
"jing": "经精境京静竟惊景睛镜径警晶劲竞净敬井颈茎鲸荆靖兢痉憬泾菁粳阱胫腈迳旌璟儆箐刭肼靓獍婧弪荊莖葏㢣蟼憼驚䔔聙頚㣏㕋脛鼱㘫坓汬丼璥靜靚䴖鶄殌璄巠剄頸鵛逕坙梷淨汫瀞㵾涇澋浄曔暻㬌踁䵞䡖幜麠麖宑穽鯨㹵猄鏡坕桱橸稉徑秔凈痙竸競竫竧妌婙婛俓傹経弳經綡䜘鶁亰旍誩",
"jiong": "炯窘迥炅颎冂扃蘏蘔褧駫駉澃䐃坰埛㷡煛泂浻煚㖥囧冋㢠冏䢛燛㤯烱逈㷗㓏㑋僒侰絅䌹綗熲顈",
"jiu": "就究九久旧酒救纠舅揪灸疚臼鸠厩赳韭咎桕啾柩鹫鬏玖阄僦匶萛韮匛䓘舊牞镹䊆䳔䳎慦㺩㺵殧齨䰗鬮㲃汣䡂㠇丩乆䊘㡱廏廐廄㶭麔䆒鯦勼匓捄摎㧕揂㩆欍柾朻樛杦舏䅢揫㐇鳩奺倃糾乣糺紤鷲䛮",
"ju": "具据局举剧句居巨距聚拒柜菊矩惧俱拘桔咀锯鞠橘踞驹沮瞿炬踽疽遽掬枸飓榘苣裾龃榉倨狙钜莒且车苴鞫犋雎琚屦窭锔醵椐讵蘜䕮䢹乬巪蒟輂埾陱聥犑駏驧駶駒䃊砠㪺䢸舉㐦擧鴡貗腒䏱鼳鼰毩毱弆壉趜埧㘲耟㠪歫䶙齟䶥郹䴗鶪㮂狊䋰勮豦劇愳虡眗䡞洰㳥挙湨澽涺泦泃淗趄昛蚷㬬蜛䗇蹫跙㘌躆跼跔踘啹罝㽤巈岠岨崌㞫鵙怇鶋懅懼䪕㥌屨㞐凥烥粔焗粷寠袓襷䆽窶䄔鉅鐻邭鋸鋦鮔匊䱟鮈鵴䱡據㩴㩀㨿挶䰬抅㐝拠檋櫸欅䣰䤎椇梮椈秬簴筥躹䅓艍䈮䵕閰姖娵㜘婮婅倶侷颶䜯繘詎䛯諊渠",
"juan": "卷倦捐圈娟鹃绢眷涓镌蠲鄄狷锩桊蔨菤奆朘腃臇埍睊睠淃瓹呟罥羂䳪脧惓慻焆㷷裐隽鋑䥴獧錈鎸鐫捲䚈䣺㯞䅌䡓勌劵䄅龹䖭帣巻餋弮勬絭姢䌸㢧絹㢾讂㪻",
"jue": "决觉绝掘嚼爵诀厥倔攫崛蕨獗撅噘抉镢蹶谲角孓噱橛珏矍鳜桷钁劂爝觖匷㓸芵蕝孒䦼矡駃砄蹷蟨憠鷢橜䐘䏣臄貜䏐䁷覺趉䞵䞷赽瑴䝌玨㻕玦亅䀗覐㵐決覚泬灍蟩䖼蚗虳噊䟾躩䠇趹爴䡈㟲嶡嶥崫㤜憰戄屩屫刔鴂爑㷾熦焳䙠䘿䆕䆢氒鐍鐝觼觮䦆鈌鴃玃㹟㩱挗㸕捔撧㰐㭾㭈櫭䍊䇶欮疦瘚弡彏䋉㔢絶㔃絕譎斍訣",
"jun": "军均菌君俊峻钧郡骏竣隽浚筠麇儁皲捃莙葰䕑陖皹駿鵕㕙碅㓴埈䝍㻒珺䜭濬汮㴫晙蜠蚐呁㽙畯賐懏燇麏麕皸軍袀㝦寯鲪銞馂鵔鮶鍕銁鈞攈攟棞桾箟箘䇹姰頵鵘覠㒞餕㑺雋龟",
"ka": "卡咔咖咯喀佧胩垰裃鉲䘔",
"kai": "开凯慨恺揩楷铠忾闿锴岂蒈垲剀锎䒓奒䐩塏䁗暟嘅䡷輆剴颽凱㡁嵦愷愾炌烗鎧㚊鎎鐦鍇開闓勓欬",
"kan": "看刊堪砍坎勘嵌侃槛瞰龛阚磡戡莰凵顑歁墈栞䶫鬫矙轗輡嵁崁惂冚欿衎㸝䘓㸔䀍竷闞龕偘",
"kang": "抗康炕扛慷亢糠鱇伉钪闶匟砊漮䡉囥嵻忼㱂粇㝩鏮犺鈧槺躿穅閌嫝邟㰠",
"kao": "考靠烤铐拷犒尻栲䐧攷丂洘䯌嵪㸆銬鲓鮳鯌䯪髛",
"ke": "可科克客刻课颗壳棵渴咳柯磕苛坷瞌窠蝌轲颏恪稞髁珂氪缂岢嗑剋尅呵骒溘蚵锞钶疴薖萪匼騍牱犐礚碦勊勀砢㕉堁殼殻㵣渇顆敤㪙趷礊軻嶱嵑㞹嵙峇愘炣㪡愙䙐錁翗鈳搕揢榼醘㐓㪼㤩衉艐痾㾧牁娔樖緙課頦",
"kei": "剋尅",
"ken": "肯恳垦啃龈裉㸧硍墾懇貇豤肻肎褃錹掯",
"keng": "坑吭铿硻阬牼硁硜䡰鏗鍞銵摼挳妔誙劥",
"kong": "空控孔恐箜倥崆鞚硿埪涳㤟悾鵼錓躻㸜",
"kou": "口扣寇叩抠佝蔻芤眍筘剾蔲瞉鷇㲄瞘滱䳟怐冦宼㓂窛釦敂䳹摳劶㔚簆彄",
"ku": "苦哭库枯裤酷窟挎骷绔袴刳堀喾䧊郀矻嚳㱠跍圐㠸庫廤㐣焅褲鮬狜楛桍䇢秙䵈瘔㒂俈絝",
"kua": "跨夸垮挎胯侉咵趶骻䯞銙舿姱誇䋀",
"kuai": "会快块筷脍侩狯哙蒯浍郐䓒巜膾凷墤㙕㙗塊圦㱮欳澮㬮噲䯤㟴廥糩鲙鱠獪擓㧟㔞䈛鄶䭝儈旝",
"kuan": "款宽髋䕀臗髖寛寬窾窽䥗䲌鑧䤭㯘歀梡欵",
"kuang": "况矿狂框旷筐眶匡邝哐圹诳劻夼贶贶纩诓匩邼硄礦砿壙眖矌洭黋況曠昿軭軖軦軠岲貺恇忹懭鄺懬爌䊯鋛鑛鉱㤮鵟狅抂䵃筺穬儣絖纊絋誆誑",
"kui": "亏溃愧奎魁馈葵窥盔傀匮逵夔喟睽喹聩揆篑岿馗蒉蝰暌跬悝愦䕚蘷藈匱蕢䕫虁聵聭聧骙騤犪尯磈㚝膭頍㙓刲䖯殨㕟虧潰晆䠑䟸躨蹞嘳顝䯓巋巙憒煃窺頯鍷鍨㨒䫥楏䤆櫆楑籄簣䈐䦱闚䍪㛻嬇媿戣鄈䳫饋餽䧶謉",
"kun": "困昆捆坤锟崑鲲琨髡堃醌悃阃菎騉髨髠硱堒壼壸瑻睏涃潉蜫䖵晜㫻鹍鵾䠅崐焜熴鶤裩裍裈褌祵錕鯤猑㩲梱稇稛閸閫綑",
"kuo": "括扩阔廓蛞鞟鞹萿葀䯺髺鬠霩濶䟯㗥韕挄擴拡頢筈䦢闊",
"la": "拉啦腊辣蜡落喇垃剌旯邋砬瘌藞鞡䪉菈䏀鬎磖䂰㕇䃳臈臘䟑䝓䶛㻋㻝瓎溂䗶蝋蝲蠟嚹翋㸊爉鯻鑞镴搚揦攋䱫揧辢楋櫴柆䓥",
"lai": "来赖莱癞睐籁徕涞崃疠唻赉濑铼䓶藾萊䧒騋㚓䂾琜睞瀨瀬淶䠭㠣崍庲襰䄤䲚鯠錸猍梾頼賴鵣棶郲來賚顂鶆逨䚅麳筙㥎籟徠箂䅘癩㾢婡俫倈䋱",
"lan": "兰蓝烂览篮栏拦懒滥揽澜婪岚缆阑榄斓褴啉谰镧漤罱藍韊䪍覧覽擥蘫蘭葻䰐䃹䑌壈璼㱫瓓灆濫灠灡浨㳕瀾嚂囒躝㘓幱嵐㞩懢懶惏㦨爁爦爤糷䊖顲燗爛燷燣襤襽襕襴䆾钄䳿鑭㩜攬㨫攔欖㰖欗醂欄籃籣䦨闌㜮孏嬾㛦孄儖㑣㑑繿纜䌫䍀譋斕讕",
"lang": "浪朗郎狼廊琅螂啷榔鎯莨阆蒗锒稂䕞蓈蓢硠朤朖㙟埌㱢瑯䁁䀶蜋㫰䍚䡙䯖崀㟍㢃烺䆡㝗䱶鋃樃桹躴艆筤㾿閬㾗嫏郞塱㮾勆郒欴㓪斏誏",
"lao": "老劳落牢络捞姥烙唠涝佬潦痨酪崂醪乐耢铹铑栳荖䵏䕩硓磱嗠䝤朥耮耂㐗䳓珯澇労浶蛯蟧㗦咾嘮哰轑㟙㟹嶗㟉㞠恅憦顟粩䃕勞憥䝁窂銠鮱鐒䲏狫㧯撈㨓橯䇭躼軂簩癆嫪僗髝䜎",
"le": "了乐勒肋仂嘞鳓泐叻艻阞砳㔹玏氻㖀忇㦡鰳鱳扐楽樂簕竻韷餎",
"lei": "类累雷泪勒蕾垒肋擂磊儡镭耒羸嘞檑酹嫘缧缧诔䒹蕌蘲虆藟蘽蔂蘱絫厽㹎䮑礌礧磥㲕䐯鼺䨓靁㙼䢮䣂頛㼍瓃矋㵢洡灅㶟涙淚㴃蠝䍥䍣塁罍礨㔣壘壨畾纍轠鸓䴎櫐㡞類頪纇颣禷鐳銇鑸鑘鱩錑攂㭩䣦欙櫑樏䉪䉂䉓癗㿔㒍㑍㒦儽傫纝縲䛶誄讄",
"leng": "冷愣楞棱塄薐䮚碐堎睖踜㘄唥䚏䉄稜倰䬋",
"li": "里理力利立例离历李礼丽粒隶哩璃励黎厉厘梨莉吏栗犁鲤狸砾沥荔篱漓笠蛎痢俐锂俚雳逦戾镉罹栎蠡俪藜鹂骊砺蜊黧娌莅猁疠傈唳溧疬慄醴砬喱鬲苈澧蓠坜嫠郦呖跞轹詈粝鲡鳢枥篥缡藶蒚蒞荲䔆䔁䔣䔧蔾菞䔉苙茘䓞蘺䧉犡䮥䮋驪勵厲礪㔏礰鬁㻎砅䃯礫歴暦厯磿歷厤曆㻺㽁貍䤚蠫䴄脷壢靂隷䟐赲䟏靋塛孷釐剺斄㹈瓑珕蟸叓䣓䰛酈鸝邐䚕婯麗䴡㱹㡂㽝瓅瑮琍瓈䶘㮚䁻睙濿瀝浬浰沴涖灕蠇䘈曞蠣蛠㬏蝷蚸蟍蜧㒿嚦㘑囇躒㗚唎嚟㕸囄轣䡃轢䍠䍦豊巁屴峛峢㟳峲㠟岦㤦㤡㦒悧悷䊪爄糲糎爏廲粴麜㷰裡褵䙰禲禮䄜䥶觻䲞鋰鱱鳨鱺鯉鱧鯏㺡鏫鑗鉝瓥㼖攊㿨攦㸚擽皪搮㧰攭櫔櫪栛朸隸䣫欐䤙醨栃檪櫟鷅梸㰀㯤欚棙樆㰚䅄穲䖽䵩悡鋫䱘㴝犂睝䖿鯬鵹䊍邌錅䴻棃剓筣䉫秝艃䵓䅻籬癘竰癧䍽㿛㾐㾖鴗凓䇐孋㓯娳刕儮儷䬅䬆㑦㒧劙䗍盠盭䰜纚䋥綟縭讈裏離謧",
"lia": "俩",
"lian": "联连脸练炼恋莲怜链廉帘敛镰鲢涟殓濂梿奁裢潋楝蔹臁琏琏蠊裣匲蓮薕萰蘞匳蘝聨聫聯䏈聮奩鬑䃛磏臉䨬覝堜鄻璉㱨殮瑓䁠㶌瀮漣湅濓溓瀲澰㶑螊蹥嗹噒連㦁㡘慩翴㦑憐䙺㥕燫煉劆㢘熑褳襝鏈鰱鰊鐮錬鍊㺦䥥鎌㼓摙櫣㪝槤㼑㰈㯬㟀簾䆂䇜籢籨亷㾾㝺羷㜕嫾嬚媡㜃㜻斂㪘歛㰸僆䭑縺練䌞纞謰戀",
"liang": "两量亮良粮梁俩凉辆谅粱踉晾靓莨墚魉椋䩫䓣駺㹁脼㔝兩両涼湸蜽唡啢䠃喨哴輌輛輬辌㒳䝶悢糧裲䭪鍄掚魎䣼樑倆倞俍緉諒",
"liao": "了料疗辽僚聊廖缭寥撩燎撂瞭缪嘹潦寮镣蓼獠尥鹩钌藔䒿镽䩍尞鷯遼䨅㶫膫㙩璙䝀敹漻㵳暸蟟曢蹽蹘䍡嶚嶛髎嵺賿憭憀屪鄝䢧䎆廫膋爎㡻䉼炓㝋窷竂釕鐐爒㺒橑䄦簝䑠療嫽尦飉豂䜮繚䜍",
"lie": "列烈裂猎劣咧冽趔鬣埒洌躐捩茢䓟聗㸹犣鬛㼲脟㲱埓劽䴕㤠烮鮤鴷迾姴䁽浖毟蛚㬯哷䟹䟩㽟煭鱲猟獵㧜挒挘擸栵㭞㯿䅀䉭巤颲儠䜲",
"lin": "林临邻磷淋鳞霖麟琳拎凛吝粼赁蔺躏嶙啉璘廪檩遴膦瞵辚辚懔臨䕲菻藺隣阾厸驎䮼䫰碄壣瀶潾澟暽䗲晽躪蹸躙㖁轥疄轔崊恡悋懍燐㷠䢯鄰粦㔂亃翷斴甐麐廩冧㝝䚬鱗鏻獜撛㨆橉䫐檁箖䉮焛閵癝凜癛僯賃繗綝㐭",
"ling": "领另令灵零龄岭铃玲凌陵棱菱伶苓聆翎绫羚鲮呤棂蛉囹瓴酃泠柃䔖蘦䖅蕶蔆蓤䕘䧙駖㸳砱朎霊霗㪮䰱龗霝䴒䚖孁靈㲆䨩夌坽䴇霛琌㱥㻏齡羐鹷齢澪淩㬡昤㖫跉䡼䡿輘軨䯍崚岺嶺㦭㥄爧燯炩㡵䴫麢䙥裬袊祾䄥錂鯪魿狑鈴掕皊櫺欞㯪醽䉁䍅䉹䈊䉖䠲舲彾秢笭衑竛閝㾉婈姈鸰刢領鴒䌢綾紷詅〇",
"liu": "流六留刘硫柳溜瘤碌榴馏琉浏绺蹓遛镠骝鎏鹨熘镏锍旒蓅藰蒥䋷䭷驑駵駠騮磟磂䶉㙀塯霤㽌璢畱鬸珋瑠䰘澑畄瀏瑬蟉䗜㽞嚠疁罶嵧羀懰鷚翏雡熮㶯廇麍裗䄂䚧鐂鏐䱞䱖鰡鎦鋶鹠劉鶹㨨橊桺栁桞橮䉧癅嬼媹飗飂䬟飀飅餾綹㐬斿旈",
"long": "龙隆笼垄拢胧聋咙陇窿珑垅弄砻茏栊滝眬泷癃䪊蘢䃧隴䏊龓尨礲朧霳䥢鏧壠靇瓏矓漋㙙㴳湰瀧昽曨蠬哢躘嚨嶐㟖巃巄贚㦕㢅爖㝫襱竉鑨攏梇䙪櫳槞㚅䡁徿籠䆍篭聾礱龍壟龒蠪驡鸗㰍竜㛞㑝儱豅㡣",
"lou": "露楼漏陋搂喽篓娄镂偻髅蝼瘘耧蒌嵝鞻㔷蔞䮫㲎塿耬䝏剅瞜䁖漊溇螻嘍䣚䫫婁甊遱鷜㪹髏㟺嶁屚慺㥪廔熡䄛鏤䱾㺏摟樓簍䅹軁艛瘻瘺謱",
"lu": "路陆绿露录鲁炉卢芦鹿碌禄卤虏庐噜麓颅漉辘掳六赂鹭戮泸橹璐潞鲈撸蓼箓轳胪垆氇鸬渌辂镥栌簏舻逯虂䩮蘆蓾蕗蔍菉陸䎼騼䮉騄馿䰕磠硵䃙硉臚膔氌䐂壚塷趢塶圥勎坴鵱瓐㱺璷琭矑虜㪭盧顱鸕鹵睩淕瀘滷澛瀂淥曥蠦螰㫽踛嚧蹗鷺䟿嚕㖨黸䡜轤轆輅䡎髗㠠賂峍㟤㦇䎑勠剹㢚廬爐廘熝粶䴪㼾䘵祿錴鐪鑪鏀㔪鏴鯥䲐鱸魯鴼鵦䱚鏕魲鑥獹録錄鈩擄攎摝擼醁㯭櫨樐㯝樚櫓㯟㭔椂枦甪罏稑籚簬簵穋簶穞籙艣艫艪舮㓐㿖㛬㪖䚄盝㜙娽僇侓纑彔䌒㢳㪐謢玈",
"luan": "乱卵挛峦滦鸾孪栾銮脔娈䖂虊亂灤羉圞圝釠癴癵鵉孿㝈奱㡩灓曫巒鸞鑾攣欒孌臠㱍龻䜌",
"lun": "论轮伦仑沦纶抡囵崙菕芲陯磮碖腀耣埨淪溣蜦踚㖮圇輪崘惀㷍鯩錀㤻掄棆䑳稐䈁婨侖倫綸論",
"luo": "落罗逻洛络螺裸萝锣骆烙骡啰珞箩摞捋倮瘰猡硌荦脶漯泺镙椤雒蠃蘿蓏騾駱䯁硦覶頱腡㼈㱻覼䀩㴖濼曪囉囖邏羅峈㦬犖鏍鑼鮥玀㩡攞㰁欏洜㓢鵅籮躶䈷笿癳㿚㑩儸饠㒩纙絡䌱䌴驘臝䊨鸁䇔詻剆㽋咯",
"lv": "律率绿虑旅氯铝履吕捋驴滤侣屡缕榈褛偻闾稆膂藘葎䕡驢膢膟垏勴慮濾郘呂氀㠥嵂屢爈焒褸祣鑢鋁㲶捛挔櫖梠櫚穭箻閭儢侶僂絽縷緑綠繂膐",
"lve": "略掠锊寽㔀畧㨼圙鋢鋝稤",
"ma": "马吗妈麻嘛骂码抹玛蚂蟆犸嫲么杩蟇蔴䣕馬䣖遤碼鬕瑪睰溤螞䗫嗎駡嘜罵䯦犘㦄䳸祃禡鎷鰢鷌獁㨸榪㾺痲痳閁媽㜫㐷傌㑻摩",
"mai": "买卖麦脉埋迈霾荬劢唛薶勱邁蕒䮮脈霢霡䨪賣売䨫䁲嘪䚑鷶買麥衇䘑䈿㜥佅䜕",
"man": "满慢漫曼蛮瞒蔓馒螨幔缦鳗谩颟墁埋鞔熳镘䕕顢㒼蔄蘰鬗䯶鬘䰋䐽䝡䝢㙢䟂瞞満滿㵘澷蟎鄤㬅㗈㗄䡬㡢慲屘悗䊡襔鏋鏝鰻獌摱樠槾䅼䑱姏娨嫚㛧僈饅䜱縵謾䛲矕蠻",
"mang": "忙盲茫芒氓莽蟒铓牤邙硭漭䒎莾蘉茻牻駹厖硥壾㙁㻊䁳䀮盳浝汒蠎㬒蛖哤䟥䵨㟿㟐㟌㡛恾庬㝑鋩狵釯杧䅒笀䈍痝娏䖟杗吂",
"mao": "毛矛貌冒贸帽猫茂茅髦瑁锚牦铆卯懋袤昴峁眊茆瞀蟊蝥耄泖旄蓩鶜䓮芼鄚萺堥暓䖥愗髳冇貓䫉覒氂犛㲠㺺渵㴘冐毷㪞㒻㫯蝐罞軞䡚冃㡌戼㝟錨夘鉾䀤鉚乮鄮貿㧌㿞㧇皃㒵楙柕㮘枆酕䅦笷媢㚹䋃",
"me": "么濹嚰嚒",
"mei": "没美每妹梅煤眉霉媒枚酶镁媚魅玫昧莓糜楣寐湄嵋袂浼鹛镅猸䒽葿䓺苺脄腜脢堳坆㺳䜸瑂珻眛睸䀛湈沬沒渼䰪蝞跊嚜槑䵢黣䍙嵄郿鶥韎㶬䊊煝塺䊈燘禖祙鎇鋂鎂抺攗鬽挴楳㭑䤂栂䆀䰨躾黴徾篃毎䉋羙凂痗媺嬍媄睂旀",
"men": "们门闷瞒懑扪汶焖钔虋菛璊玧㱪懣㵍暪㡈䝧㥃㦖䊟穈燜䫒鍆㨺捫椚門悶閅們",
"meng": "梦蒙猛盟孟萌朦氓锰懵蟒勐檬濛蜢虻蠓矇瞢甍礞艨艋䓝鄸䒐䠢顭夢莔氋鹲鸏蕄䰒㚞䑅䑃䏵㙹靀霿霥矒溕曚䗈甿㠓幪懜懞冡鼆䀄䙩㝱䙦錳䴌䲛鯭鯍䥂獴䥰㩚掹擝橗䤓䴿䵆䉚㒱癦䇇㜴儚饛鄳夣蝱",
"mi": "密米秘迷蜜弥泌眯咪觅谜靡糜猕谧醚嘧弭脒幂麋縻汨蘼蘼芈敉宓冖祢糸蔝㰽蒾䕷蘪藌蔤葞䕳䮭镾覔㫘䪾覓㸓塓鸍羋瞇䖑濗漞濔㵋㳴㴵灖洣滵淧沵沕䌘渳瀰㳽羃䍘峚幎㠧㟜怽幦戂㥝㐘粎䊳麊熐麿爢㸏麛䴢冪宻鼏䁇冞㝥袮禰祕䱊銤獼㩢覛擟攠㨠䤍䤉釄醿醾䣾榓櫁樒簚䉾㜆孊侎䭩䭧䌩䌐㣆䥸彌㜷瓕䌕䋛䌏䛉謐䛑䛧謎詸",
"mian": "面免棉眠绵勉缅腼冕娩沔湎眄渑宀芇葂䏃䰓勔靦靣䃇㻰㤁丏麺䀎睌矈矏矊汅㴐澠蝒㬆喕愐糆㝰鮸緜㮌䤄杣㰃櫋麵麪麫檰䫵臱媔㛯婂嬵偭㒙緬絻綿",
"miao": "描苗妙秒庙渺瞄缪淼藐缈邈鹋眇喵杪鶓㦝䁧䖢㠺庿廟劰篎䅺竗媌嫹㑤緢緲玅",
"mie": "灭蔑篾咩乜蠛薎孭礣烕䩏䁾瀎滅䘊哶吀幭懱鴓鑖鱴搣櫗衊䈼㒝",
"min": "民敏闽皿悯抿泯岷闵苠珉玟黾愍鳘缗蠠䃉䂥碈砇垊琝瑉琘䁕盿湣潣旻旼䟨䡅罠䡑䡻㟭崏㞶䪸敯刡㥸鴖暋㟩敃惽怋憫忟鍲鈱䲄錉㨉捪笽笢簢勄慜鰵閩冺痻閔姄僶緡㢯䋋黽緍忞",
"ming": "明命名鸣铭冥螟茗瞑酩溟暝蓂眀眳洺㫥鳴朙㟰慏䊅鄍䒌䫤覭㝠䆩䆨䄙銘猽掵榠凕嫇姳佲詺",
"miu": "谬缪謬",
"mo": "么没模末默莫摸脉磨冒膜摩墨漠魔抹沫陌寞摹蓦蟆蘑馍谟茉貉秣殁貘万貊耱麽镆瘼嫫嬷嬷靺䒬莈驀㱳謩藦䮬砞䩋礳䃺䏞貃䳮塻圽歿歾瞙眜瞐䁼眽眿尛蛨黙昩䘃蟔嗼嚤䁿㱄髍帞帓懡糢㷬爅㷵䯢劘麼䜆庅鏌銆魹䱅魩獏㹮皌擵枺橅䴲䉑妺嫼嬤饃䬴饝纆絈謨嘿",
"mou": "某谋牟眸缪呣哞鍪蛑侔䥐劺鴾䏬䗋踎䍒恈䱕㭌麰繆謀",
"mu": "目母木模莫幕牧亩墓姆慕穆暮姥牡拇睦募沐牟缪苜钼毪坶仫莯䧔鞪䱯楘㜈牳砪氁胟雮霂畞䀲暯蚞踇畂畮峔幙慔毣炑䥈鉬狇鉧㣎㧅䑵艒㾇凩㒇縸䊾畆畝畒",
"na": "那哪拿纳娜呐捺衲钠内南肭镎靹蒳䖓乸䫱貀豽䏧雫䀑㴸䖧䟜吶㗙嗱軜䎎䪏袦鈉魶䱹鎿㨥䅞笝䇱郍䇣䈫拏妠搻納䛔",
"nai": "奶耐乃奈萘氖迺艿能鼐柰孻螚䘅䯮腉渿褦釢錼㮈㲡廼㮏疓㾍䍲嬭倷",
"nan": "难南男喃楠囡赧囝腩蝻䕼䔜萳戁難莮䔳遖䁪湳暔㫱㽖畘䶲煵揇抩枏柟䈒㓓婻娚侽諵䛁",
"nang": "囊囔曩馕攮䂇嚢灢㶞蠰乪擃欜齉儾㒄饢",
"nao": "脑闹恼挠瑙呶孬桡淖铙硇垴蛲猱夒䃩碙碯臑脳腦䑋䴃堖鬧蟯巎嶩悩憹怓惱鐃獶獿峱㺀㺁撓䄩閙嫐㞪㛴䫸㑎匘譊䛝詉䜀䜧",
"ne": "呢呐讷哪疒䭆䎪眲㕯抐訥",
"nei": "那内哪馁脮腇㼏㘨㖏䡾內䳖鮾䲎鯘錗㨅氞氝娞㐻餒",
"nen": "嫩恁㶧㯎㜛嫰",
"neng": "能䏻㲌㴰",
"ni": "你疑尼泥拟逆妮腻倪匿溺霓昵睨怩鲵铌旎呢坭猊伲䘌臡苨䕥薿孴聣隬䧇膩貎胒䝚郳㪒堄䁥齯惄眤㵫淣聻埿氼暱晲蜺蚭跜輗㞾㠜㥾㦐愵籾麑䘽䘦觬鈮鯢狔㹸掜屔抳䰯擬棿檷柅䭲馜秜䵒䵑屰䦵嫟嬺婗妳儞㲻伱儗㣇縌誽䛏",
"nian": "年念粘碾撵捻辗蔫拈埝黏鲶鲇辇廿䩞卄輦涊㲽淰躎蹍蹨哖唸㘝㞋惗焾鮎鯰攆撚䚓鵇秥簐䄭秊艌䄹姩䬯",
"niang": "娘酿䖆醸釀嬢孃",
"niao": "鸟尿溺袅脲茑嬲蔦䮍䦊䃵䐁㳮㠡㞙鳥䙚裊㭤樢嬝嫋㜵㒟褭",
"nie": "捏聂涅孽镍蹑蘖镊颞啮嗫摄乜陧臬糵㜸苶菍聶顳隉孼蠥糱櫱䯅䯀䯵齧㚔䂼㘿㙞摰槷湼㴪圼囁囓躡踙嚙踂噛踗㡪嵲嶭巕㸎䄒鑷鑈钀鎳錜揑㩶枿㮆籋臲篞㖖痆闑帇敜䌜䜓讘捻",
"nin": "您恁脌囜㤛拰䋻䚾䛘",
"ning": "宁凝拧狞咛柠泞佞聍甯䔭薴聹鬡㿦矃澝濘䗿嚀寕㝕㲰寍寜鸋寧寗鑏獰擰橣檸㣷嬣儜倿䭢侫",
"niu": "牛扭纽钮拗妞忸狃靵莥䒜牜䏔㺲䀔汼炄鈕杻䋴紐",
"nong": "农弄浓脓哝侬蕽鬞膿䢉䁸濃噥農燶㶶襛禯㺜挵挊醲檂欁辳齈穠秾䵜癑儂繷譨",
"nu": "努奴怒弩帑孥驽胬搙䢞笯駑砮㐐傉伮㚢",
"nuan": "暖䎡渜㬉煗煖䙇奻餪",
"nuo": "诺娜挪糯懦喏傩搦难锘逽㔮蹃㡅愞懧糥糑鍩䚥掿㰙梛榒橠稬穤㐡㛂儺㑚諾",
"nv": "女衄恧钕朒沑籹釹衂",
"nve": "虐疟硸䖋䖈瘧婩",
"o": "哦噢喔筽",
"ou": "偶呕鸥殴耦藕讴禺沤怄瓯区欧蕅毆鷗歐甌䚆鴎藲膒腢塸漚㼴嘔吘䯚慪熰鏂䳼櫙㛏㒖䌔䌂謳",
"pa": "怕爬帕扒啪趴琶耙杷葩钯筢䔤苩䯲䶕潖帊袙皅掱舥妑",
"pai": "派排迫拍牌湃徘俳哌蒎犤沠渒㵺䖰輫鎃猅棑㭛簲箄簰",
"pan": "判盘胖潘盼叛攀畔拌蹒泮蟠磐槃爿袢柈番襻丬萠蒰聁䰉䰔磻䃑䃲坢眅㳪溿沜瀊洀蹣跘炍鑻鋬牉䈲鞶幋縏盤鎜搫媻頖鵥冸詊拚",
"pang": "旁胖庞乓磅螃彷滂徬耪逄䮾厐龎肨膖胮霶㫄雱䨦眫㤶㥬炐龐鳑鰟舽䅭㜊嫎䒍覫",
"pao": "跑炮泡抛袍刨咆疱狍庖匏脬鞄䩝萢皰礟礮靤砲奅褜垉㘐軳麅麃炰拋爮㯡麭䶌㚿䛌",
"pei": "配培陪佩胚赔沛妃裴呸帔辔霈锫醅旆蓜阫馷䪹䲹䫠肧毰珮㳈浿㫲䣙賠㟝怌㤄䊃犻錇㧩衃姵俖伂轡裵斾",
"pen": "盆喷湓葐翸歕喯噴呠瓫",
"peng": "朋碰棚蓬膨捧篷鹏烹砰澎抨怦硼嘭彭堋蟛莑芃蘕駍騯鬅髼鬔䰃磞硑鵬蟚塜塳㼞淎泙踫輣軯䡫剻㥊憉恲熢袶䄘鑝錋匉捀皏掽樥槰椪䴶梈椖稝竼篣閛韸韼㛔倗傰纄弸苹亨",
"pi": "皮批屁披辟疲脾匹劈僻副罢譬啤琵坯癖毗痞枇霹噼裨媲否貔丕吡陂砒邳铍圮睥蜱疋鼙陴埤淠蚍罴甓庀擗郫仳纰苉鴄㓟隦阰駓髬㔻礔磇䏘豾脴腗䑀䑄膍肶豼噽嚭壀耚疈錃潎澼蚾蚽䠘㔥羆䡟毘岯嶏崥翍礕䴙憵鷿鸊悂炋焷螷蠯鈹銔鉟銢鲏鮍魾魮䤨釽錍狓狉鈚抷㨽揊䰦䫌䤏㯅秛秠稫篺笓鵧㿙闢嫓伾伓枈紕諀旇䚰䚹",
"pian": "片偏篇骗扁翩骈胼蹁便犏谝貵䮁騈駢騙腁䏒跰囨骿賆魸鍂楩楄覑㸤㾫㛹媥㓲騗鶣㼐諞",
"piao": "票飘漂瓢瞟缥剽嫖朴嘌骠慓殍螵薸䕯䏇驃犥㵱㬓䴩鰾㺓㹾皫㩠魒勡彯飄顠翲㼼醥徱篻闝僄飃縹旚",
"pie": "撇瞥苤氕丿暼鐅撆嫳覕䥕",
"pin": "品贫频拼聘拚嫔颦姘牝玭榀蘋薲驞礗砏琕顰䀻矉蠙嚬汖㰋馪穦嬪娦貧",
"ping": "平评凭瓶屏苹萍乒坪呯鲆枰娉俜蓱荓聠砯胓䶄塀玶㻂淜涄洴蚲蛢輧軿甹岼幈帲帡屛焩鮃檘缾䍈甁簈箳郱頩艵慿憑凴竮㺸評冯",
"po": "破迫婆坡颇泼朴泊魄粕珀鄱钋笸陂叵钷皤蔢尀蒪頗駊奤砶䞟䨰㨇洦湐溌潑昢哱嘙嚩岥䯙岶䪖烞鉕釙鏺廹敀櫇䣮䣪酦醱醗箥䎊䄸㰴㛘㔇繁",
"pou": "剖掊裒犃垺哣㧵抔捊抙箁咅娝婄",
"pu": "普铺扑谱朴葡仆浦蒲埔菩瀑圃噗曝匍蹼溥濮璞莆氆攴镤镨堡攵䔕䑑蒱䧤陠㹒暴圤墣㺪瞨潽㬥䗱圑贌烳炇㲫䴆菐鯆鏷䲕鋪獛鐠擈撲酺檏樸㯷䈻䈬穙痡暜舖舗㒒僕纀諩譜",
"qi": "起其气期器企七奇汽齐妻启旗弃骑欺漆棋岂凄契歧戚栖泣砌祈蹊乞迄崎祺鳍伎缉岐琦祁琪憩畦沏绮脐亟嘁荠杞麒颀耆啐蛴碛淇葺芪祇綦欹槭萋讫圻蕲揭萁芑骐亓丌柒汔蜞屺桤藄䩓䓅鄿䕤蘄䔇䒻炁芞藒䒗萕陭隑䏅䧘亝騹騎騏䭼䭶唘碶磩碕鬐䰇磧慼䫔䚉栔㓞㼤矵攲敧鵸碁䫏磜剘蜝㐞䳢棊肵䏠臍墄埼霋䞚䟄䎢璂䚍玘郪鶈䀙䶞盀盵濝淒呇滊湇湆蚑螧蚔蚚暣㫓蠐咠唭踦跂䟚噐呮罊蟿䡋軝䡔䢀㟢豈帺㟓岓嵜㠎邔慽㥓愭悽愒迉忯㞚㞓懠粸䉻麡䧵褀褄䙄禥䄎䄢鏚錡锜釮鲯鯕鶀䱈鰭䲬䰴夡玂猉鐑頎掑捿氣鬿魌気摖㩩櫀㯦㟚棲㩽榿檱㮑䣛桼憇諬䅲欫甈㣬䄫簯䅤䑴䉝艩簱籏㾨竒疧闙䀈婍娸傶僛倛䏌䬣㒅綺緀紪䭫䭬綥䌌斊棄䛴諆斉齊䶒䐡䁉䋯啔啟䏿䁈晵啓棨訖旂枝俟稽",
"qia": "恰洽掐卡髂拤袷咭葜鞐圶硈胢䨐殎䶝䶗䠍跒䯊峠㡊帢㤉擖酠冾㓣䜑",
"qian": "前千钱潜迁浅签纤牵欠遣铅歉谦乾倩嵌虔钳黔谴堑扦阡茜钎掮犍钤佥荨骞愆箝芡芊肷椠岍悭慊褰搴仟缱䪈韆䕭茾孯臤蜸掔婜蔳葥蕁蒨騚騝㸫鬜鬝厱膁㦮墘䥅亁乹圲䨿䁮䖍歬淺灊潛汧壍嬱汘濳蚈黚輤塹㟻槧㜞軡㡨岒慳悓忴粁䊴䞿騫錢鹐鵮銭鉗鑓鰬釺鎆鈆鉛鈐鏲㧄攑㩮拑皘㨜攐攓㩃拪揵扲撁橬檶遷棈榩櫏杄槏㯠圱刋谸籖䍉篏䈤䈴篟簽籤羬䇂䦲竏㪠䫡奷媊僉俔儙諐伣㐸偂傔䭤仱欦綪繾縴譴顅謙牽",
"qiang": "强枪墙抢腔羌呛跄锵蔷羟襁戕戗嫱樯蜣炝锖镪薔蘠蔃墻玱瑲溬漒蹡蹌啌嗴唴嗆嶈廧熗獇猐鏘鎗鏹摤㩖搶檣椌䵁槍艢䅚篬牆羥羗羻羫墏斨牄嬙㛨戧強彊繈繦謒疆",
"qiao": "巧桥悄瞧敲乔侨翘峭窍俏锹鞘憔跷撬樵荞橇壳雀诮峤鞒硗愀劁缲谯鞩鞽㤍䲾㚽菬荍藮蕎陗犞磽䃝䩌硚礄䂭翹墝㚁趬趫墽墧睄郻㴥踍蹺躈蹻嘺骹帩幧韒燆㢗㝯䆻竅釥鐰鄥䱁鄡鐈鍬撽櫵槗橋勪喬䀉䎗㡑鍫䇌頝癄嫶僺僑顦繰繑誚髜毃㪣髚譙",
"qie": "切且窃契怯砌伽茄妾惬趄锲箧挈郄苆㥦匧㰼聺㚗洯蛪㓶厒㤲㰰朅淁㫸䟙踥㗫愜悏竊鍥䤿鯜㹤癿篋笡籡穕㾜䦧㾀㛍㛙䬊",
"qin": "亲侵勤秦琴禽钦沁芹寝擒矜噙覃揿芩嗪衾螓吣锓檎菣靲䔷懃斳兓菳菦藽耹骎㮗駸肣㘦赾埐坅琹珡䖌澿瀙螼蠄昑蚙唚㞬嶜嵚嶔嵰懄慬吢㤈㢙庈㝲寴寢寑顉鈙鮼鵭欽鋟鈫抋捦撳㩒搇梫䠴笉䈜瘽䦦親㓎㾛嫀媇㪁鳹雂綅誛",
"qing": "情清亲青轻请倾庆氢晴顷卿蜻擎氰磬罄圊箐苘檠謦黥鲭綮葝䔛碃䌠硘埥殸漀㷫郬靘靑殑濪淸暒甠啨軽輕鑋䝼䞍慶檾庼廎寈錆鯖䲔夝擏掅氫㯳櫦棾樈凊儬傾頃請勍剠䋜䯧",
"qiong": "穷琼穹邛茕跫蛩銎筇卭㧭䓖藭藑蛬䊄䅃赹璚瓗㼇瓊瞏睘惸㷀煢焭熍焪䆳竆窮宆憌桏㮪橩笻䠻舼儝㒌䛪",
"qiu": "求球秋丘酋囚蚯邱裘鳅巯泅湫虬遒楸逑龟蝤赇糗犰鼽俅蓲鞦鞧莍萩蘒芁䎿毬肍䞭趥坵皳䣇盚㺫蟗玌璆殏巰㐀汓浗湭渞蛷虯䟵䟬䠗唒㕤賕㟈崷㞗㤹㥢恘秌煪觩觓銶䲡䤛䱸鰽鯄鮂鰍鰌釚釻㼒㧨搝扏梂逎㭝朹湬蝵鹙鶖醔媝穐篍龝蠤㷕丠頄㐤叴訄恷䜪紌絿緧䊵訅仇",
"qu": "去区取曲趣趋屈驱渠躯娶岖瞿祛蛐觑衢蛆龋黢癯苣蠼佉阒麯蘧蕖磲朐璩氍劬鸲麴诎葋䒧匤菃敺區䒼螶䧢阹驅駆駈厺髷胠刞臞䝣鼩㰦鼁坥䟊䞤趍趨耝璖麹䶚齲覰覻䁦䀠䂂戵鸜覷灈浀淭䖦㫢蠷蟝蝺呿䠐躣㖆軥㻃嶇㲘岴胊鶌憈翑焌爠粬煀袪鑺鴝斪䵶鰸魼鱋抾㭕㯫欔欋麮衐籧忂筁軀闃閴竘竬㜹佢伹紶㣄䋧絇詘詓誳㧁",
"quan": "全权圈泉劝拳券犬醛蜷痊颧铨荃诠筌鬈畎辁悛犭绻勸顴葲虇䄐騡駩犈牷犮硂䑏䟒埢瑔䀬湶洤蠸䠰踡跧啳圏輇巏㟨㟫峑恮䊎烇鳈鐉鰁銓搼權楾権棬椦勧箞㒰齤奍韏觠牶闎婘姾佺縓綣絟詮",
"que": "确却缺雀鹊炔瘸榷阙阕悫皵鵲䧿蒛碏礭確硞碻礐趞㱿㲉愨慤埆㱋塙琷㴶崅燩㕁搉㩁棤㰌缼䇎䦬㾡闕闋傕卻",
"qun": "群裙逡麇䭽夋囷峮宭㿏㪊裠帬羣",
"ran": "然染燃冉髯苒蚺䖄㲯蒅㸐䒣㿵髥肰䫇珃蚦呥嘫冄䎃衻袡袇䤡橪㯗䑙㾆媣姌㚩㜣䣸繎",
"rang": "让壤嚷攘瓤禳穰蘘鬤㚂壌瀼躟懹爙獽穣䉴儴勷譲讓",
"rao": "绕扰饶桡娆荛蕘隢㹛遶襓擾橈䫞嬈㑱饒繞",
"re": "热惹喏若熱",
"ren": "人认任忍仁韧刃妊纫壬饪仞衽荏稔轫亻靭靱荵芢㸾牣䏕䏰肕腍忈䀼軔㠴岃屻韌㣼䴦袵祍魜鈓銋扨梕杒栣朲棯忎躵秹䇮秂姙刄䋕鵀㶵栠飪餁䭃仭䌾紝纴綛紉絍認訒讱",
"reng": "仍扔芿陾辸礽㭁䄧㺱䚮",
"ri": "日䒤驲馹囸衵鈤釰釼",
"rong": "容溶荣融绒熔蓉茸戎榕冗嵘镕蝾肜狨茙㲨䩸氄駥毧㲓㲝坈瑢瀜栄螎曧蠑䠜㘇䡥䡆軵嶸峵烿爃嵤榮㣑䘬褣䇀宂㝐䢇㼸鎔㺎搑搈榵㭜䤊槦穁䇯穃䈶羢媶嬫嫆傇傛縙絨",
"rou": "肉柔揉蹂鞣糅葇鶔騥䰆腬脜䐓瑈瓇渘蝚㖻輮㽥禸韖煣粈宍鍒鰇楺䄾䧷媃厹譳",
"ru": "如入乳儒辱汝蠕茹褥濡嚅孺铷缛襦女蓐薷颥溽洳蕠蒘㹘㦺鄏肗䰰顬渪蝡曘嗕嶿袽鱬銣㨎擩扖醹杁筎㐈鳰邚鴑䋈媷嬬帤鴽挐桇侞縟繻",
"ruan": "软阮朊䓴碝礝耎腝堧壖瑌瓀輭㽭軟䞂撋䪭㼱媆偄㐾緛",
"rui": "瑞锐蕊兑睿芮蕤蚋枘蕋蘃蘂䓲㓹甤叡㪫㲊壡汭蜹繠橤鋭銳桵㮃䅑㛱緌䌼",
"run": "润闰膶瞤潤㠈橍閏閠䦞",
"ruo": "若弱偌箬鄀爇蒻叒䐞渃㘃嵶焫鰙鰯挼捼楉篛婼鶸",
"sa": "萨撒洒仨卅飒脎蕯薩靸躠隡馺䘮㪪灑㳐䊛䙣鈒钑摋櫒颯㽂㒎䬃訯",
"sai": "塞赛腮鳃噻毸毢嗮㗷嘥顋愢賽䚡鰓揌䈢簺僿思",
"san": "三参散伞叁糁毵馓弎㪚毿犙䫩鬖毶壭䀐潵㤾糤糣糝䊉䫅鏾鏒㧲㪔䉈閐厁俕饊傘繖",
"sang": "丧桑嗓搡颡磉顙䫙桒喪䡦褬鎟槡",
"sao": "扫嫂骚缫搔臊瘙埽鳋䕅騒騷䐹矂溞螦氉鰠鱢掻掃㿋㛐㛮颾繅髞梢",
"se": "色涩瑟啬塞铯穑槭䔼雭䨛嗇㱇璱㻭歮濇濏澁渋㴔洓瀒澀轖懎㥶銫鏼摵擌㮦栜穯穡䉢閪瘷歰飋㒊繬譅",
"sen": "森襂槮椮",
"seng": "僧鬙",
"sha": "沙杀啥纱砂傻刹厦杉莎煞鲨霎裟挲嗄唦痧唼铩歃萐蔱䮜髿䝊硰㲚㸺乷鯊桬啑喢帹翜翣廈粆魦鯋鎩猀毮閷殺榝樧㰱箑䶎䈉䵘閯㚫㛼儍倽紗繺",
"shai": "晒筛曬㬠㩄簛籭簁篩",
"shan": "山单善闪扇衫陕珊禅杉擅掺栅煽膳删姗汕赡跚掸讪缮舢疝嬗潸鳝搧鄯苫膻芟骟彡蟮钐陝剼騸㚒磰㪎脠赸墠圸墡㣌睒灗澘㶒晱蟺嘇軕刪邖幓贍炶煔覢熌䘰禪䄠釤銏䱉䱇鱓鯅鱔狦鐥䦅䥇䦂掞挻㨛樿柵檆椫䴮㣣笘䠾䆄痁閊㪨敾歚羴閃羶譱姍僐饍傓縿繕䚲訕謆",
"shang": "上商伤尚赏汤裳晌熵墒垧殇觞绱鞝蔏鬺殤丄尙賞漡滳螪贘慯恦禓觴鋿鏛鑜樉䬕傷緔扄謪",
"shao": "少烧绍召稍梢哨勺捎邵鞘芍韶筲艄苕劭潲杓莦萷䒚䔠蕱髾㪢䏴㲈玿輎㷹焼燒䘯袑鮹柖䈰䈾㸛娋卲綤䙼䬰弰紹旓",
"she": "社设射涉舍摄舌蛇折拾畲奢赦慑麝赊佘猞歙阇厍滠揲蔎騇厙奓䂠䁋䁯灄渉㴇㵃涻蠂虵蛥䵥畭輋䞌賒賖懾韘慴䀅䄕䤮攝摂捨欇㰒㭙檨䠶㒤舎畬䬷弽䌰㢵設",
"shen": "什身神深参甚审伸申沈渗婶肾慎绅呻娠砷蜃莘吲糁鯵诜谌瘆信葚胂渖哂矧谂蔘腎頣蓡薓葠駪㰮眘昚脤㥲堔珅眒瞫滲㵕㵊瀋涁蜄曑曋罧屾峷愼糂籸燊籶邥㔤審覾宷裑䆦穼罙祳鋠鲹鉮鰺鰰魫鯓氠扟䰠柛㰂榊兟甧甡鵢瘮㾕妽嬸㜤姺敒侺侁㑗紳弞矤訷谉讅詵諗訠",
"sheng": "生声省胜升盛圣剩乘牲绳笙甥嵊晟眚蕂苼䎴聖陞阩陹鼪勝賸榺墭聲殅珄渻湦泩䚇㼳晠琞曻昇㗂呏貹䞉憴焺鍟䱆鵿鉎狌斘橳枡剰䪿㾪竔偗䁞繉縄繩譝甸",
"shi": "是时实事十使什式世识食市史石始师失视示似适士势试施室释诗氏湿饰驶拾蚀尸逝侍誓矢狮匙柿硕嗜屎噬嘘栅拭峙仕恃虱轼舐耆螫豕谥弑奭殖蓍泽莳贳埘炻鲥鲺铈酾筮蒔貰䒨蒒葹䦹旹㱁乨駛䰄觢㸷䩃乭䂖䏡鼫鼭卋㔺邿塒㐊辻兘勢丗䴓鳾瑡亊䶡眎睗䁺眂眡溼溡浉湜濕㵓澨溮湤䖨㫑㫭時昰遈㒾呩㕜䟗㖷呞軾嵵崼峕忕蝨屍鸤䲩鳲恀烒煶䊓実寔宩冟襫襹褷䙾實祏視鉽釶鉐鉂䤱鮖鰣鯴鰘鰤鶳鉇鉃㹬㹝獅鈰鍦㹷銴弒揓栻枾釃榯榁柹㮶簭遾舓秲徥師釋釈笶籂箷竍䦠嬕姼餝䭄蝕餙飾飠䌳絁試詩諟戺䗐䛈適謚諡識",
"shou": "手受收首守授售寿瘦兽狩绶扌艏膄壽夀垨涭獣㖟獸㥅収㝊鏉龵痩䭭綬䛵",
"shu": "术数书属树述熟输束殊叔朱舒鼠疏署竖蔬抒枢淑暑薯梳俞蜀庶赎塾墅恕曙倏漱黍腧戍孰澍秫菽纾疋沭摅姝殳毹荗䩳䩱㷂竪豎䜿䝂薥䔫蒁藷陎㽰毺䑕䞖霔尌朮怷璹琡䜹㻿尗虪濖瀭潄潻㳆鼡㶖蠴暏䠱踈䟽咰數軗輸㟬贖䝪䎉疎屬庻糬襩裋襡䘤䆝鏣鮛鱪鱰錰鉥掓攄捒樞樹橾㯮杸䴰鶐䉀䢤術癙㾁書㛸婌㜐㣽鵨鄃侸跾倐儵焂㒔紓綀絉䃞",
"shua": "刷耍唰㕞誜",
"shuai": "率衰摔帅甩蟀帥䢦卛",
"shuan": "拴栓涮闩䧠腨閂",
"shuang": "双霜爽孀骦騻驦礵䫪鷞㼽㦼塽鹴鸘漺灀䗮䡯慡鏯欆艭㕠孇雙縔",
"shui": "谁水睡税说氵脽氺涚涗帨裞祱稅閖㽷䭨誰",
"shun": "顺瞬舜吮蕣䑞鬊䀵瞚䀢順㥧橓楯",
"shuo": "说烁硕朔数妁蒴铄搠槊矟碩䀥爍鑠獡鎙欶箾䌃説說",
"si": "思四死斯似司丝私饲寺撕祀肆嘶嗣厮俟泗咝巳鸶蛳驷锶汜伺食厶耜兕澌笥姒缌纟蕼䔮蕬㹑㸻牭騃駟騦磃蟴䏤鼶貄亖耛䎣㺨肂洍涘洠瀃泀泤㴲蟖螄㕽噝罳㟃孠覗廝燍䇁禗禩禠鈶鐁鋖鍶鈻鉰釲㺇銯虒枱杫梩柶楒㭒榹蜤㐌恖竢凘䦙䇃媤㚶㚸娰儩佀飔価俬颸飼飤緦糹㣈鷥絲",
"song": "送松宋颂讼耸诵淞嵩悚凇怂忪菘崧竦駷鬆硹濍㕬嵷憽㞞愯䢠庺梥鎹㧐㩳㨦檧楤㮸枩柗㣝䉥聳慫娀頌枀倯傱餸䜬誦訟䛦",
"sou": "搜艘嗽嗖擞飕馊薮螋叟溲瞍嗾锼蓃藪蒐䏂騪䮟鄋㵻㖩廋廀叜鎪獀捜擻摉摗醙櫢籔䉤䈹凁瘶傁颼䬒餿",
"su": "素速苏诉缩俗塑肃宿稣溯粟酥簌窣夙谡嗉僳愫蔌涑觫蘇莤藗䔎蘓㕖骕驌碿䃤膆塐趚甦殐璛珟玊溸㴑㴼泝潥潚㴋洬㬘囌蹜憟䘻㝛鯂穌鱐鋉䥔㨞㩋榡遬㔄樎櫯梀㯈樕䅇橚䑿愬遡㪩肅䎘鷫嫊鹔䏋粛㜚㓘傃㑛餗㑉縤䌚䛾謖訴",
"suan": "算酸蒜狻匴㔯祘筭笇痠",
"sui": "随虽岁碎遂髓穗隋绥隧邃祟燧睢荽濉谇䔹荾鞖䪎芕隨䢫鐆遀砕膸埣瓍㻟璲㻪㻽歲歳睟瀡㵦浽澻㴚滖哸䠔雖䡵嵗㞸䯝髄亗賥韢熣煫襚禭䥙鐩夊檖䉌穂䅗穟㒸嬘䭉倠綏繐繀繸䍁䜔旞譢誶尿",
"sun": "孙损笋荪狲飧榫隼蓀薞蕵孫飱䁚㡄㦏猻鎨搎損㔼槂簨箰筍鶽",
"suo": "所索缩锁梭嗦琐唆羧唢娑蓑挲些睃睃嗍桫䓾莏䂹䐝䞽趖琑瑣㪽䖛溹溑逤䣔暛蜶嗩䞆惢褨鎍鎖鮻獕鏁鎻挱乺摍䵀䅴䈗簔簑㛖傞䌇縮莎",
"ta": "他它她塔踏塌榻沓蹋嗒拓獭挞趿遢溻鳎铊闼鞳鞜䓠㿹牠䂿䶁䶀墖㳠㳫澾涾毾躂躢蹹嚃嚺㗳䵬䍝遝崉䎓粏褟祂禢錔鰨鮙鉈㺚㹺獺狧撻㧺搨榙橽㭼㯓䑜䍇㣵濌䈋䈳㣛闧闥闒阘㛥侤㒓傝䌈誻䜚譶",
"tai": "大太态台抬泰胎苔汰钛酞肽薹骀邰炱跆鲐䑓菭孡態㣍駘夳冭坮臺㙵溙汏汱㬃旲㘆囼㥭忲䢰燤炲㷘㸀鈦鮐擡檯䣭䈚籉箈舦嬯㒗㑷㑀儓颱",
"tan": "谈探弹碳坦叹滩炭摊坛贪谭潭痰毯瘫檀坍袒覃忐昙钽澹郯锬藫歎菼䕊䃪貚䏙䐺墵䞡壜埮墰㽑壇璮灘潬湠曇暺嘆嘽啴嗿惔憛憳憻顃㲜㲭㷋燂䊤襢䆱鉭錟擹攤醈醓醰橝榃舑舕罎罈䉡癱䦔痑婒怹倓僋貪談譚䜖譠",
"tang": "堂唐糖躺汤塘倘趟烫膛淌棠搪螳蹚羰傥溏帑醣耥瑭螗铴镗樘鞺薚蓎隚䧜磄膅鼞赯矘漟燙湯坣䣘劏曭蝪踼䟖嘡啺戃糛爣糃煻鄌㲥鶶㼺禟鐋鏜钂鎲镋鎕㿩摥㭻橖榶䉎篖䅯闛㜍伖㑽儻㒉偒傏饄餹䌅㙶",
"tao": "讨套逃陶桃萄掏涛淘滔叨韬啕绦洮饕跳鼗鞱鞉鞀㹗騊駣㚐夲瑫㴞濤蜪飸咷轁幍慆韜裪祹迯鋾匋搯槄醄䵚嫍絛䬞饀䬢弢縚綯绹縧詜謟討䚯䛬",
"te": "特忑忒慝铽脦蟘㥂鋱㧹",
"teng": "腾疼藤滕誊䕨虅驣䲢幐縢螣騰鰧謄膯鼟霯漛䠮熥籐籘䒅䲍駦痋邆儯",
"ti": "体提题替梯踢蹄惕啼剔剃涕屉嚏锑棣倜悌鹈逖醍缇绨䪆䔶薙蕛䧅㯩騠髰鬄鬀碮厗朑䨑趧趯䎮瑅殢瓋睼漽渧題鶗惖逷㗣嚔蹏鷤嗁㖒罤䯜體骵䝰㡗崹惿屜褆䙗褅禔禵䚣鳀鯷鷈鮷悐銻鍗䴘鷉掦挮揥擿笹䣽㬱䶑䅠躰軆徲籊稊㣢䣡䶏鵜媞偍䬾緹䌡綈䛱戻謕歒鶙弟",
"tian": "天田甜填添佃恬腆舔阗钿畑忝殄畋掭菾黇磌碵䩄胋鷏㙉甛塡靔靝瑱㐁琠璳兲睓沺淟湉晪䟧䠄唺㖭䡒䡘鴫䐌覥觍賟悿屇㥏㶺窴錪䥖搷㮇䣯酟䑚舚䄼䄽闐痶婖倎餂鷆緂㧂甸",
"tiao": "条调跳挑眺迢窕苕佻笤啁粜髫龆蜩祧鲦䒒萔芀蓚蓨糶聎䯾朓趒齠晀旫䟭㟘脁岧岹恌庣宨窱祒覜鰷䱔樤㸠䠷䎄䳂嬥鞗䩦䖺鯈鋚鎥條絩誂",
"tie": "铁贴帖餮萜聑驖䵿蛈呫貼怗鐵鐡䥫銕鉄䴴僣飻",
"ting": "听停庭挺厅廷亭艇烃婷蜓汀霆町铤葶莛梃鞓聴聽聤厛鼮脡䵺圢耓珽涏渟䗴蝏甼嵉聼廰廳烴庁烶䱓鋌㹶邒桯榳楟頲颋筳䦐閮娗侹䋼綎誔諪",
"tong": "同通统痛童铜筒桶桐佟侗酮捅瞳僮彤潼嗵恸峒茼砼仝蓪㼧㪌䂈䮵犝朣赨眮浵晍蚒䳋曈哃㠽峝峂㠉膧慟㤏烔粡庝炵燑䆚䆹鲖鉵銅鮦狪獞鉖樋㮔橦筩憅㣠秱㣚衕穜䶱勭氃䴀㼿痌㛚㸗餇絧統綂詷",
"tou": "头投透偷愉骰亠蘣斢黈䞬頭㰯䟝㖣㡏䵉㢏鋀䱏鍮㪗敨婾媮妵㓱偸紏緰㕻䚵",
"tu": "图土突途徒吐涂兔屠凸秃荼钍菟堍酴蒤葖莵鷋駼鼵迌腯㐋堗圡瑹㻬㻯㻠㻌䖘汢潳涋湥塗跿䠈唋圗圖図嶀㟮䣝鷵怢悇廜庩宊鶟鈯釷鵵鵌鍎鋵揬捸捈䤅㭸梌䅷馟兎禿稌筡鵚瘏痜凃䣄峹嵞䳜",
"tuan": "团湍疃抟彖䵎貒墥剸鷒漙湪団䵯團畽圕慱䊜糰煓褖鏄鷻猯摶㩛槫檲篿䜝揣",
"tui": "推退腿颓蜕褪忒煺藬蓷蘈隤駾㞂尵㦌䍾䀃㱣螁蛻蹪蹆骽㷟㢈㢑魋橔頺䅪頹䫋頽穨㿉㾯㾽㿗㾼弚娧俀僓弟",
"tun": "吞屯豚臀囤褪饨鲀氽暾芚朜霕坉㼊豘涒旽蛌㖔噋黗軘臋忳㞘焞魨㹠㩔呑飩",
"tuo": "脱托拖妥拓驼陀唾椭驮沱砣鸵佗坨跎箨柁柝橐沲鼍庹酡乇䓕萚蘀莌阤嶞陁馱駄䭾驝騨驒駝馲駞㸰㸱毻碢砤鼧鵎脫堶槖沰汑涶跅鼉咜咃䡐㟎岮䪑袥袉㼠饦䲊鰖鮀鴕魠䰿鮵狏扡拕捝挩橢楕杔䴱彵籜䍫㾃嫷媠毤侂仛侻飥紽詑託讬",
"wa": "瓦挖娃哇蛙凹洼袜佤娲腽韈聉䎳砙膃劸㰪鼃䵷邷漥溛咓䠚嗢嗗畖㼘韤襪窐窪穵窊㧚搲攨屲瓾媧䚴",
"wai": "外歪崴呙㖞喎咼䶐䠿顡竵",
"wan": "完万晚玩湾弯碗顽挽烷婉皖蔓腕丸宛惋蜿豌绾纨莞剜脘畹塆菀芄琬箢薍萖萬㿸䂺䩊脕埦頑㝴刓壪琓瞣睕澫涴潫汍灣蟃晥晼晩踠唍輐輓贎䯈岏貦帵贃䝹忨卐卍翫䗕䘼䖤盌㽜鋄錽䳃鋔䥑鎫抏捖捥杤椀梚䅋笂妧婠倇㸘綰綩紈䛷彎",
"wang": "往王望忘亡网旺汪妄枉惘罔辋辋魍朢菵莣尪迋尫瀇㲿㴏㳹蚟蛧蝄暀罒輞罖罓㓁䤑棢徍彺䰣徃兦仼亾尣尩䋞䋄網䛃誷",
"wei": "为维围委未微谓卫味唯威危伟尾违伪慰魏喂胃纬畏韦惟苇萎尉蔚巍薇偎帷娓渭桅圩倭痿崴猬诿猥潍煨葳韪帏嵬玮逶炜隈隗洧涠沩囗軎鲔艉闱位䔺蔿䪋苿菋蓶葨䵋荱藯葦蘶芛蒍隇䧦䮹熭碨硙䃬㞇硊㕒䑊腲鄬爲䙿壝墛霨䞔霺䝐瑋㱬琟覹矀濻潙韑瀢渨潿溦浘湋洈濰溈蝛㬙韙蝟暐蜲蜼喴踓㖐喡䡺轊囲䵳罻圍㠕骩骫骪幃嶉嵔㟪峗峞嶶崣屗㞑叞褽犚螱㷉韡䪘韋違㥜愄愇懀燰烓煟煒寪頠鏏厃鳂鳚鍡鍏鮪鰄鮇鰃䲁鮠䥩撱㨊揻揋捤㧑楲㭏醀椳欈梶椲䈧㣲徫躗躛㦣衛衞䘙讆讏䉠覣犩䭳痏闈癓媙媦媁儰僞偉䬑颹䬐饖餵䬿餧偽縅緭緯㢻維䗽詴亹斖䜜謂䜅為諉",
"wen": "文问温闻稳纹吻蚊紊瘟韫雯汶刎璺阌鞰莬芠䎽駇馼鼤脗肳塭豱瑥䰚殟珳渂溫㳷昷㗃呡㖧呅輼辒轀蟁炆顐㝧鳁鎾鰛鰮魰揾搵抆榅榲桽穩穏䎹聞閿闅䦩閺問闦瘒妏㒚伆饂繧紋彣䘇螡蚉㐎鴍鳼",
"weng": "翁嗡瓮蓊蕹聬㹙㹚䐥䤰塕奣瞈滃暡螉㘢嵡䱵鎓攚齆䈵㜲勜鹟鶲罋甕",
"wo": "我握窝卧沃涡斡蜗喔倭挝龌渥莴幄硪肟臥萵䰀臒腛㦱瓁㱧齷䁊瞃濣渦涹蝸䠎踒唩㠛焥窩猧捰捾㧴枂楃婐媉婑仴偓",
"wu": "物无五务舞武屋误恶午吴伍污乌雾悟吾呜侮唔巫勿梧诬捂晤兀於芜戊毋鹉妩钨邬坞蜈婺鹜忤骛牾庑杌亡芴阢鼯圬浯鋈怃焐寤迕痦仵莁靰蘁茣蕪鹀鵐陚䎸隖奦務㡔嵍熃騖鶩䳱敄䮏鴮碔矹䃖䑁㬳霧雺霚塢墲鵡珷珸郚㻍㐚逜㐏忢瑦卼玝璑瞴洿汚汙洖溩㵲潕螐旿蟱䟼躌吳呉嗚䡧䍢峿屼嵨岉剭悮悞憮乄熓粅廡㷻窏窹祦鋙铻鄔鯃烏鰞歍鎢㹳扤摀㐅杇啎無鷡橆甒鼿齀箼䒉㽾䦜䫓䦍娬娪嫵娒倵俉㐳儛㑄弙䳇誣誈䛩誤譕",
"xi": "系西细习息吸喜戏析希席洗稀惜悉袭腊溪媳牺锡嘻夕隙晰栖膝熙昔烯熄禧鳃徙嬉犀蟋奚兮曦蜥汐翕玺唏螅铣淅硒皙熹窸羲矽檄郗忾僖屣歙樨觋娭豨咭葸菥蓰隰鼷舄浠粞裼穸禊饩欷醯舾阋㐂葈蕮蒵䩤䓇匸煕蓆莃薂蒠覡隵隟䧍䢄枲騱驨騽䮎犔犠犧磶磎礂䲪䙽㚛䐼䏮貕舃肸肹谿䫣㙾霼趘䨳趇欯囍憙歖霫赩赥豯卌琋壐璽瞦䀘鬩戲䖒矖戱卥戯睎盻覤㳧澙渓潟鸂虩漝㵿漇潝螇暿蟢蠵晞嚱躧蹝呬㗩㕧焁唽噏喺繫黖㽯嵠巇㠄嶍酅㔒忚㤴慀恄憘㤸怬屃屓屭㥡㦻悕習飁恓㞒屖焟熺糦㸍焬熂燨爔熻邜鐊觿觽觹鳛錫鑴饻鱚鰼鯑鉨釸鈢㹫㺣鎴釳鏭狶鉩扱鵗㩗忥氥扸墍㯕榽䙵橲槢桸晳惁椞㮩㭡厀椺橀怸熈㷩稧徯㣟䈪郋鄎徆襲㿇凞瘜闟䊠㜎衋嬆傒翖俙㑶係饎餼餏郤豀縘繥緆細縰綌绤謑䜁譆諰焈謵䛥䜣䚷洒蹊",
"xia": "下夏吓狭辖霞峡瞎厦虾暇匣唬遐侠黠呷瑕罅狎瘕硖柙蕸陿陜䖎騢硤碬磍夓埉圷㙤赮丅乤珨睱䖖虲蝦㗇㽠㘡翈轄峽懗䫗㰺䪗舝炠煆烚鶷䘥祫鎼鏬鍜魻鰕鎋狹梺筪敮舺閕䦖疜閜傄俠颬谺縖諕䛅",
"xian": "现先线显限县鲜险献宪陷仙闲纤腺弦贤嫌掀咸衔羡掺涎娴见酰舷藓馅锨铣冼霰暹籼苋痫氙蚬岘莶燹跹跣祆猃筅鹇藖韅䁂賢贒莧䵌㔵蘚䒸䕔薟苮䧟䧋䧮陥険險礥䃱尠䃸臔姭䏹鼸毨胘韯壏塪赻䨘垷埳䨷現豏珗䶢䶟獻睍縣鹹県盷瞯涀灦㳭瀗㶍㳄鍌㵪澖湺䝨尟㫫晛蜆䗾顕䘆㬗蛝顯㬎蚿㘋咁咞嘕哯蹮躚啣㘅嗛輱䞁幰峴㡉崄嶮㦓忺憪憸糮粯廯䵇烍㡾麙鶱憲褼襳禒鑦臽䚚䀏鋧䥪䱤鱻䲗鮮銽錎䤼鍁銛铦銑獮玁狝㺌獫㧋搟攇㩈㧥撊撏挦攕㮭醎枮櫶杴㭠橌橺麲㭹㯀䉯䢾㪇箲馦秈銜䉳衘稴屳閒鷳羨鷼閑鷴㜪䦥㿅癇癎甉㛾娊奾嫺嫻嬐孅娹妶仚僊僲僩僴餡韱佡伭綫纎繊線缐絤㢺纖婱絃諴誢䜢譣誸洗",
"xiang": "想相象向响像项乡降香羊享箱祥详湘橡翔巷厢镶襄饷骧芗飨衖葙蟓庠鲞缃缃項瓨䔗萫䢽薌驤䐟膷䜶珦瓖晑䖮曏跭㟟嶑㟄䊑廂麘襐勨鱌鱶鱜鐌銄鑲栙楿欀缿稥忀鮝鯗姠佭餉饟緗鄊蚃鄕郷鄉蠁響嚮㗽饗絴纕亯㖜㐔詳",
"xiao": "小消笑效校销削晓肖硝萧孝啸潇俏嚣哮淆宵箫霄筱逍骁姣枭哓鴞蛸崤魈枵绡绡䒕虈䕧䒝蕭藃驍硣膮斅斆㬵毊瀟揱涍㕾敩洨蠨蟏暁曉蟂蟰嘵嘋鸮踃嚻囂呺嘐㗛咲嘯嘨髐髇憢㤊恔庨焇灲熽䊥灱宯窙銷鴵䥵梟㹲猇獢郩殽皢皛撨櫹穘鷍筿簫簘篠痚痟効㔅歗婋虓侾翛㑾烋颵俲傚綃彇謏誟歊誵訤詨",
"xie": "些解写协谢械鞋斜谐胁泄歇邪契携卸屑泻蟹懈挟蝎偕楔勰亵燮鲑撷颉榭邂缬澥瀣廨躞叶薤渫獬榍绁靾鞢鞵䕵䩧䢡藛薢䕈䔑㔎㕐絜脅脇劦膎協㙝奊翓塮暬垥瑎齛齥齘禼卨䪥韰㱔㳦洩㴮瀉㵼㴬㴽㳿蝢旪蠍蠏㖑嚡噧㖿嗋䵦䡡峫嶰屟恊愶屧㞕㥟㦪灺緳熁燲糏炨炧䊝冩寫㝍褉䙎襭䙊祄㙰䲒䥱䥾猲揳挾拹㨙擷攜㨝烲焎娎㩉㩦擕㩪㰔䉣缷徢齂㣯䉏㣰䦑㸉㓔䦏媟孈脋伳偞偰龤㙦㒠㰡僁䭎紲緤綊纈絏縀繲絬衺䚳䙝褻讗爕夑㽊謝䚸諧血",
"xin": "心新信欣辛薪锌芯馨鑫衅昕訢忻莘炘歆囟忄镡䒖阠孞馸舋釁脪盺噷噺軐惞廞焮襑鈊䰼鐔鋅邤㭄杺枔馫顖嬜妡㛛㚯㐰伈俽伩䜗䚱訫䛨",
"xing": "行性形兴型星省幸醒刑姓杏猩腥邢惺悻荥陉擤荇硎饧䓷莕葕陘骍騂臖興㐩㓝㼬㙚垶㼛郉瑆䣆䁄睲涬洐蛵曐哘䳙煋滎㝭觲觪䤯鈃钘鉶铏銒鋞鯹鮏㨘䰢皨㮐䂔㣜箵篂㓑嬹婞娙倖侀餳緈䛭謃",
"xiong": "雄兄胸凶熊汹匈芎熋䧺洶焽焸哅賯恟忷夐敻胷匂兇詗诇詾訩讻㐫",
"xiu": "修秀休袖臭羞绣朽锈嗅溴貅岫咻宿髹庥馐鸺苬髤脙璓臹珛㱙琇潃滫螑嚊㗜峀糔烌鱃鮴鏥銹鏽鎀鏅銝樇齅㾋脩鵂俢飍饈綉繡繍褎褏",
"xu": "许需须续序虚徐绪叙蓄吁絮婿嘘旭栩墟畜浒戌胥圩恤煦蓿酗顼诩魆洫盱砉溆勖糈醑芧蕦藇藚㰲蒣聓䔓㜿䦽㞊䳳㷦㕛㐨䂆驉㚜㦽鬚䢕盨媭嬃須㘧壻垿珬頊珝殈㺷瞁虛歔虗汿沀㵰湑潊漵朂晇暊勗旴冔蝑昫㖅噓㗵呴喣盢㞰賉怴㤢㥠慉燸烼歘欻烅裇䙒禑銊鑐欨鱮䱬獝揟魖䣱䣴楈槒聟䅡鄦卹䘏欰稰稸疞㾥䦗䍱姁㜅㑔㑯敍敘伵偦䬔侐俆䋶續続緒緖縃綇䜡訏譃諿詡諝谞訹許䛙休邪",
"xuan": "选宣旋悬玄喧轩绚眩炫渲漩暄萱癣煊镟璇县碹泫铉揎楦痃儇谖萲䩰鞙䩙蓒蕿藼蘐蔙䧎駽䮄塇璿琄瑄琁玹懸睻眴矎贙䁢㳙㳬晅昍蠉暅蝖蜁暶昡咺䠣吅軒翾䴉㘣䍗䝮愋懁選愃怰烜翧䘩袨禤䚭䚙鋗䴋鰚䲂鍹㹡鏇鉉㧦楥梋檈箮衒䍻癬㾌媗嫙颴弲繏絢縼諼譞諠䗠䲻券",
"xue": "学血雪削穴薛靴谑踅噱鳕泶蒆鞾茓辥膤學觷壆澩嶨燢鷽䨮趐坹瞲㔧辪㶅瀥峃鸴㗾㖸吷轌㞽㡜岤䎀袕鱈䱑狘㧒㿱乴樰䤕桖艝疶䫻䬂䫼䭥斈謔",
"xun": "训迅寻循讯巡询旬逊驯勋熏汛殉荀薰峋洵浚鲟徇浔醺窨荨埙巽蕈孙曛恂郇獯蘍薫愻遜馴駨顨奞毥臐壦攳坃塤壎殾燅珣璕矄潠潯畃䖲蟳勛噀嚑噚䞊卂巺㽦爋燻燖䙉㝁迿㰬鱏鱘鑂狥㨚灥揗㰊杊栒樳桪稄勲勳鄩尋廵焄㜄侚伨偱㒐䭀紃䋸纁㢲訓訊詢䛜訙",
"ya": "压呀亚牙雅芽鸭押崖哑鸦讶丫涯轧衙娅伢蚜桠氩垭碣琊疋迓邪砑睚吖岈揠痖蕥䪵鴉聐孲厊圧厓䃁壓厑䝟劜堐埡圠玡亞鵶䢝㰳亜襾齖齾漄啞唖圔䵝軋鴨崕䯉㿿庌䊦庘㝞窫錏鐚铔䰲犽猰猚㧎掗氬挜枒椏覀笌䄰稏䅉冴疨瘂䦪婭俹訝",
"yan": "眼研验言严演烟沿盐延颜岩炎燕掩厌艳咽焰铅宴衍殷阎雁淹砚檐焉彦蜒俨奄谚腌堰晏胭嫣阉湮筵兖妍偃唁鼹恹琰赝魇滟酽焱餍甗郾菸厣埏鄢罨崦剡闫谳讠鹽匽鶠䕾酀㬫鷰㷼䴏嬊莚萒蔅䓂隁隒驠騴騐験驗牪硽黡䊙揅硏硯夵魘厭厴懕黶檿嬮饜䣍剦礹䂩鳫贗鴈贋㷳䶮䂴臙䑍鼴墕壧䎦䀋塩壛㿼䢥珚琂齞齴䖗鬳䁙覎䀽虤沇厳漹灔灎灧灩淊溎渷㶄㳂渰蝘曣㦔猒䗡暥曮鷃曕妟䳛昖㫟嚥嚈囐嚴碞喦嵒㘙啱㗴喭㘖噞黭黫黬黤艶艷豓豔巘巚巌嵓巖巗觃嵃嶖愝懨熖㷔焑敥炏焔煙烻㢂爓㢛麣戭褗裺鴳䄋䤷觾燄鰋䲓䱲狿抁揜椻㭺歅醼醃釅醶欕棪樮椼櫩楌篶郔䗺躽軅簷䅧䇾閆閹龑䢭兗乵閻顔遃㿕嬿㛪姸孍㚧姲娫娮傿弇顩㕣儼偐䭘酓㓧䳺䨄縯䊻綖䌪讌䜩顏彥訮詽讞扊諺㫃訁",
"yang": "样养阳洋氧央杨扬羊仰秧痒漾疡佯殃鸯怏鞅恙徉炀暘泱蛘烊陽阦駚礢胦䑆霷雵坱垟珜䁑眏眻瀁䬗昜敭蝆䖹旸㬕咉䵮輰軮㿮崸䒋鴦崵岟㟅懩慃煬炴鍈卬鍚鉠钖鰑㺊氜揚氱抰㨾攁楧鸉楊柍様樣䇦劷羏㔦羕飬養瘍鴹癢姎佒飏颺䬬䬺䭐傟紻諹詇详",
"yao": "要药摇腰咬耀遥邀瑶姚窑妖谣钥尧么乐吆肴夭侥舀幺徭珧杳窕窈鹞繇曜爻约轺崾鳐䔄蘨靿薬藥葽蓔苭葯騕磘㞁䂚䍃颻鷂飖尭垚顤堯瑤殀䋤䶧齩䁘㔽矅覞䁏眑㴭溔滧㵸㿢暚䖴㫐嗂喓鷕軺峣嶢嶤岆㟱愮熎燿烑㢓䴠宎㝔䙅袎窰䆙窅䆞穾窯窔祅鎐鰩鱙猺遙獟狕䚻䢣䌛邎揺抭搖㨱摿榣柼㮁楆枖榚鴁鼼䉰筄䑬艞㿑闄媱婹傜倄偠仸䬙餆餚鴢䌊䋂纅謡謠訞㫏䚺讑詏疟",
"ye": "也业夜叶液爷野喝页冶耶咽邪拽曳腋椰掖噎晔谒揶射邺靥吔烨铘䓉葉枼䧨驜靨擪㪑頁礏墷枽㙪㐖璍瑘殗瞸瞱潱澲漜洂曄曅蠮暍曵曗嘢㗼㖶㖡㙒嶪嶫燁煠㥷爗鄴鸈業㱉㝣鐷鋣釾䥺鍱鎁䤶鎑馌䲜䥟䥡䤳擛皣捓抴擫歋㩎捙擨㭨壄埜䈎㸣僷倻爺䭟餣饁謁亪亱鵺",
"yi": "一以义意已艺易议咦依益衣异医移遗疑亦宜仪忆伊倚乙亿抑役毅译椅翼姨蚁泄谊疫逸矣溢夷疙绎尾蛾怡胰贻裔彝邑奕翌屹臆颐诣驿熠咿蜴漪沂呓揖弋轶迤懿悒佚羿噫铱弈壹肄翳癔缢刈旖苡怿痍猗诒峄食射荑薏埸圯殪眙嗌黟嶷嶷衤饴钇镱镒挹酏劓舣瘗翊仡佾蘙芅匜䩟藝蓺虉弌頤巸媐䖁䓃㔴䔬苢勚勩萓苅殹㙠醫鹥瞖繄䗟贀悘鷖黳嫛毉瑿萟䓈藙䓹䕍䬥隿耴迆阣䧧㹓瓵䮊驛駅䭿逘礒䝝帠肊䐖䐅鶂膉貖䝘敼㰻霬墿夁亄㦤鷧㱅壱坄㙯埶㺿玴珆豷豛䰙鹝鷊辷㱲殔鴺乁頥齮齸頉㵩浳㶠渏沶㴁洟浥潩㳑瀷㲼泆浂澺洢㵝㴒湙曀蛦晹䗑曎螘蛡敡鶍螔蟻䗷螠蛜暆囈呭㘊跇遺跠㖂唈㘁呹吚㕥㘈異欭輢黓睪斁歝圛軼轙畩貤貽䞅骮䯆顗峓幆嶧䝯嶬崺怈㦉恞㠯䎈郼䢃懌乛㞔㰝㥴忔攺憶㡼廙熼燡㢞熤燚熪燱炈庡焲宧冝宐㝖襼袣䘝衪裿褹袘寱䘸䆿迱寲䄁祎禕釴鈘釔鉯䱌鶃鮧鯣䱒鳦鸃䲑鮨鏔匇迻狋㹭獈鐿鎰鈠銥撎䖊㣻拸乂㩘枻杙杝槸䣧醳醷桋栧椬栘柂檥檍榏枍䴬㰘椸檹棭䄬劮鄓㓷䇵䄿䇩穓顊稦笖簃乊䉨艗艤秇垼篒籎瘞瘱豙䴊義羛羠鷾痬䦴竩兿鹢鷁嫕㚤㜒嬄㚦㛕彛彞嬟嬑㜋㛄佁侇㑥俋伿㐹㑜䬁儀億飴饐䭂䭞䬮䭇伇㥋偯㑊弬㣂㡫䋵繹䋚䌻彜觺㽈繶縊讛詍裛詒旑訲讉譯㦾扅悥扆訳帟誼誃謻㫊議譩詣蛇",
"yin": "因音引印银阴隐饮姻吟殷荫淫尹茵寅蚓瘾龈垠胤喑氤窨鄞吲圻狺铟茚霪堙洇廴夤夤蘟蔭䕃鞇靷荶蔩䓄蒑䒡隱檃櫽隠阥陻隂陰骃駰㹜碒磤㕂㥯㸒䨸霒趛赺韾堷霠烎璌殥慭珢齗齦龂䖜濦滛濥垽㴈峾溵乑湚泿洕朄螾蟫噖嚚㖗噾䡛囙輑圁嶾湮㡥崟崯㞤訔㦩懚㥼愔廕粌㝙㪦冘裀禋䤺䲟淾銦鮣犾鈝㹞銀鈏㼉㧢斦慇㐆㧈檼垔䤃酳鷣栶檭猌㙬憖憗筃秵㣧䇙癮癊䪩㾙闉凐瘖訚誾婬婣飲侌㱃飮䌥絪緸讔䚿諲訡",
"ying": "应影英营映迎硬盈婴鹰颖赢荧蝇莹莺樱瑛萤鹦萦缨膺瀛荥璎嘤媵罂瘿茔楹郢滢颍嬴景蓥潆撄萾㲟鶧蘡藀䕦盁孾碤礯䃷朠膡䑉霙䨍珱瓔㼆䁐䀴鷪渶溁溋㵬浧㴄瀴濴瀠㶈瀯濙灐濚瀅蛍営鴬灜暎蝧蝿蠳蠅嚶甖巊鑍鸎罌嬰鸚賏譻巆愥煐㢍廮応罃褮塋䁝禜縈螢䪯營熒鶯覮鎣嫈瑩甇謍鶑噟應鷹譍䙬锳鐛鱦䤝㨕攖摬攍桜梬櫻櫿矨軈籝籯韺癭㿘媖孆偀僌㑞䭊䭗緓绬頴颕潁纓㯋穎贏",
"yo": "哟唷喲",
"yong": "用永勇拥涌庸泳佣咏雍踊蛹臃俑甬壅鳙恿痈邕喁慵湧墉镛饔苚蒏㦷勈硧砽惥埇䞻塎㙲慂滽㴩灉澭顒颙䗤踴嗈噰㞲嵱愑悀愹怺㶲醟鄘鷛廱彮㝘鲬鯒鱅鰫鏞郺擁柡栐㷏牅癰癕雝嫞傭㽫詠",
"you": "有又由优油友游右幼尤犹忧邮幽诱悠铀佑黝柚囿蚴酉釉疣猷莠攸祐鱿繇鼬蚰牖呦莜莸尢卣蝣宥铕侑苃䒴蕕䢊聈牰駀䀁鄾迶憂䳑肬貁䞥耰丣㻀逌䚃瀀沋㳺湵滺浟泑蜏䖻哊嚘㕱唀㘥輏輶㽕峟甴峳懮㤑怞怮庮麀䆜禉銪鲉鈾魷鮋䱂㹨狖㺠猶逰㮋栯櫌櫾酭梄槱楢郵怣牗㰶秞䅎䑻㕗羑㾞羪姷㚭優佦㒡㛜䬀偤纋孧㓜訧亴䛻遊誘䢟㫍",
"yu": "于与语育鱼余雨预域玉遇予欲宇愈渔誉郁羽狱御裕愉豫愚喻娱寓浴吁舆尉榆俞禹屿淤逾峪谕於迂虞瘀驭芋隅渝瑜阈毓盂汩熨禺腴揄臾煜钰彧鹬鬻谀馀聿纡竽伛龉觎圄欤妪玙邪蓣萸舁雩蜮昱蝓圉嵛庾庾燠窳窬饫狳瘐妤肀俣鹆蕷蘛㔱䩒芌蕍茰蒮䔡䖇萭薁蓹蘌茟匬萮陓隃䂊矞預鷸遹䮙驈馭䮇騟䂛戫礖砡㝼礇䃋硢硲䏸礜轝㦛鸒歟與譽輿䐳雤貐斞霱堣䨒迃亐圫䨞堬堉琙璵邘㺮㪀玗䢩敔䜽鳿瑀齬齵鸆䁌䲣䱷䁩睮歶淢㳚潏滪澦㳛盓澞湡漁灪淯㶛虶㬂䗨欥㬰蜟噳踰喅喩唹罭㽣輍骬嶼㠘髃嵎嶎䍞㠨崳惐䣁忬頨懙㥚㥥㤤㥔燏㡰粖庽㷒爩麌焴䢓㲾䴁䵫寙㝢䙔衧褕䆷穻鴧鴪䄏祤鈺鍝魣鱊鰅鴥鷠䰻魚鮽鯲㺞鐭䥏㺄獄銉鋊錥㼌扝扜挧魊扵棫櫲桙楰醧杅酑鬰欎欝鬱楀楡棛棜稢䈅稶穥籅䍂䄨䘘牏鄅㙑軉秗禦䉛篽籞艅艈籲込箊閾瘉羭癒䘱嫗嬩㚥䢖媀娛娯傴伃僪㒜儥兪覦歈㼶悆雓俁㑨㒁䬄偊饇飫餘螸慾鵒俼緎紆䋖㣃逳袬諛謣語斔䛕旟諭乻吾奥粥",
"yuan": "原员远元院源愿圆园缘援袁怨冤渊猿宛苑垣媛鸳辕沅爰橼塬鸢圜螈垸瑗鼋湲芫眢掾蒝薳䩩薗蒬茒葾鳶㹉䏍貟贠騵厡厵願鶢䳒䳣遠鼘逺邧䲮黿㤪盶溒渁鼝淵渆渕灁蝯蚖蜵蜎䖠蝝肙剈噮鶰員圎園轅囦圓㟶円㥳悁鹓惌鵷寃褑褤裫裷禐駌夗鴛妴鎱鈨魭鋺猨㭇榞榬杬酛棩櫞笎衏邍羱䅈䬇嫄媴嬽傆㥐䬧䬼䨊縁緣謜䛄䛇",
"yue": "月约越跃阅悦曰岳乐粤兑钥栎钺说刖瀹哕樾龠䖃戉蘥㹊玥䢲泧㬦蚏蚎䟠噦跀躍䠯啘䢁黦䡇軏岄曱嶽恱悅爚礿禴鉞鈅䥃鸑䤦鑰抈捳㰛籆矱籰粵籥篗箹閲閱嬳㜧妜㜰鸙䶳䋐約",
"yun": "运云允匀韵孕晕蕴芸陨酝韫耘恽纭熨愠氲筠郓郧殒员昀狁蕓䩵荺蕰薀蒀蒷蒕藴蘊阭耺隕馻夽奫磒腪䢵䨶䲰雲䞫霣㚃鋆殞齫齳眃沄澐涢溳蝹暈鄖䚋喗囩䵴䡝畇賱㟦㞌韗韞愪慍惲煴熉熅鄆運褞䆬鈗䤞勻抎氳抣枟橒醖醞秐䉙馧筼篔䦾䇖韻㾓㚺妘㛣㜏䪳伝傊餫紜緼缊縜縕贇赟",
"za": "杂咱扎咋砸咂匝拶䕹臜臢䞙䪞帀迊沯沞囋囃襍鉔魳桚韴雑雥雜",
"zai": "在再载灾仔栽宰崽哉甾䏁䮨載䵧烖㦲酨㱰睵渽溨洅㴓㞨賳扗畠䣬災傤儎縡",
"zan": "咱赞暂攒簪瓒錾糌趱昝㔆兂趲瓉鄼賛瓚濽灒噆喒暫蹔鏨㟛寁襸禶鐕鵤鐟撍攅攢揝橵贊簮㜺儧儹偺㤰饡㣅讃讚",
"zang": "藏脏葬赃臧奘驵蔵塟匨駔臟臓羘㘸贜贓髒賍賘弉銺牂",
"zao": "造早遭藻燥糟灶躁枣凿噪皂澡蚤唣薻䥣㲧趮栆璪璅䖣䗢蹧喿唕慥㷮煰鑿竃竈䲃皁醩棗梍簉艁䒃傮䜊譟",
"ze": "则责择泽侧啧仄赜咋昃帻箦迮舴蔶賾䕪䕉矠礋責齰䶦齚歵瞔㳻㳁澤溭沢滜泎汄蠌昗㖽嘖鸅幘則崱庂襗䰹皟捑擇択樍䇥簀㣱嫧諎謮",
"zei": "贼蠈賊戝鲗鱡鰂",
"zen": "怎谮䫈譖",
"zeng": "增综赠憎曾锃甑罾缯鬵磳増䰝璔囎㽪贈熷䙢鋥鱛橧矰鄫曽繒譄",
"zha": "扎炸眨渣闸喳榨诈栅札乍楂喋蚱柞铡咤查咋砟哳吒揸齄痄䕢䃎厏䞢耫霅㱜皻㪥㗬㴙溠䖳灹㡸宱觰鲊鍘鮓䥷抯摣紥挓搾拃柤醡樝皶蚻紮䵵牐齇劄箚䵙㷢閘鲝鮺偧㒀䋾譇䛽詐譗",
"zhai": "摘窄债宅寨斋翟砦责择侧祭齐瘵㡯鉙粂捚㩟榸檡夈債斎齋",
"zhan": "展战站占粘颤沾崭盏斩毡湛瞻栈辗詹绽蘸谵旃霑搌㠭菚虦盞䪌薝驏驙䩅氊趈䟋琖㻵虥䁴惉戦魙䗃蛅戰噡輾轏斬覱㟞岾嶃嶄嶦嶘㞡䎒䘺鳣䱠䱼鱣㺘棧桟醆枬榐栴橏䡀㣶閚嫸偡佔僝飐颭飦饘䋎綻詀讝氈鹯鸇邅譧譫旜",
"zhang": "长张章掌丈障涨帐仗胀账杖璋彰樟瘴漳蟑嶂鱆獐幛鄣嫜仉蔁騿礃脹墇㙣瞕涱漲暲㕩賬帳幥慞粻粀麞鏱扙痮㽴遧瘬傽餦張",
"zhao": "找照招召赵着兆昭沼诏朝钊肇濯啁棹罩爪嘲笊䮓駋㕚䃍㐍䝖爫趙垗瑵瞾曌㷖䍜羄燳㡽炤鍣釗鮡狣㺐鉊㨄櫂枛罀箌䈇䈃䍮㐒巶妱㑿佋皽肈肁旐詔",
"zhe": "这着者折哲遮浙蔗褶辙锗辄蛰蜇赭柘鹧摺螫谪著磔䩾䓆䎲㪿䮰䂞矺厇砓詟䐑䐲䏳喆嚞乽蟄謺䝕䝃歽淛蟅晣虴啫踷䠦嗻輙輒䵭轍㞏䗪鷓粍籷䊞襵袩銸鍺鮿埑晢啠悊㯰樜讋嫬這謫讁",
"zhei": "这",
"zhen": "真针阵镇振珍震诊侦贞枕圳砧斟疹臻甄祯桢朕赈帧榛缜箴畛稹填蓁胗溱浈轸鸩椹葴蒖䑐䫬薽萙塦陣聄㓄駗碪鬒䂧䂦㪛䏖䨯瑧殝珎遉貞眹眕㴨湞潧澵昣䟴辴轃黰甽軫賑帪幀䝩屒䲴寊䪴鴆裖袗禛禎鍼鋴針鎮錱覙鱵獉鉁鎭挋䳲揕搸抮㮳酙楨樼㯢栚籈姫嫃侲㐱偵弫䊶縥絼縝㣀眞紾紖纼誫診",
"zheng": "正政争整证征丁蒸症郑睁挣怔拯铮筝狰峥诤徵钲聇脀烝氶䂻鬇爭㱏埩靕鴊䥭睜眐塣晸踭䡕崢崝幁㡧㡠炡䥌鉦錚猙鏳掙揁掟抍撜愸篜箏徰䈣䦛䦶鄭㽀癥姃媜佂凧䋊䋫糽䛫証諍證",
"zhi": "之只制质知指直至志织支值致职止植置纸智执殖枝脂秩肢滞拓汁旨址稚芝吱帜蜘挚掷侄趾治识酯窒峙炙桎栉雉祗芷咫痣栀氏胝祇跖踯鸷蛭枳帙痔徵贽姪沚陟骘陟膣豸埴郅踬轾轵忮黹祉觯卮摭絷夂彘蘵芖䓌䛗䓜迣茋䓡藢䕌聀阯騭隲䏄㝂䎺職犆馶駤馽厔㕄砋礩䐭䐈䏯胑䑇乿膱墆鳷䧴坧䟈㙷覟墌疐坁垁漐縶贄慹騺鷙䥍摯執瓡驇臸瓆璏歭㫖淽滯滍汥洔淔洷㴛潌汦泜潪瀄晊蟙跱蹠躓躑㗌㗧㘉畤䡹輊軹豑豒剬䞃幟崻懥懫翐恉庤庢廌㡶熫寘衼襧衹袟禃祬祑帋觶觗䚦鋕銍铚䳅䱨鯯㩼锧鑕狾猘釞劧㨁貭搘挃㨖巵㧻抧摨搱扺扻劕質䭁擳擲梽榰㮹梔櫍椥柣櫛䵂栺樴㲛䝷鼅䵹鴙䅩秓徝稙憄䉅秷製䱥䄺䇛徏軄徴筫穉䆈稺秖䇽䉜㣥瘈痓䦯疻疷㜼娡㛿妷嬂値俧凪傂儨倁偫䬹隻綕緻䌤鴲紙紩織誌訨袠戠䫕旘",
"zhong": "中种重众终钟忠肿仲衷踵盅冢锺忪螽舯茽蔠刣尰鼨腫塚堹歱泈汷蚛蜙蹱喠眾幒煄炂衶衳祌銿鈡䱰鴤鍾狆㹣鐘㲴柊衆籦種㣫徸彸筗瘇妕媑妐偅伀㐺終螤諥蚣",
"zhou": "周州洲宙轴骤皱昼舟咒粥肘帚绉胄纣诌妯繇啁调荮碡酎籀䩜菷葤㔌䎻驟駎騆駲䐍䶇霌盩珘睭淍䖞晭嚋呪喌噣咮輖軸輈辀冑郮週㼙賙赒㥮粙炿烐皺鯞銂矪徟甃籒籕鸼鵃箒䈙䇠疛㾭晝婤㛩伷㑳㑇僽侜紂縐䋓诪譸詋䛆謅",
"zhu": "主住注助逐著宁筑诸珠猪竹朱柱祝驻株贮嘱煮铸烛蛛瞩竺蛀拄伫褚诛侏澍潴箸渚炷躅铢瘃苎术属茱翥洙麈橥杼槠邾舳疰丶茿莇藸蓫䕽苧蕏陼䎷逫馵䮱駯駐劯硃砫䐢墸䟉壴坾䬡煑䝒豬櫫矚眝㵭瀦濐灟乼蝫蠋曯蠾蠩跦跓囑鸀罜軴帾貯嵀䝬劚斸㤖㔉㫂燝燭爥炢麆㝉㿾䘢袾窋宔祩鋳鑄钃鯺鱁鮢䥮㺛銖㹥鉒拀㧣柷欘樦櫧笁篫築笜筯䍆鴸鼄篴䇧簗䇡秼㾻竚羜孎㑏佇䭖飳䰞䌵纻紵絑紸諸迬殶詝誅註",
"zhua": "抓爪髽膼撾檛簻挝",
"zhuai": "拽转跩",
"zhuan": "转专砖赚撰篆传颛馔啭蒃孨磚磗膞腞塼堟瑼鄟專甎叀専瑑蟤囀䡱転轉顓賺灷襈鱄篹籑䉵竱嫥僎饌縳諯譔",
"zhuang": "状装庄壮撞桩妆幢僮奘戆庒荘莊壵湷糚粧樁梉狀壯焋娤裝妝",
"zhui": "追缀椎坠锥赘惴骓隹缒墜騅硾礈腏膇贅沝畷䄌錣鑆鵻錐醊甀笍娷綴縋諈揣",
"zhun": "准谆淳屯肫窀埻迍準啍㡒宒衠稕凖綧訰諄",
"zhuo": "捉桌著卓着浊灼啄琢拙酌镯茁斫濯淖涿棹擢焯浞禚倬诼斮斲䕴䪼叕硺䶂龺圴斱琸鵫灂濁汋晫蠗啅罬斀劅㣿㪬蠿烵炪丵窡窧鐯鋜鐲㺟犳斵擆撯棳椓㭬槕櫡棁梲穱籗籱篧彴䅵穛娺妰諁諑謶鷟缴",
"zi": "自子资字紫仔姿滋兹姊籽咨孜渍梓髭恣滓谘淄呲孳鲻龇辎甾眦秭赀吱齐茈趑耔觜訾嵫锱笫粢缁芓蓻茡荢䔂茊葘菑茲孖牸矷頾頿胏䐉胾嗭赼趦鼒㺭剚鄑㱴㰷齜眥呰啙貲胔鈭㰣姕漬澬湽虸吇嗞輺輜崰䘣禌釨鰦鯔鎡镃鍿錙㧗杍橴榟椔秄䅆稵資栥秶㾅㜽姉鶅倳紎緇緕纃訿齍諮孶玆",
"zong": "总宗综纵踪棕粽鬃熜偬从腙葼蓗骔騌騣惣㹅鬉䰌碂磫朡堫䝋豵鬷昮蝬䗥蹤踨䍟嵏嵕嵸惾翪燪糭㷓糉㢔焧鑁鯮鯼鍐猔猣㚇揔摠搃捴㯶椶稯熧瘲疭倧傯倊綜緫緵總繌縦縱縂総緃",
"zou": "走奏邹揍陬鄹驺鲰诹菆郰棸騶赱㔿齱齺㵵䠫黀鄒鯫鯐掫棷箃緅諏",
"zu": "组族足祖阻租卒诅镞俎菹靻䔃蒩葅䯿珇䖕唨踤哫㞺崒崪䚝䱣鎺鏃爼椊䅸箤卆組䘚詛㲞㰵",
"zuan": "钻攥纂躜缵繤䂎躦鑚鉆鑽䤸劗籫纉纘䌣",
"zui": "最嘴罪醉咀蕞䮔厜璻蟕晬嗺噿嶵㠑嶊冣㝡䘹祽鋷錊酻酔樶檌㰎栬槜檇辠䘒稡纗絊",
"zun": "尊遵樽鳟撙墫噂嶟鶎銌鱒鐏捘罇鷷僔繜譐",
"zuo": "作做坐左座昨佐琢撮柞唑祚捽阼胙嘬怍酢笮葄葃蓙䔘苲莋㸲㝾䞰䎰咗㘀㘴岝岞䝫糳袏鈼㭮稓穝秨筰㛗㑅飵侳繓䋏"
}

View file

@ -1,39 +0,0 @@
local Element = require('elements/Element')
---@class BufferingIndicator : Element
local BufferingIndicator = class(Element)
function BufferingIndicator:new() return Class.new(self) --[[@as BufferingIndicator]] end
function BufferingIndicator:init()
Element.init(self, 'buffering_indicator', {ignores_curtain = true, render_order = 2})
self.enabled = false
self:decide_enabled()
end
function BufferingIndicator:decide_enabled()
local cache = state.cache_underrun or state.cache_buffering and state.cache_buffering < 100
local player = state.core_idle and not state.eof_reached
if self.enabled then
if not player or (state.pause and not cache) then self.enabled = false end
elseif player and cache and state.uncached_ranges then
self.enabled = true
end
end
function BufferingIndicator:on_prop_pause() self:decide_enabled() end
function BufferingIndicator:on_prop_core_idle() self:decide_enabled() end
function BufferingIndicator:on_prop_eof_reached() self:decide_enabled() end
function BufferingIndicator:on_prop_uncached_ranges() self:decide_enabled() end
function BufferingIndicator:on_prop_cache_buffering() self:decide_enabled() end
function BufferingIndicator:on_prop_cache_underrun() self:decide_enabled() end
function BufferingIndicator:render()
local ass = assdraw.ass_new()
ass:rect(0, 0, display.width, display.height, {color = bg, opacity = config.opacity.buffering_indicator})
local size = round(30 + math.min(display.width, display.height) / 10)
local opacity = (Elements.menu and Elements.menu:is_alive()) and 0.3 or 0.8
ass:spinner(display.width / 2, display.height / 2, size, {color = fg, opacity = opacity})
return ass
end
return BufferingIndicator

View file

@ -1,95 +0,0 @@
local Element = require('elements/Element')
---@alias ButtonProps {icon: string; on_click: function; anchor_id?: string; active?: boolean; badge?: string|number; foreground?: string; background?: string; tooltip?: string}
---@class Button : Element
local Button = class(Element)
---@param id string
---@param props ButtonProps
function Button:new(id, props) return Class.new(self, id, props) --[[@as Button]] end
---@param id string
---@param props ButtonProps
function Button:init(id, props)
self.icon = props.icon
self.active = props.active
self.tooltip = props.tooltip
self.badge = props.badge
self.foreground = props.foreground or fg
self.background = props.background or bg
---@type fun()
self.on_click = props.on_click
Element.init(self, id, props)
end
function Button:on_coordinates() self.font_size = round((self.by - self.ay) * 0.7) end
function Button:handle_cursor_click()
-- We delay the callback to next tick, otherwise we are risking race
-- conditions as we are in the middle of event dispatching.
-- For example, handler might add a menu to the end of the element stack, and that
-- than picks up this click event we are in right now, and instantly closes itself.
mp.add_timeout(0.01, self.on_click)
end
function Button:render()
local visibility = self:get_visibility()
if visibility <= 0 then return end
cursor:zone('primary_click', self, function() self:handle_cursor_click() end)
local ass = assdraw.ass_new()
local is_hover = self.proximity_raw == 0
local is_hover_or_active = is_hover or self.active
local foreground = self.active and self.background or self.foreground
local background = self.active and self.foreground or self.background
-- Background
if is_hover_or_active or config.opacity.controls > 0 then
ass:rect(self.ax, self.ay, self.bx, self.by, {
color = (self.active or not is_hover) and background or foreground,
radius = state.radius,
opacity = visibility * (self.active and 1 or (is_hover and 0.3 or config.opacity.controls)),
})
end
-- Tooltip on hover
if is_hover and self.tooltip then ass:tooltip(self, self.tooltip) end
-- Badge
local icon_clip
if self.badge then
local badge_font_size = self.font_size * 0.6
local badge_opts = {size = badge_font_size, color = background, opacity = visibility}
local badge_width = text_width(self.badge, badge_opts)
local width, height = math.ceil(badge_width + (badge_font_size / 7) * 2), math.ceil(badge_font_size * 0.93)
local bx, by = self.bx - 1, self.by - 1
ass:rect(bx - width, by - height, bx, by, {
color = foreground,
radius = state.radius,
opacity = visibility,
border = self.active and 0 or 1,
border_color = background,
})
ass:txt(bx - width / 2, by - height / 2, 5, self.badge, badge_opts)
local clip_border = math.max(self.font_size / 20, 1)
local clip_path = assdraw.ass_new()
clip_path:round_rect_cw(
math.floor((bx - width) - clip_border), math.floor((by - height) - clip_border), bx, by, 3
)
icon_clip = '\\iclip(' .. clip_path.scale .. ', ' .. clip_path.text .. ')'
end
-- Icon
local x, y = round(self.ax + (self.bx - self.ax) / 2), round(self.ay + (self.by - self.ay) / 2)
ass:icon(x, y, self.font_size, self.icon, {
color = foreground,
border = self.active and 0 or options.text_border * state.scale,
border_color = background,
opacity = visibility,
clip = icon_clip,
})
return ass
end
return Button

View file

@ -1,374 +0,0 @@
local Element = require('elements/Element')
local Button = require('elements/Button')
local CycleButton = require('elements/CycleButton')
local Speed = require('elements/Speed')
-- sizing:
-- static - shrink, have highest claim on available space, disappear when there's not enough of it
-- dynamic - shrink to make room for static elements until they reach their ratio_min, then disappear
-- gap - shrink if there's no space left
-- space - expands to fill available space, shrinks as needed
-- scale - `options.controls_size` scale factor.
-- ratio - Width/height ratio of a static or dynamic element.
-- ratio_min Min ratio for 'dynamic' sized element.
---@alias ControlItem {element?: Element; kind: string; sizing: 'space' | 'static' | 'dynamic' | 'gap'; scale: number; ratio?: number; ratio_min?: number; hide: boolean; dispositions?: table<string, boolean>}
---@class Controls : Element
local Controls = class(Element)
function Controls:new() return Class.new(self) --[[@as Controls]] end
function Controls:init()
Element.init(self, 'controls', {render_order = 6})
---@type ControlItem[] All control elements serialized from `options.controls`.
self.controls = {}
---@type ControlItem[] Only controls that match current dispositions.
self.layout = {}
self:init_options()
end
function Controls:destroy()
self:destroy_elements()
Element.destroy(self)
end
function Controls:init_options()
-- Serialize control elements
local shorthands = {
['play-pause'] = 'cycle:pause:pause:no/yes=play_arrow?' .. t('Play/Pause'),
menu = 'command:menu:script-binding uosc/menu-blurred?' .. t('Menu'),
subtitles = 'command:subtitles:script-binding uosc/subtitles#sub>0?' .. t('Subtitles'),
audio = 'command:graphic_eq:script-binding uosc/audio#audio>1?' .. t('Audio'),
['audio-device'] = 'command:speaker:script-binding uosc/audio-device?' .. t('Audio device'),
video = 'command:theaters:script-binding uosc/video#video>1?' .. t('Video'),
playlist = 'command:list_alt:script-binding uosc/playlist?' .. t('Playlist'),
chapters = 'command:bookmark:script-binding uosc/chapters#chapters>0?' .. t('Chapters'),
['editions'] = 'command:bookmarks:script-binding uosc/editions#editions>1?' .. t('Editions'),
['stream-quality'] = 'command:high_quality:script-binding uosc/stream-quality?' .. t('Stream quality'),
['open-file'] = 'command:file_open:script-binding uosc/open-file?' .. t('Open file'),
['items'] = 'command:list_alt:script-binding uosc/items?' .. t('Playlist/Files'),
prev = 'command:arrow_back_ios:script-binding uosc/prev?' .. t('Previous'),
next = 'command:arrow_forward_ios:script-binding uosc/next?' .. t('Next'),
first = 'command:first_page:script-binding uosc/first?' .. t('First'),
last = 'command:last_page:script-binding uosc/last?' .. t('Last'),
['loop-playlist'] = 'cycle:repeat:loop-playlist:no/inf!?' .. t('Loop playlist'),
['loop-file'] = 'cycle:repeat_one:loop-file:no/inf!?' .. t('Loop file'),
shuffle = 'toggle:shuffle:shuffle?' .. t('Shuffle'),
fullscreen = 'cycle:crop_free:fullscreen:no/yes=fullscreen_exit!?' .. t('Fullscreen'),
}
-- Parse out disposition/config pairs
local items = {}
local in_disposition = false
local current_item = nil
for c in options.controls:gmatch('.') do
if not current_item then current_item = {disposition = '', config = ''} end
if c == '<' and #current_item.config == 0 then
in_disposition = true
elseif c == '>' and #current_item.config == 0 then
in_disposition = false
elseif c == ',' and not in_disposition then
items[#items + 1] = current_item
current_item = nil
else
local prop = in_disposition and 'disposition' or 'config'
current_item[prop] = current_item[prop] .. c
end
end
items[#items + 1] = current_item
-- Create controls
self.controls = {}
for i, item in ipairs(items) do
local config = shorthands[item.config] and shorthands[item.config] or item.config
local config_tooltip = split(config, ' *%? *')
local tooltip = config_tooltip[2]
config = shorthands[config_tooltip[1]]
and split(shorthands[config_tooltip[1]], ' *%? *')[1] or config_tooltip[1]
local config_badge = split(config, ' *# *')
config = config_badge[1]
local badge = config_badge[2]
local parts = split(config, ' *: *')
local kind, params = parts[1], itable_slice(parts, 2)
-- Serialize dispositions
local dispositions = {}
for _, definition in ipairs(comma_split(item.disposition)) do
if #definition > 0 then
local value = definition:sub(1, 1) ~= '!'
local name = not value and definition:sub(2) or definition
local prop = name:sub(1, 4) == 'has_' and name or 'is_' .. name
dispositions[prop] = value
end
end
-- Convert toggles into cycles
if kind == 'toggle' then
kind = 'cycle'
params[#params + 1] = 'no/yes!'
end
-- Create a control element
local control = {dispositions = dispositions, kind = kind}
if kind == 'space' then
control.sizing = 'space'
elseif kind == 'gap' then
table_assign(control, {sizing = 'gap', scale = 1, ratio = params[1] or 0.3, ratio_min = 0})
elseif kind == 'command' then
if #params ~= 2 then
mp.error(string.format(
'command button needs 2 parameters, %d received: %s', #params, table.concat(params, '/')
))
else
local element = Button:new('control_' .. i, {
render_order = self.render_order,
icon = params[1],
anchor_id = 'controls',
on_click = function() mp.command(params[2]) end,
tooltip = tooltip,
count_prop = 'sub',
})
table_assign(control, {element = element, sizing = 'static', scale = 1, ratio = 1})
if badge then self:register_badge_updater(badge, element) end
end
elseif kind == 'cycle' then
if #params ~= 3 then
mp.error(string.format(
'cycle button needs 3 parameters, %d received: %s',
#params, table.concat(params, '/')
))
else
local state_configs = split(params[3], ' */ *')
local states = {}
for _, state_config in ipairs(state_configs) do
local active = false
if state_config:sub(-1) == '!' then
active = true
state_config = state_config:sub(1, -2)
end
local state_params = split(state_config, ' *= *')
local value, icon = state_params[1], state_params[2] or params[1]
states[#states + 1] = {value = value, icon = icon, active = active}
end
local element = CycleButton:new('control_' .. i, {
render_order = self.render_order,
prop = params[2],
anchor_id = 'controls',
states = states,
tooltip = tooltip,
})
table_assign(control, {element = element, sizing = 'static', scale = 1, ratio = 1})
if badge then self:register_badge_updater(badge, element) end
end
elseif kind == 'speed' then
if not Elements.speed then
local element = Speed:new({anchor_id = 'controls', render_order = self.render_order})
local scale = tonumber(params[1]) or 1.3
table_assign(control, {
element = element, sizing = 'dynamic', scale = scale, ratio = 3.5, ratio_min = 2,
})
else
msg.error('there can only be 1 speed slider')
end
else
msg.error('unknown element kind "' .. kind .. '"')
break
end
self.controls[#self.controls + 1] = control
end
self:reflow()
end
function Controls:reflow()
-- Populate the layout only with items that match current disposition
self.layout = {}
for _, control in ipairs(self.controls) do
local matches = true
for prop, value in pairs(control.dispositions) do
if state[prop] ~= value then
matches = false
break
end
end
if control.element then control.element.enabled = matches end
if matches then self.layout[#self.layout + 1] = control end
end
self:update_dimensions()
Elements:trigger('controls_reflow')
end
---@param badge string
---@param element Element An element that supports `badge` property.
function Controls:register_badge_updater(badge, element)
local prop_and_limit = split(badge, ' *> *')
local prop, limit = prop_and_limit[1], tonumber(prop_and_limit[2] or -1)
local observable_name, serializer, is_external_prop = prop, nil, false
if itable_index_of({'sub', 'audio', 'video'}, prop) then
observable_name = 'track-list'
serializer = function(value)
local count = 0
for _, track in ipairs(value) do if track.type == prop then count = count + 1 end end
return count
end
else
local parts = split(prop, '@')
-- Support both new `prop@owner` and old `@prop` syntaxes
if #parts > 1 then prop, is_external_prop = parts[1] ~= '' and parts[1] or parts[2], true end
serializer = function(value) return value and (type(value) == 'table' and #value or tostring(value)) or nil end
end
local function handler(_, value)
local new_value = serializer(value) --[[@as nil|string|integer]]
local value_number = tonumber(new_value)
if value_number then new_value = value_number > limit and value_number or nil end
element.badge = new_value
request_render()
end
if is_external_prop then
element['on_external_prop_' .. prop] = function(_, value) handler(prop, value) end
else
self:observe_mp_property(observable_name, handler)
end
end
function Controls:get_visibility()
return Elements:v('speed', 'dragging') and 1 or Elements:maybe('timeline', 'get_is_hovered')
and -1 or Element.get_visibility(self)
end
function Controls:update_dimensions()
local window_border = Elements:v('window_border', 'size', 0)
local size = round(options.controls_size * state.scale)
local spacing = round(options.controls_spacing * state.scale)
local margin = round(options.controls_margin * state.scale)
-- Disable when not enough space
local available_space = display.height - window_border * 2 - Elements:v('top_bar', 'size', 0)
- Elements:v('timeline', 'size', 0)
self.enabled = available_space > size + 10
-- Reset hide/enabled flags
for c, control in ipairs(self.layout) do
control.hide = false
if control.element then control.element.enabled = self.enabled end
end
if not self.enabled then return end
-- Container
self.bx = display.width - window_border - margin
self.by = Elements:v('timeline', 'ay', display.height - window_border) - margin
self.ax, self.ay = window_border + margin, self.by - size
-- Controls
local available_width, statics_width = self.bx - self.ax, 0
local min_content_width = statics_width
local max_dynamics_width, dynamic_units, spaces, gaps = 0, 0, 0, 0
-- Calculate statics_width, min_content_width, and count spaces & gaps
for c, control in ipairs(self.layout) do
if control.sizing == 'space' then
spaces = spaces + 1
elseif control.sizing == 'gap' then
gaps = gaps + control.scale * control.ratio
elseif control.sizing == 'static' then
local width = size * control.scale * control.ratio + (c ~= #self.layout and spacing or 0)
statics_width = statics_width + width
min_content_width = min_content_width + width
elseif control.sizing == 'dynamic' then
local spacing = (c ~= #self.layout and spacing or 0)
statics_width = statics_width + spacing
min_content_width = min_content_width + size * control.scale * control.ratio_min + spacing
max_dynamics_width = max_dynamics_width + size * control.scale * control.ratio
dynamic_units = dynamic_units + control.scale * control.ratio
end
end
-- Hide & disable elements in the middle until we fit into available width
if min_content_width > available_width then
local i = math.ceil(#self.layout / 2 + 0.1)
for a = 0, #self.layout - 1, 1 do
i = i + (a * (a % 2 == 0 and 1 or -1))
local control = self.layout[i]
if control.sizing ~= 'gap' and control.sizing ~= 'space' then
control.hide = true
if control.element then control.element.enabled = false end
if control.sizing == 'static' then
local width = size * control.scale * control.ratio
min_content_width = min_content_width - width - spacing
statics_width = statics_width - width - spacing
elseif control.sizing == 'dynamic' then
statics_width = statics_width - spacing
min_content_width = min_content_width - size * control.scale * control.ratio_min - spacing
max_dynamics_width = max_dynamics_width - size * control.scale * control.ratio
dynamic_units = dynamic_units - control.scale * control.ratio
end
if min_content_width < available_width then break end
end
end
end
-- Lay out the elements
local current_x = self.ax
local width_for_dynamics = available_width - statics_width
local empty_space_width = width_for_dynamics - max_dynamics_width
local width_for_gaps = math.min(empty_space_width, size * gaps)
local individual_space_width = spaces > 0 and ((empty_space_width - width_for_gaps) / spaces) or 0
for c, control in ipairs(self.layout) do
if not control.hide then
local sizing, element, scale, ratio = control.sizing, control.element, control.scale, control.ratio
local width, height = 0, 0
if sizing == 'space' then
if individual_space_width > 0 then width = individual_space_width end
elseif sizing == 'gap' then
if width_for_gaps > 0 then width = width_for_gaps * (ratio / gaps) end
elseif sizing == 'static' then
height = size * scale
width = height * ratio
elseif sizing == 'dynamic' then
height = size * scale
width = max_dynamics_width < width_for_dynamics
and height * ratio or width_for_dynamics * ((scale * ratio) / dynamic_units)
end
local bx = current_x + width
if element then element:set_coordinates(round(current_x), round(self.by - height), bx, self.by) end
current_x = element and bx + spacing or bx
end
end
Elements:update_proximities()
request_render()
end
function Controls:on_dispositions() self:reflow() end
function Controls:on_display() self:update_dimensions() end
function Controls:on_prop_border() self:update_dimensions() end
function Controls:on_prop_title_bar() self:update_dimensions() end
function Controls:on_prop_fullormaxed() self:update_dimensions() end
function Controls:on_timeline_enabled() self:update_dimensions() end
function Controls:destroy_elements()
for _, control in ipairs(self.controls) do
if control.element then control.element:destroy() end
end
end
function Controls:on_options()
self:destroy_elements()
self:init_options()
end
return Controls

View file

@ -1,35 +0,0 @@
local Element = require('elements/Element')
---@class Curtain : Element
local Curtain = class(Element)
function Curtain:new() return Class.new(self) --[[@as Curtain]] end
function Curtain:init()
Element.init(self, 'curtain', {render_order = 999})
self.opacity = 0
---@type string[]
self.dependents = {}
end
---@param id string
function Curtain:register(id)
self.dependents[#self.dependents + 1] = id
if #self.dependents == 1 then self:tween_property('opacity', self.opacity, 1) end
end
---@param id string
function Curtain:unregister(id)
self.dependents = itable_filter(self.dependents, function(item) return item ~= id end)
if #self.dependents == 0 then self:tween_property('opacity', self.opacity, 0) end
end
function Curtain:render()
if self.opacity == 0 or config.opacity.curtain == 0 then return end
local ass = assdraw.ass_new()
ass:rect(0, 0, display.width, display.height, {
color = config.color.curtain, opacity = config.opacity.curtain * self.opacity,
})
return ass
end
return Curtain

View file

@ -1,59 +0,0 @@
local Button = require('elements/Button')
---@alias CycleState {value: any; icon: string; active?: boolean}
---@alias CycleButtonProps {prop: string; states: CycleState[]; anchor_id?: string; tooltip?: string}
---@class CycleButton : Button
local CycleButton = class(Button)
---@param id string
---@param props CycleButtonProps
function CycleButton:new(id, props) return Class.new(self, id, props) --[[@as CycleButton]] end
---@param id string
---@param props CycleButtonProps
function CycleButton:init(id, props)
local is_state_prop = itable_index_of({'shuffle'}, props.prop)
self.prop = props.prop
self.states = props.states
Button.init(self, id, props)
self.icon = self.states[1].icon
self.active = self.states[1].active
self.current_state_index = 1
self.on_click = function()
local new_state = self.states[self.current_state_index + 1] or self.states[1]
local new_value = new_state.value
if self.owner then
mp.commandv('script-message-to', self.owner, 'set', self.prop, new_value)
elseif is_state_prop then
if itable_index_of({'yes', 'no'}, new_value) then new_value = new_value == 'yes' end
set_state(self.prop, new_value)
else
mp.set_property(self.prop, new_value)
end
end
local function handle_change(name, value)
value = type(value) == 'boolean' and (value and 'yes' or 'no') or tostring(value or '')
local index = itable_find(self.states, function(state) return state.value == value end)
self.current_state_index = index or 1
self.icon = self.states[self.current_state_index].icon
self.active = self.states[self.current_state_index].active
request_render()
end
local prop_parts = split(self.prop, '@')
if #prop_parts == 2 then -- External prop with a script owner
self.prop, self.owner = prop_parts[1], prop_parts[2]
self['on_external_prop_' .. self.prop] = function(_, value) handle_change(self.prop, value) end
handle_change(self.prop, external[self.prop])
elseif is_state_prop then -- uosc's state props
self['on_prop_' .. self.prop] = function(self, value) handle_change(self.prop, value) end
handle_change(self.prop, state[self.prop])
else
self:observe_mp_property(self.prop, 'string', handle_change)
end
end
return CycleButton

View file

@ -1,194 +0,0 @@
---@alias ElementProps {enabled?: boolean; render_order?: number; ax?: number; ay?: number; bx?: number; by?: number; ignores_curtain?: boolean; anchor_id?: string;}
-- Base class all elements inherit from.
---@class Element : Class
local Element = class()
---@param id string
---@param props? ElementProps
function Element:init(id, props)
self.id = id
self.render_order = 1
-- `false` means element won't be rendered, or receive events
self.enabled = true
-- Element coordinates
self.ax, self.ay, self.bx, self.by = 0, 0, 0, 0
-- Relative proximity from `0` - mouse outside `proximity_max` range, to `1` - mouse within `proximity_min` range.
self.proximity = 0
-- Raw proximity in pixels.
self.proximity_raw = math.huge
---@type number `0-1` factor to force min visibility. Used for toggling element's permanent visibility.
self.min_visibility = 0
---@type number `0-1` factor to force a visibility value. Used for flashing, fading out, and other animations
self.forced_visibility = nil
---@type boolean Show this element even when curtain is visible.
self.ignores_curtain = false
---@type nil|string ID of an element from which this one should inherit visibility.
self.anchor_id = nil
---@type fun()[] Disposer functions called when element is destroyed.
self._disposers = {}
if props then table_assign(self, props) end
-- Flash timer
self._flash_out_timer = mp.add_timeout(options.flash_duration / 1000, function()
local function getTo() return self.proximity end
local function onTweenEnd() self.forced_visibility = nil end
if self.enabled then
self:tween_property('forced_visibility', 1, getTo, onTweenEnd)
else
onTweenEnd()
end
end)
self._flash_out_timer:kill()
Elements:add(self)
end
function Element:destroy()
for _, disposer in ipairs(self._disposers) do disposer() end
self.destroyed = true
Elements:remove(self)
end
function Element:reset_proximity() self.proximity, self.proximity_raw = 0, math.huge end
---@param ax number
---@param ay number
---@param bx number
---@param by number
function Element:set_coordinates(ax, ay, bx, by)
self.ax, self.ay, self.bx, self.by = ax, ay, bx, by
Elements:update_proximities()
self:maybe('on_coordinates')
end
function Element:update_proximity()
if cursor.hidden then
self:reset_proximity()
else
local range = options.proximity_out - options.proximity_in
self.proximity_raw = get_point_to_rectangle_proximity(cursor, self)
self.proximity = 1 - (clamp(0, self.proximity_raw - options.proximity_in, range) / range)
end
end
function Element:is_persistent()
local persist = config[self.id .. '_persistency']
return persist and (
(persist.audio and state.is_audio)
or (
persist.paused and state.pause
and (not Elements.timeline or not Elements.timeline.pressed or Elements.timeline.pressed.pause)
)
or (persist.video and state.is_video)
or (persist.image and state.is_image)
or (persist.idle and state.is_idle)
or (persist.windowed and not state.fullormaxed)
or (persist.fullscreen and state.fullormaxed)
)
end
-- Decide elements visibility based on proximity and various other factors
function Element:get_visibility()
-- Hide when curtain is visible, unless this elements ignores it
local min_order = (Elements.curtain.opacity > 0 and not self.ignores_curtain) and Elements.curtain.render_order or 0
if self.render_order < min_order then return 0 end
-- Persistency
if self:is_persistent() then return 1 end
-- Forced visibility
if self.forced_visibility then return math.max(self.forced_visibility, self.min_visibility) end
-- Anchor inheritance
-- If anchor returns -1, it means all attached elements should force hide.
local anchor = self.anchor_id and Elements[self.anchor_id]
local anchor_visibility = anchor and anchor:get_visibility() or 0
return anchor_visibility == -1 and 0 or math.max(self.proximity, anchor_visibility, self.min_visibility)
end
-- Call method if it exists
function Element:maybe(name, ...)
if self[name] then return self[name](self, ...) end
end
-- Attach a tweening animation to this element
---@param from number
---@param to number|fun():number
---@param setter fun(value: number)
---@param duration_or_callback? number|fun() Duration in milliseconds or a callback function.
---@param callback? fun() Called either on animation end, or when animation is killed.
function Element:tween(from, to, setter, duration_or_callback, callback)
self:tween_stop()
self._kill_tween = self.enabled and tween(
from, to, setter, duration_or_callback,
function()
self._kill_tween = nil
if callback then callback() end
end
)
end
function Element:is_tweening() return self and self._kill_tween end
function Element:tween_stop() self:maybe('_kill_tween') end
-- Animate an element property between 2 values.
---@param prop string
---@param from number
---@param to number|fun():number
---@param duration_or_callback? number|fun() Duration in milliseconds or a callback function.
---@param callback? fun() Called either on animation end, or when animation is killed.
function Element:tween_property(prop, from, to, duration_or_callback, callback)
self:tween(from, to, function(value) self[prop] = value end, duration_or_callback, callback)
end
---@param name string
function Element:trigger(name, ...)
local result = self:maybe('on_' .. name, ...)
request_render()
return result
end
-- Briefly flashes the element for `options.flash_duration` milliseconds.
-- Useful to visualize changes of volume and timeline when changed via hotkeys.
function Element:flash()
if self.enabled and options.flash_duration > 0 and (self.proximity < 1 or self._flash_out_timer:is_enabled()) then
self:tween_stop()
self.forced_visibility = 1
request_render()
self._flash_out_timer.timeout = options.flash_duration / 1000
self._flash_out_timer:kill()
self._flash_out_timer:resume()
end
end
-- Register disposer to be called when element is destroyed.
---@param disposer fun()
function Element:register_disposer(disposer)
if not itable_index_of(self._disposers, disposer) then
self._disposers[#self._disposers + 1] = disposer
end
end
-- Automatically registers disposer for the passed callback.
---@param event string
---@param callback fun()
function Element:register_mp_event(event, callback)
mp.register_event(event, callback)
self:register_disposer(function() mp.unregister_event(callback) end)
end
-- Automatically registers disposer for the observer.
---@param name string
---@param type_or_callback string|fun(name: string, value: any)
---@param callback_maybe nil|fun(name: string, value: any)
function Element:observe_mp_property(name, type_or_callback, callback_maybe)
local callback = type(type_or_callback) == 'function' and type_or_callback or callback_maybe
local prop_type = type(type_or_callback) == 'string' and type_or_callback or 'native'
mp.observe_property(name, prop_type, callback)
self:register_disposer(function() mp.unobserve_property(callback) end)
end
return Element

View file

@ -1,152 +0,0 @@
local Elements = {_all = {}}
---@param element Element
function Elements:add(element)
if not element.id then
msg.error('attempt to add element without "id" property')
return
end
if self:has(element.id) then Elements:remove(element.id) end
self._all[#self._all + 1] = element
self[element.id] = element
-- Sort by render order
table.sort(self._all, function(a, b) return a.render_order < b.render_order end)
request_render()
end
function Elements:remove(idOrElement)
if not idOrElement then return end
local id = type(idOrElement) == 'table' and idOrElement.id or idOrElement
local element = Elements[id]
if element then
if not element.destroyed then element:destroy() end
element.enabled = false
self._all = itable_delete_value(self._all, self[id])
self[id] = nil
request_render()
end
end
function Elements:update_proximities()
local curtain_render_order = Elements.curtain.opacity > 0 and Elements.curtain.render_order or 0
local mouse_leave_elements = {}
local mouse_enter_elements = {}
-- Calculates proximities for all elements
for _, element in self:ipairs() do
if element.enabled then
local previous_proximity_raw = element.proximity_raw
-- If curtain is open, we disable all elements set to rendered below it
if not element.ignores_curtain and element.render_order < curtain_render_order then
element:reset_proximity()
else
element:update_proximity()
end
if element.proximity_raw == 0 then
-- Mouse entered element area
if previous_proximity_raw ~= 0 then
mouse_enter_elements[#mouse_enter_elements + 1] = element
end
else
-- Mouse left element area
if previous_proximity_raw == 0 then
mouse_leave_elements[#mouse_leave_elements + 1] = element
end
end
end
end
-- Trigger `mouse_leave` and `mouse_enter` events
for _, element in ipairs(mouse_leave_elements) do element:trigger('mouse_leave') end
for _, element in ipairs(mouse_enter_elements) do element:trigger('mouse_enter') end
end
-- Toggles passed elements' min visibilities between 0 and 1.
---@param ids string[] IDs of elements to peek.
function Elements:toggle(ids)
local has_invisible = itable_find(ids, function(id)
return Elements[id] and Elements[id].enabled and Elements[id]:get_visibility() ~= 1
end)
self:set_min_visibility(has_invisible and 1 or 0, ids)
-- Reset proximities when toggling off. Has to happen after `set_min_visibility`,
-- as that is using proximity as a tween starting point.
if not has_invisible then
for _, id in ipairs(ids) do
if Elements[id] then Elements[id]:reset_proximity() end
end
end
end
-- Set (animate) elements' min visibilities to passed value.
---@param visibility number 0-1 floating point.
---@param ids string[] IDs of elements to peek.
function Elements:set_min_visibility(visibility, ids)
for _, id in ipairs(ids) do
local element = Elements[id]
if element then
local from = math.max(0, element:get_visibility())
element:tween_property('min_visibility', from, visibility)
end
end
end
-- Flash passed elements.
---@param ids string[] IDs of elements to peek.
function Elements:flash(ids)
local elements = itable_filter(self._all, function(element) return itable_has(ids, element.id) end)
for _, element in ipairs(elements) do element:flash() end
-- Special case for 'progress' since it's a state of timeline, not an element
if itable_has(ids, 'progress') and not itable_has(ids, 'timeline') then
Elements:maybe('timeline', 'flash_progress')
end
end
---@param name string Event name.
function Elements:trigger(name, ...)
for _, element in self:ipairs() do element:trigger(name, ...) end
end
-- Trigger two events, `name` and `global_name`, depending on element-cursor proximity.
-- Disabled elements don't receive these events.
---@param name string Event name.
function Elements:proximity_trigger(name, ...)
for i = #self._all, 1, -1 do
local element = self._all[i]
if element.enabled then
if element.proximity_raw == 0 then
if element:trigger(name, ...) == 'stop_propagation' then break end
end
if element:trigger('global_' .. name, ...) == 'stop_propagation' then break end
end
end
end
-- Returns a property of an element with a passed `id` if it exists, with an optional fallback.
---@param id string
---@param prop string
---@param fallback any
function Elements:v(id, prop, fallback)
if self[id] and self[id].enabled and self[id][prop] ~= nil then return self[id][prop] end
return fallback
end
-- Calls a method on an element with passed `id` if it exists.
---@param id string
---@param method string
function Elements:maybe(id, method, ...)
if self[id] then return self[id]:maybe(method, ...) end
end
function Elements:has(id) return self[id] ~= nil end
function Elements:ipairs() return ipairs(self._all) end
return Elements

Some files were not shown because too many files have changed in this diff Show more