From f39d735e2ba625a31a7dbf6fb8bdd62501379ad1 Mon Sep 17 00:00:00 2001 From: zachir Date: Wed, 5 Oct 2022 22:00:32 -0500 Subject: Initial Commit --- .gitignore | 185 ++ .gitmodules | 12 + Makefile | 50 + README.md | 14 + X11/Xresources | 492 ++++ X11/xinitrc | 4 + X11/xprofile | 7 + alacritty/alacritty.yml | 850 ++++++ autostart.sh | 50 + awesome | 1 + bspwm/bspwmrc | 66 + bspwm/noswallow | 1 + bspwm/terminals | 3 + caffeine/audio_blacklist.txt | 0 caffeine/whitelist.txt | 0 computerrc.txt | 10 + cool-retro-term/cool-retro-term.conf | 7 + deadbeef/config | 79 + deadbeef/dspconfig | 0 deadbeef/playlists/0.dbpl | Bin 0 -> 7050 bytes deadbeef/playlists/1.dbpl | Bin 0 -> 6814 bytes deadbeef/playlists/2.dbpl | Bin 0 -> 8914 bytes doas.conf | 19 + doom/config.el | 54 + doom/init.el | 183 ++ doom/packages.el | 50 + dunst/dunstrc | 418 +++ dwm/autostart.sh | 3 + dwm/autostart_blocking.sh | 2 + ff_enterprise_policy.zip | Bin 0 -> 2479 bytes firejail/disable-exec.local | 1 + firejail/dolphin-emu.local | 4 + firejail/librewolf.local | 4 + firejail/lynx.local | 3 + firejail/mpv.local | 3 + firejail/neomutt.local | 24 + firejail/nextcloud.local | 4 + firejail/qutebrowser.local | 4 + firejail/steam.local | 2 + ghostwriter/ghostwriter.conf | 68 + gtk-2.0/gtkfilechooser.ini | 11 + gtk-2.0/gtkrc | 19 + gtk-3.0/gtk.css | 12 + gtk-3.0/settings.ini | 16 + herbstluftwm/README.md | 3 + herbstluftwm/autostart | 205 ++ herbstluftwm/spblue | 17 + herbstluftwm/sphtop | 18 + herbstluftwm/spirss | 18 + herbstluftwm/spmpv | 22 + herbstluftwm/spmutt | 18 + herbstluftwm/spncmp | 18 + herbstluftwm/sppmxr | 18 + herbstluftwm/spprof | 18 + herbstluftwm/spterm | 18 + installers/vimplug_nvim.sh | 4 + installers/vimplug_vim.sh | 4 + jellycli.yaml | 0 jellycli/jellycli.yaml | 38 + kshrc | 38 + lf/3q | 2 + lf/cleaner | 4 + lf/image | 18 + lf/lfrc | 351 +++ lf/preview | 83 + lxqt/lxqt.conf | 3 + mksh/mkshalias | 50 + mksh/mkshfunc | 58 + mksh/mkshrc | 684 +++++ modprobed-db.conf | 21 + mpd/mpd.conf | 401 +++ mpv/input.conf | 2 + mpv/mpv.conf | 5 + mpv/script-opts/quality-menu.conf | 95 + mpv/script-opts/youtube-download.conf | 48 + mpv/scripts/quality-menu-osc.lua | 2911 +++++++++++++++++++ mpv/scripts/quality-menu.lua | 806 ++++++ mpv/scripts/youtube-download.lua | 758 +++++ ncmpcpp/bindings | 543 ++++ ncmpcpp/config | 544 ++++ ncmpcpp/patterns.list | 0 newsboat/config | 55 + nvim/init.vim | 267 ++ nyxt/auto-config.lisp | 4 + open/openrc | 15 + paru/paru.conf | 37 + picom.conf | 93 + pipewire/pipewire.conf | 246 ++ pipewire/wireplumber.conf | 90 + polybar/config | 615 ++++ profanity/themes/redbox | 80 + psub/config.yaml | 74 + qt5ct/qt5ct.conf | 32 + qt6ct/qt6ct.conf | 38 + qtile/config.py | 539 ++++ qutebrowser/bookmarks/urls | 1 + qutebrowser/config.py | 275 ++ qutebrowser/jmatrix | 1 + qutebrowser/quickmarks | 1 + river/init | 167 ++ sh/aliases | 70 + sh/functions | 130 + snownews/colors | 21 + snownews/keybindings | 39 + spectrwm/spectrwm.conf | 145 + stalonetrayrc | 137 + stmp | 6 + swayidle/config | 2 + swhkd/swhkdrc | 158 + sx/sxrc | 1 + sxhkd/sxhkdrc | 170 ++ sxhkd/sxhkdrc.1 | 329 +++ sxhkd/sxhkdrc.bsp | 159 + sxiv/exec/key-handler | 11 + tmux/tmux.conf | 30 + tofi/config | 18 + trizen/trizen.conf | 57 + user-dirs.dirs | 15 + user-dirs.locale | 1 + vlc/vlcrc | 5120 +++++++++++++++++++++++++++++++++ waybar/config | 474 +++ waybar/style.css | 245 ++ waylock/waylock.toml | 4 + xmodmap | 26 + xplr/init.lua | 2443 ++++++++++++++++ xplr/plugins/dragon/LICENSE | 21 + xplr/plugins/dragon/README.md | 49 + xplr/plugins/dragon/src/init.lua | 62 + yay/config.json | 43 + ytfzf/conf.sh | 9 + zsh/.zlogout | 2 + zsh/.zprofile | 6 + zsh/.zshenv | 78 + zsh/.zshrc | 79 + 134 files changed, 23369 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Makefile create mode 100644 README.md create mode 100644 X11/Xresources create mode 100755 X11/xinitrc create mode 100755 X11/xprofile create mode 100644 alacritty/alacritty.yml create mode 100755 autostart.sh create mode 160000 awesome create mode 100755 bspwm/bspwmrc create mode 100644 bspwm/noswallow create mode 100644 bspwm/terminals create mode 100644 caffeine/audio_blacklist.txt create mode 100644 caffeine/whitelist.txt create mode 100644 computerrc.txt create mode 100644 cool-retro-term/cool-retro-term.conf create mode 100644 deadbeef/config create mode 100644 deadbeef/dspconfig create mode 100644 deadbeef/playlists/0.dbpl create mode 100644 deadbeef/playlists/1.dbpl create mode 100644 deadbeef/playlists/2.dbpl create mode 100644 doas.conf create mode 100644 doom/config.el create mode 100644 doom/init.el create mode 100644 doom/packages.el create mode 100644 dunst/dunstrc create mode 100755 dwm/autostart.sh create mode 100755 dwm/autostart_blocking.sh create mode 100644 ff_enterprise_policy.zip create mode 100644 firejail/disable-exec.local create mode 100644 firejail/dolphin-emu.local create mode 100644 firejail/librewolf.local create mode 100644 firejail/lynx.local create mode 100644 firejail/mpv.local create mode 100644 firejail/neomutt.local create mode 100644 firejail/nextcloud.local create mode 100644 firejail/qutebrowser.local create mode 100644 firejail/steam.local create mode 100644 ghostwriter/ghostwriter.conf create mode 100644 gtk-2.0/gtkfilechooser.ini create mode 100644 gtk-2.0/gtkrc create mode 100644 gtk-3.0/gtk.css create mode 100644 gtk-3.0/settings.ini create mode 100644 herbstluftwm/README.md create mode 100755 herbstluftwm/autostart create mode 100755 herbstluftwm/spblue create mode 100755 herbstluftwm/sphtop create mode 100755 herbstluftwm/spirss create mode 100755 herbstluftwm/spmpv create mode 100755 herbstluftwm/spmutt create mode 100755 herbstluftwm/spncmp create mode 100755 herbstluftwm/sppmxr create mode 100755 herbstluftwm/spprof create mode 100755 herbstluftwm/spterm create mode 100755 installers/vimplug_nvim.sh create mode 100755 installers/vimplug_vim.sh create mode 100644 jellycli.yaml create mode 100644 jellycli/jellycli.yaml create mode 100644 kshrc create mode 100755 lf/3q create mode 100755 lf/cleaner create mode 100755 lf/image create mode 100644 lf/lfrc create mode 100755 lf/preview create mode 100644 lxqt/lxqt.conf create mode 100644 mksh/mkshalias create mode 100644 mksh/mkshfunc create mode 100644 mksh/mkshrc create mode 100644 modprobed-db.conf create mode 100644 mpd/mpd.conf create mode 100644 mpv/input.conf create mode 100644 mpv/mpv.conf create mode 100644 mpv/script-opts/quality-menu.conf create mode 100644 mpv/script-opts/youtube-download.conf create mode 100644 mpv/scripts/quality-menu-osc.lua create mode 100644 mpv/scripts/quality-menu.lua create mode 100644 mpv/scripts/youtube-download.lua create mode 100644 ncmpcpp/bindings create mode 100644 ncmpcpp/config create mode 100644 ncmpcpp/patterns.list create mode 100644 newsboat/config create mode 100644 nvim/init.vim create mode 100644 nyxt/auto-config.lisp create mode 100644 open/openrc create mode 100644 paru/paru.conf create mode 100644 picom.conf create mode 100644 pipewire/pipewire.conf create mode 100644 pipewire/wireplumber.conf create mode 100644 polybar/config create mode 100644 profanity/themes/redbox create mode 100644 psub/config.yaml create mode 100644 qt5ct/qt5ct.conf create mode 100644 qt6ct/qt6ct.conf create mode 100644 qtile/config.py create mode 100644 qutebrowser/bookmarks/urls create mode 100644 qutebrowser/config.py create mode 160000 qutebrowser/jmatrix create mode 100644 qutebrowser/quickmarks create mode 100755 river/init create mode 100644 sh/aliases create mode 100644 sh/functions create mode 100644 snownews/colors create mode 100644 snownews/keybindings create mode 100644 spectrwm/spectrwm.conf create mode 100644 stalonetrayrc create mode 100644 stmp create mode 100644 swayidle/config create mode 100755 swhkd/swhkdrc create mode 100755 sx/sxrc create mode 100755 sxhkd/sxhkdrc create mode 100755 sxhkd/sxhkdrc.1 create mode 100755 sxhkd/sxhkdrc.bsp create mode 100755 sxiv/exec/key-handler create mode 100644 tmux/tmux.conf create mode 100644 tofi/config create mode 100644 trizen/trizen.conf create mode 100644 user-dirs.dirs create mode 100644 user-dirs.locale create mode 100644 vlc/vlcrc create mode 100644 waybar/config create mode 100644 waybar/style.css create mode 100644 waylock/waylock.toml create mode 100644 xmodmap create mode 100644 xplr/init.lua create mode 100644 xplr/plugins/dragon/LICENSE create mode 100644 xplr/plugins/dragon/README.md create mode 100644 xplr/plugins/dragon/src/init.lua create mode 100644 yay/config.json create mode 100644 ytfzf/conf.sh create mode 100644 zsh/.zlogout create mode 100644 zsh/.zprofile create mode 100644 zsh/.zshenv create mode 100644 zsh/.zshrc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0f02088 --- /dev/null +++ b/.gitignore @@ -0,0 +1,185 @@ +zsh/hist +zsh/zcompdump +zoomus.conf +zec-qt-wallet-org/ +ytfzf/subscriptions +yabridgectl/ +xmonad/.stack-work +xmonad/stack.yaml.lock +xmonad/xmonad-x86_64-linux +xmonad/xmonad.o +xmonad/xmonad.hi +weechat/ +vlc/vlc-qt-interface.conf +vdirsyncer/ +unity3d/ +ubports-installer/ +transmission-daemon/ +transmission/* +!transmission/settings.json +torbrowser/ +tmux/plugins +syncthing/ +switcher/ +straw-viewer/ +spotify-tui/ +spotifyd/ +snownews/urls.opml +sh/weather +rtorrent/ +rncbc.org/ +retroarch/ +rclone/ +qutebrowser/jmatrix-rules +qtile/__pycache__/ +!qt6ct/qt6ct.conf +qt6ct/* +!qt5ct/qt5ct.conf +qt5ct/* +pupgui/ +pulse/ +protonmail/ +protonfixes/ +profanity/profrc +print-manager/ +polychromatic/ +poezio/ +pmbootstrap.cfg +pipewire/media-session.d/ +PCSX2/ +pcmanfm/ +pavucontrol.ini +openrazer/ +okularrc +okularpartrc +nvim/plugged/ +nwg-outputs/ +nssdb/ +npm/ +notmuch/ +nitrogen/bg-saved.cfg +newsboat/urls +newsboat/cache.db +nextcloud/ +neofetch/ +ncmpcpp/error.log +mutt/ +musnify-mpd/musnify-mpd.config +msmtp/ +mpv/watch_later/ +mpv/download.log +mpd/database +mpd/log +mpd/pid +mpd/socket +mpd/state +mpd/sticker.sql +mpd/playlists/ +modprobed.db +monero-project/ +mimeapps.list +mksh/history +minigalaxy/ +micro/buffers/ +mgba/ +menus/ +lutris/ +lsp-plugins/ +lkjb/ +linvst/ +light/ +libreoffice/ +libfm/ +lbry/ +lab/ +ksh/history +kritarc +kritadisplayrc +kicad/ +keepassxc/ +kdenlive-layoutsrc +kdenlive-appimagerc +kdenliverc +kdeglobals +kdeconnect/ +kaidan/ +joplin/ +joplin-desktop/ +java/ +jack_mixer/ +jack/ +isync/ +irssi/ +inkscape/ +icedtea-web/ +htop/htoprc +guitarix/ +gtk-3.0/bookmarks +gtk-2.0/gtkfilechooser.ini +gomuks/ +ghb/ +gaiasky/ +fontconfig/ +falkTX/ +enchant/ +emacs/ +dolphin-emu/ +dde-printer.ini +dconf/ +cordless/config.json +configstore/ +computerrc +companion/ +coc/extensions/db.json +clangd/ +chromium/ +cef_user_data +calibre/conversion +calibre/ +blender/ +autostart/ +ardour6/ +amsynth/ +abook/ +VirtualBox/ +UNDERTALE*/ +The Crown EXEX.settings +SUPERHOT/ +Session/ +SchildiChat/ +RVXX v2/ +RVXX v2.settings +RVXX EXEX.settings +Resonant DSP/ +REAPER/ +ReAmp Studio R1.settings +ReAmp Studio R1/ +QtProject.conf +QtProject/ +Proton AG/ +Portmaster/ +NuGet/ +Nextcloud/ +LibrePCB/ +Kitware/ +Joplin/ +Iriun/ +GIMP/ +FreeTube/ +FreakQ305.settings +FreakQ305/ +Epic/ +Etherdyne/ +EmeraldWallet/ +Element/ +Cadence/ +BULLDOG.settings +BraveSoftware/ +Blacksun.settings +Blacksun/ +Binance/ +AHM 5050 v3.settings +AHM 5050 v3/ +@joplin/ +.tsrc +.charles.config diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4528b81 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule "emacs"] + path = emacs + url = https://github.com/hlissner/doom-emacs +[submodule "xplr/dragon.xplr"] + path = xplr/dragon.xplr + url = https://github.com/sayanarijit/dragon.xplr +[submodule "awesome"] + path = awesome + url = https://gitlab.com/zachir/awesome-config +[submodule "qutebrowser/jmatrix"] + path = qutebrowser/jmatrix + url = https://gitlab.com/jgkamat/jmatrix.git diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0de9447 --- /dev/null +++ b/Makefile @@ -0,0 +1,50 @@ +VIM := $(shell command -v vim 2>/dev/null) +NVIM := $(shell command -v nvim 2>/dev/null) +XCONFS := X11/xinitrc X11/xprofile X11/Xresources +ZCONFS := zsh/.zshenv +DCONFS := doas.conf + +all: + +install: install-xconfigs install-zshconfigs vimplug-vim vimplug-nvim doas-conf + +install-xconfigs: $(XCONFS) + @echo "Installing Xorg conf files..." + @echo "xinitrc..." + @ln -sf `pwd`/X11/xinitrc ~/.xinitrc + @echo "xprofile..." + @ln -sf `pwd`/X11/xprofile ~/.xprofile + @echo "Xresources..." + @ln -sf `pwd`/X11/Xresources ~/.Xresources + @echo "Done." + +install-zshconfigs: $(ZCONFS) + @echo "Installing zsh conf files..." + @echo ".zshenv..." + @ln -sf `pwd`/zsh/.zshenv ~/.zshenv + @echo "Done." + +vimplug-vim: installers/vimplug_vim.sh +ifdef VIM + @echo "Installing vim-plug for vim..." + @$(shell installers/vimplug_vim.sh) + @echo "Done." +else + @echo "vim not installed." +endif + +vimplug-nvim: installers/vimplug_nvim.sh +ifdef NVIM + @echo "Installing vim-plug for nvim..." + @$(shell installers/vimplug_nvim.sh) + @echo "Done." +else + @echo "nvim not installed." +endif + +doas-conf: $(DCONFS) + @echo "Installing doas config files..." + @echo "doas.conf..." + @$(foreach conf,$(DCONFS),\ + $(sudo cp $(conf) /etc/$(conf))) + @echo "Done." diff --git a/README.md b/README.md new file mode 100644 index 0000000..9acdf05 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +## Zachir's Config Files + +Hello! These are all the config files I thought could potentially be useful, both to myself to make reinstalling Linux faster, as well as for anyone interested. There are a few notes I feel I should make: + +- I have a custom dwm build, which sources 'autostart.sh' and 'autostart_blocking.sh' from __*.config/dwm*__ not *.dwm*. This is available [here](https://gitlab.com/zachir/dwm-zir). +- I also have a custom st build, which sources '.Xresources' (this is a common enough patch, but I thought I would mention it, as I include my .Xresources file) available [here](https://gitlab.com/zachir/st-zir). +- I have gone through everything to remove personal information, however I might have missed something. If that happens, this repo will be updated, and the branch history deleted. + +My personal installation method is as follows (performed immediately following a clean install): +`git clone https://gitlab.com/zachir/dotfiles ~/.config +cd ~/.config +make install` + +Note that the `make install` will only install the files in `HOME` to their corresponding place in the home dir as hard links. Make sure to save changes to these files before cloning! Additionally, if you only want my configs for specific programs, I would recommend cloning it into a separate directory and avoiding the `make install`. diff --git a/X11/Xresources b/X11/Xresources new file mode 100644 index 0000000..367f4d4 --- /dev/null +++ b/X11/Xresources @@ -0,0 +1,492 @@ +!! dmenu + +dmenu.font: mononoki Nerd Font Mono:size=12 + +!! dwm + +dwm.normbgcolor: #000000 +dwm.normbordercolor: #1b1d1c +dwm.normfgcolor: #ffffff +dwm.selbgcolor: #2783a1 +dwm.selbordercolor: #2783a1 +dwm.selfgcolor: #ffffff +dwm.urgfgcolor: #ffffff +dwm.urgbordercolor: #2783a1 +dwm.urgbgcolor: #cc342b +dwm.borderpx: 3 +dwm.gappx: 6 +dwm.snap: 32 +dwm.showbar: 1 +dwm.topbar: 1 +dwm.nmaster: 1 +dwm.resizehints: 1 +dwm.mfact: 0.50 + +!! st + +! These options only take effect on startup. +st.termname: st-256color +! if you do not set shell, precedence is: -e arg, utmp option, SHELL env var, /etc/passwd shell +st.shell: /usr/bin/tmux + +! The following options options can be reloaded via USR1 signal. +st.font: mononoki Nerd Font Mono:pixelsize=12:antialias=true:autohint=true; +st.font2: Symbola:pixelsize=11:antialias=true:autohint=true; +st.borderpx: 0 +! st alpha +st.alpha: 0.5 +! Available cursor values: 2 4 6 7 = █ _ | ☃ ( 1 3 5 are blinking versions) +st.cursorshape: 6 +! thickness of underline and bar cursors +st.cursorthickness: 2 +! 0: normal blinking, 1: leave cursor border and blink with cursor''s background +st.cursorblinkstyle: 0 +! 0: cursor blinks with a constant interval; 1: blinking cycle resets on key input +st.cursorblinkontype: 1 +! st.bold_font: 0 +st.xfps: 120 +st.actionfps: 60 +! Amount of lines scrolled +st.mouseScrollLines: 1 +! Kerning / character bounding-box height multiplier +st.chscale: 1.0 +! Kerning / character bounding-box width multiplier +st.cwscale: 1.0 +! blinking timeout for terminal and cursor blinking (0 disables) +st.blinktimeout: 800 +! bell volume. Value between -100 and 100. (0 disables) +st.bellvolume: 0 +! this is a char that is exposed like so: `printf '\033[z'` +st.prompt_char: $ +! This option is can be preedit style. Available values: `root` `overthespot` (Default taken `root`) +st.imstyle: root + +!! RXVT-Unicode (urxvt) config +! do not scroll with output +URxvt.scrollTtyOutput: false +! scroll in relation to buffer (with mouse scroll or Shift+Page Up) +URxvt.scrollWithBuffer: true +! scroll back to the bottom on keypress +URxvt.scrollTtyKeypress: true +! disable scrollback buffer for secondary screen +URxvt.secondaryScreen: 1 +URxvt.secondaryScroll: 0 +URxvt.secondaryWheel: 1 +! URxvt font +URxvt.font: xft:Fira Code:regular:size=8,xft:symbola:regular:size=9 +! fix font spacing +URxvt.letterSpace: -1 +! Disable printing +URxvt.print-pipe: "cat > /dev/null" +! disable iso14755 +URxvt.iso14755: false +URxvt.iso14755_52: false +! enable transparency +URxvt.depth: 32 +URxvt.background: rgba:0000/0000/0200/c800 +! disable scrollbar +URxvt.scrollBar: false + +!! perls +! perls +URxvt.perl-ext: default,url-select,tabbed,resize-font,clipboard +! clipboard +URxvt.clipboard.autocopy: true +URxvt.keysym.Shift-Control-C: perl:clipboard:copy +URxvt.keysym.Shift-Control-V: perl:clipboard:paste +! url-select +URxvt.keysum.M-u: perl:url-select:select-next +URxvt.url-select.launcher: /usr/bin/xdg-open +URxvt.url-select.underline: true +! tabbed +URxvt.tabbed.tabbar-fg: 2 +URxvt.tabbed.tabbar-bg: 0 +URxvt.tabbed.tab-fg: 3 +URxvt.tabbed.tab-bg: 0 +! resize-font +URxvt.keysym.C-Minus: resize-font:smaller +URxvt.keysym.C-Plus: resize-font:bigger + +! "Enabled modi" Set from: Default +rofi.modi: window,run,ssh,drun +! "Window width" Set from: Default +rofi.width: 1366 +! "Number of lines" Set from: Default +! rofi.lines: 15 +! "Number of columns" Set from: Default +! rofi.columns: 1 +! "Font to use" Set from: Default +rofi.font: mononoki 9 +! "Border width" Set from: Default +! rofi.bw: 1 +! "Location on screen" Set from: Default +rofi.location: 2 +! "Padding" Set from: Default +! rofi.padding: 5 +! "Y-offset relative to location" Set from: Default +! rofi.yoffset: 0 +! "X-offset relative to location" Set from: Default +! rofi.xoffset: 0 +! "Always show number of lines" Set from: Default +! rofi.fixed-num-lines: true +! "Whether to load and show icons" Set from: Default +! rofi.show-icons: false +! "Terminal to use" Set from: Default +! rofi.terminal: rofi-sensible-terminal +! "Ssh client to use" Set from: Default +! rofi.ssh-client: ssh +! "Ssh command to execute" Set from: Default +! rofi.ssh-command: {terminal} -e {ssh-client} {host} [-p {port}] +! "Run command to execute" Set from: Default +! rofi.run-command: {cmd} +! "Command to get extra run targets" Set from: Default +! rofi.run-list-command: +! "Run command to execute that runs in shell" Set from: Default +! rofi.run-shell-command: {terminal} -e {cmd} +! "Command to executed when -kb-accept-alt binding is hit on selected window " Set from: Default +! rofi.window-command: wmctrl -i -R {window} +! "Window fields to match in window mode" Set from: Default +! rofi.window-match-fields: all +! "Theme to use to look for icons" Set from: Default +! rofi.icon-theme: +! "Desktop entry fields to match in drun" Set from: Default +! rofi.drun-match-fields: name,generic,exec,categories,keywords +! "Only show Desktop entry from these categories" Set from: Default +! rofi.drun-categories: +! "Desktop entry show actions." Set from: Default +! rofi.drun-show-actions: false +! "DRUN format string. (Supports: generic,name,comment,exec,categories)" Set from: Default +! rofi.drun-display-format: {name} [({generic})] +! "Command to open an Desktop Entry that is a Link." Set from: Default +! rofi.drun-url-launcher: xdg-open +! "Disable history in run/ssh" Set from: Default +! rofi.disable-history: false +! "Programs ignored for history" Set from: Default +! rofi.ignored-prefixes: +! "Use sorting" Set from: Default +! rofi.sort: false +! "Choose the strategy used for sorting: normal (levenshtein) or fzf." Set from: Default +! rofi.sorting-method: normal +! "Set case-sensitivity" Set from: Default +! rofi.case-sensitive: false +! "Cycle through the results list" Set from: Default +! rofi.cycle: true +! "Enable sidebar-mode" Set from: Default +! rofi.sidebar-mode: false +! "Row height (in chars)" Set from: Default +! rofi.eh: 1 +! "Enable auto select mode" Set from: Default +! rofi.auto-select: false +! "Parse hosts file for ssh mode" Set from: Default +! rofi.parse-hosts: false +! "Parse known_hosts file for ssh mode" Set from: Default +! rofi.parse-known-hosts: true +! "Set the modi to combine in combi mode" Set from: Default +! rofi.combi-modi: window,run +! "Set the matching algorithm. (normal, regex, glob, fuzzy)" Set from: Default +! rofi.matching: normal +! "Tokenize input string" Set from: Default +! rofi.tokenize: true +! "Monitor id to show on" Set from: Default +! rofi.m: -5 +! "Margin between rows *DEPRECATED*" Set from: Default +! rofi.line-margin: 2 +! "Padding within rows *DEPRECATED*" Set from: Default +! rofi.line-padding: 1 +! "Pre-set filter" Set from: Default +! rofi.filter: +! "Separator style (none, dash, solid) *DEPRECATED*" Set from: Default +! rofi.separator-style: dash +! "Hide scroll-bar *DEPRECATED*" Set from: Default +! rofi.hide-scrollbar: false +! "Fullscreen" Set from: Default +! rofi.fullscreen: false +! "Fake transparency *DEPRECATED*" Set from: Default +! rofi.fake-transparency: false +! "DPI" Set from: Default +! rofi.dpi: -1 +! "Threads to use for string matching" Set from: Default +! rofi.threads: 0 +! "Scrollbar width *DEPRECATED*" Set from: Default +! rofi.scrollbar-width: 8 +! "Scrolling method. (0: Page, 1: Centered)" Set from: Default +! rofi.scroll-method: 0 +! "Background to use for fake transparency. (background or screenshot) *DEPRECATED*" Set from: Default +! rofi.fake-background: screenshot +! "Window Format. w (desktop name), t (title), n (name), r (role), c (class)" Set from: Default +! rofi.window-format: {w} {c} {t} +! "Click outside the window to exit" Set from: Default +! rofi.click-to-exit: true +! "Indicate how it match by underlining it." Set from: Default +! rofi.show-match: true +! "New style theme file" Set from: Default +! rofi.theme: +! "Color scheme for normal row" Set from: Default +! 'bg' 'fg' 'bgalt' 'hlbg' 'hlfg' +rofi.color-normal: #000000, #b4b7b5, #89231d, #cc342b, #000000 +! "Color scheme for urgent row" Set from: Default +! rofi.color-urgent: +! "Color scheme for active row" Set from: Default +! rofi.color-active: +! "Color scheme window" Set from: Default +! 'background' 'border' 'separator' +rofi.color-window: #1d1f21, #101010, #000000 +! "Max history size (WARNING: can cause slowdowns when set to high)." Set from: Default +! rofi.max-history-size: 25 +! "Hide the prefix mode prefix on the combi view." Set from: Default +! rofi.combi-hide-mode-prefix: false +! "Set the character used to negate the matching. ('\0' to disable)" Set from: Default +! rofi.matching-negate-char: - +! "Directory where history and temporary files are stored." Set from: Default +! rofi.cache-dir: +! "Show window thumbnail (if available) as icon in window switcher." Set from: Default +! rofi.window-thumbnail: false +! "DRUN: build and use a cache with desktop file content." Set from: Default +! rofi.drun-use-desktop-cache: false +! "DRUN: If enabled, reload the cache with desktop file content." Set from: Default +! rofi.drun-reload-desktop-cache: false +! "Normalize string when matching (implies -no-show-match)." Set from: Default +! rofi.normalize-match: false +! "Pidfile location" Set from: Default +! rofi.pid: /run/user/1000/rofi.pid +! "The display name of this browser" Set from: Default +! rofi.display-window: +! "The display name of this browser" Set from: Default +! rofi.display-windowcd: +! "The display name of this browser" Set from: Default +! rofi.display-run: +! "The display name of this browser" Set from: Default +! rofi.display-ssh: +! "The display name of this browser" Set from: Default +! rofi.display-drun: +! "The display name of this browser" Set from: Default +! rofi.display-combi: +! "The display name of this browser" Set from: Default +! rofi.display-keys: +! "The display name of this browser" Set from: Default +! rofi.display-file-browser: +! "Paste primary selection" Set from: Default +! rofi.kb-primary-paste: Control+V,Shift+Insert +! "Paste clipboard" Set from: Default +! rofi.kb-secondary-paste: Control+v,Insert +! "Clear input line" Set from: Default +! rofi.kb-clear-line: Control+w +! "Beginning of line" Set from: Default +! rofi.kb-move-front: Control+a +! "End of line" Set from: Default +! rofi.kb-move-end: Control+e +! "Move back one word" Set from: Default +! rofi.kb-move-word-back: Alt+b,Control+Left +! "Move forward one word" Set from: Default +! rofi.kb-move-word-forward: Alt+f,Control+Right +! "Move back one char" Set from: Default +! rofi.kb-move-char-back: Left,Control+b +! "Move forward one char" Set from: Default +! rofi.kb-move-char-forward: Right,Control+f +! "Delete previous word" Set from: Default +! rofi.kb-remove-word-back: Control+Alt+h,Control+BackSpace +! "Delete next word" Set from: Default +! rofi.kb-remove-word-forward: Control+Alt+d +! "Delete next char" Set from: Default +! rofi.kb-remove-char-forward: Delete,Control+d +! "Delete previous char" Set from: Default +! rofi.kb-remove-char-back: BackSpace,Shift+BackSpace,Control+h +! "Delete till the end of line" Set from: Default +! rofi.kb-remove-to-eol: Control+k +! "Delete till the start of line" Set from: Default +! rofi.kb-remove-to-sol: Control+u +! "Accept entry" Set from: Default +! rofi.kb-accept-entry: Control+j,Control+m,Return,KP_Enter +! "Use entered text as command (in ssh/run modi)" Set from: Default +! rofi.kb-accept-custom: Control+Return +! "Use alternate accept command." Set from: Default +! rofi.kb-accept-alt: Shift+Return +! "Delete entry from history" Set from: Default +! rofi.kb-delete-entry: Shift+Delete +! "Switch to the next mode." Set from: Default +! rofi.kb-mode-next: Shift+Right,Control+Tab +! "Switch to the previous mode." Set from: Default +! rofi.kb-mode-previous: Shift+Left,Control+ISO_Left_Tab +! "Go to the previous column" Set from: Default +! rofi.kb-row-left: Control+Page_Up +! "Go to the next column" Set from: Default +! rofi.kb-row-right: Control+Page_Down +! "Select previous entry" Set from: Default +! rofi.kb-row-up: Up,Control+p,ISO_Left_Tab +! "Select next entry" Set from: Default +! rofi.kb-row-down: Down,Control+n +! "Go to next row, if one left, accept it, if no left next mode." Set from: Default +! rofi.kb-row-tab: Tab +! "Go to the previous page" Set from: Default +! rofi.kb-page-prev: Page_Up +! "Go to the next page" Set from: Default +! rofi.kb-page-next: Page_Down +! "Go to the first entry" Set from: Default +! rofi.kb-row-first: Home,KP_Home +! "Go to the last entry" Set from: Default +! rofi.kb-row-last: End,KP_End +! "Set selected item as input text" Set from: Default +! rofi.kb-row-select: Control+space +! "Take a screenshot of the rofi window" Set from: Default +! rofi.kb-screenshot: Alt+S +! "Toggle between ellipsize modes for displayed data" Set from: Default +! rofi.kb-ellipsize: Alt+period +! "Toggle case sensitivity" Set from: Default +! rofi.kb-toggle-case-sensitivity: grave,dead_grave +! "Toggle sort" Set from: Default +! rofi.kb-toggle-sort: Alt+grave +! "Quit rofi" Set from: Default +! rofi.kb-cancel: Escape,Control+g,Control+bracketleft +! "Custom keybinding 1" Set from: Default +! rofi.kb-custom-1: Alt+1 +! "Custom keybinding 2" Set from: Default +! rofi.kb-custom-2: Alt+2 +! "Custom keybinding 3" Set from: Default +! rofi.kb-custom-3: Alt+3 +! "Custom keybinding 4" Set from: Default +! rofi.kb-custom-4: Alt+4 +! "Custom Keybinding 5" Set from: Default +! rofi.kb-custom-5: Alt+5 +! "Custom keybinding 6" Set from: Default +! rofi.kb-custom-6: Alt+6 +! "Custom Keybinding 7" Set from: Default +! rofi.kb-custom-7: Alt+7 +! "Custom keybinding 8" Set from: Default +! rofi.kb-custom-8: Alt+8 +! "Custom keybinding 9" Set from: Default +! rofi.kb-custom-9: Alt+9 +! "Custom keybinding 10" Set from: Default +! rofi.kb-custom-10: Alt+0 +! "Custom keybinding 11" Set from: Default +! rofi.kb-custom-11: Alt+exclam +! "Custom keybinding 12" Set from: Default +! rofi.kb-custom-12: Alt+at +! "Custom keybinding 13" Set from: Default +! rofi.kb-custom-13: Alt+numbersign +! "Custom keybinding 14" Set from: Default +! rofi.kb-custom-14: Alt+dollar +! "Custom keybinding 15" Set from: Default +! rofi.kb-custom-15: Alt+percent +! "Custom keybinding 16" Set from: Default +! rofi.kb-custom-16: Alt+dead_circumflex +! "Custom keybinding 17" Set from: Default +! rofi.kb-custom-17: Alt+ampersand +! "Custom keybinding 18" Set from: Default +! rofi.kb-custom-18: Alt+asterisk +! "Custom Keybinding 19" Set from: Default +! rofi.kb-custom-19: Alt+parenleft +! "Select row 1" Set from: Default +! rofi.kb-select-1: Super+1 +! "Select row 2" Set from: Default +! rofi.kb-select-2: Super+2 +! "Select row 3" Set from: Default +! rofi.kb-select-3: Super+3 +! "Select row 4" Set from: Default +! rofi.kb-select-4: Super+4 +! "Select row 5" Set from: Default +! rofi.kb-select-5: Super+5 +! "Select row 6" Set from: Default +! rofi.kb-select-6: Super+6 +! "Select row 7" Set from: Default +! rofi.kb-select-7: Super+7 +! "Select row 8" Set from: Default +! rofi.kb-select-8: Super+8 +! "Select row 9" Set from: Default +! rofi.kb-select-9: Super+9 +! "Select row 10" Set from: Default +! rofi.kb-select-10: Super+0 +! "Go to the previous column" Set from: Default +! rofi.ml-row-left: ScrollLeft +! "Go to the next column" Set from: Default +! rofi.ml-row-right: ScrollRight +! "Select previous entry" Set from: Default +! rofi.ml-row-up: ScrollUp +! "Select next entry" Set from: Default +! rofi.ml-row-down: ScrollDown +! "Select hovered row" Set from: Default +! rofi.me-select-entry: MousePrimary +! "Accept hovered row" Set from: Default +! rofi.me-accept-entry: MouseDPrimary +! "Accept hovered row with custom action" Set from: Default +! rofi.me-accept-custom: Control+MouseDPrimary + +!! special +!*.foreground: #c5c8c6 +!*.background: #1d1f21 +!*.cursorColor: #c5c8c6 +! +!! black +!*.color0: #282a2e +!*.color8: #373b41 +! +!! red +!*.color1: #a54242 +!*.color9: #cc6666 +! +!! green +!*.color2: #8c9440 +!*.color10: #b5bd68 +! +!! yellow +!*.color3: #de935f +!*.color11: #f0c674 +! +!! blue +!*.color4: #5f819d +!*.color12: #81a2be +! +!! magenta +!*.color5: #85678f +!*.color13: #b294bb +! +!! cyan +!*.color6: #5e8d87 +!*.color14: #8abeb7 +! +!! white +!*.color7: #707880 +!*.color15: #c5c8c6 +! +!! special +*.foreground: #c5c8c6 +*.background: #000000 +*.cursorColor: #c5c8c6 +*.reverseCursor: #333536 +dmenu.selbackground: #39c1ed +dmenu.selforeground: #000000 +dmenu.hibackground: #000000 +dmenu.hiforeground: #198844 +dmenu.selhibackground: #39c1ed +dmenu.selhiforeground: #198844 + +! black +*.color0: #1b1d1c +*.color8: #969896 + +! red +*.color1: #89231d +*.color9: #cc342b + +! green +*.color2: #4eec4e +*.color10: #198844 + +! yellow +*.color3: #ae7518 +*.color11: #fba922 + +! blue +*.color4: #2b55b2 +*.color12: #3971ed + +! magenta +*.color5: #784e93 +*.color13: #a36ac7 + +! cyan +*.color6: #2783a1 +*.color14: #39c1ed + +! white +*.color7: #b4b7b5 +*.color15: #ffffff diff --git a/X11/xinitrc b/X11/xinitrc new file mode 100755 index 0000000..3945b40 --- /dev/null +++ b/X11/xinitrc @@ -0,0 +1,4 @@ +xrdb ~/.Xresources +sh -c ~/.xprofile & +WM="$(~/.local/scripts/crcparse 'WM')" +exec dbus-launch --exit-with-session $WM diff --git a/X11/xprofile b/X11/xprofile new file mode 100755 index 0000000..96f2954 --- /dev/null +++ b/X11/xprofile @@ -0,0 +1,7 @@ +#!/bin/sh +layout.sh +tsoff +xrdb ~/.Xresources & +setxkbmap -option "caps:escape" & +xwallpaper --center ~/background.jpg & +picom & diff --git a/alacritty/alacritty.yml b/alacritty/alacritty.yml new file mode 100644 index 0000000..1e4bfe0 --- /dev/null +++ b/alacritty/alacritty.yml @@ -0,0 +1,850 @@ +# Configuration for Alacritty, the GPU enhanced terminal emulator. + +# Import additional configuration files +# +# Imports are loaded in order, skipping all missing files, with the importing +# file being loaded last. If a field is already present in a previous import, it +# will be replaced. +# +# All imports must either be absolute paths starting with `/`, or paths relative +# to the user's home directory starting with `~/`. +#import: +# - /path/to/alacritty.yml + +# 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) + # + # Number of lines/columns (not pixels) in the terminal. The number of columns + # must be at least `2`, while using a value of `0` for columns and lines will + # fall back to the window manager's recommended size. + #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 and 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 + + # Allow terminal applications to change Alacritty's window title. + #dynamic_title: true + + # Window class (Linux/BSD only): + #class: + # Application instance name + #instance: Alacritty + # General application class + #general: Alacritty + + # GTK theme variant (Linux/BSD only) + # + # Override the variant of the GTK theme. Commonly supported values are `dark` + # and `light`. Set this to `None` to use the default theme variant. + #gtk_theme_variant: None + + # Background opacity + # + opacity: 0.8 + +scrolling: + # Maximum number of lines in the scrollback buffer. + # Specifying '0' will disable scrolling. + history: 10000 + + # Scrolling distance multiplier. + multiplier: 3 + +# Font configuration +font: + # Normal (roman) font face + normal: + # Font family + # + # Default: + # - (macOS) Menlo + # - (Linux/BSD) monospace + # - (Windows) Consolas + family: mononoki Nerd Font Mono + + # 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: mononoki Nerd Font Mono + + # 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: mononoki Nerd Font Mono + + # The `style` can be specified to pick a specific face. + style: Italic + + # Bold italic font face + bold_italic: + # Font family + # + # If the bold italic family is not specified, it will fall back to the + # value specified for the normal font. + family: mononoki Nerd Font Mono + + # The `style` can be specified to pick a specific face. + style: Bold Italic + + # Point size + size: 11.0 + + # 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 upward. + #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`. + #use_thin_strokes: true + +# If `true`, bold text is drawn using the bright color variants. +draw_bold_text_with_bright_colors: true + +# Colors (ZachIR) +colors: + # Default colors + primary: + background: '#000000' + foreground: '#c5c8c6' + + # Bright and dim foreground colors + # + # The dimmed foreground color is calculated automatically if it is not + # present. If the bright foreground color is not set, or + # `draw_bold_text_with_bright_colors` is `false`, the normal foreground + # color will be used. + dim_foreground: '#828482' + bright_foreground: '#eaeaea' + + # Cursor colors + # + # Colors which should be used to draw the terminal cursor. + # + # Allowed values are CellForeground/CellBackground, which reference the + # affected cell, or hexadecimal colors like #ff00ff. + cursor: + text: CellBackground + cursor: CellForeground + + # Vi mode cursor colors + # + # Colors for the cursor when the vi mode is active. + # + # Allowed values are CellForeground/CellBackground, which reference the + # affected cell, or hexadecimal colors like #ff00ff. + vi_mode_cursor: + text: CellBackground + cursor: CellForeground + + # Search colors + # + # Colors used for the search bar and match highlighting. + search: + # Allowed values are CellForeground/CellBackground, which reference the + # affected cell, or hexadecimal colors like #ff00ff. + matches: + foreground: '#000000' + background: '#ffffff' + focused_match: + foreground: '#ffffff' + background: '#000000' + + bar: + background: '#c5c8c6' + foreground: '#1d1f21' + + # Keyboard regex hints + hints: + # First character in the hint label + # + # Allowed values are CellForeground/CellBackground, which reference the + # affected cell, or hexadecimal colors like #ff00ff. + start: + foreground: '#1d1f21' + background: '#e9ff5e' + + # All characters after the first one in the hint label + # + # Allowed values are CellForeground/CellBackground, which reference the + # affected cell, or hexadecimal colors like #ff00ff. + end: + foreground: '#e9ff5e' + background: '#1d1f21' + + # Line indicator + # + # Color used for the indicator displaying the position in history during + # search and vi mode. + # + # By default, these will use the opposing primary color. + line_indicator: + foreground: None + background: None + + # Selection colors + # + # Colors which should be used to draw the selection area. + # + # Allowed values are CellForeground/CellBackground, which reference the + # affected cell, or hexadecimal colors like #ff00ff. + selection: + text: CellBackground + background: CellForeground + + # Normal colors + normal: + black: '#1d1f21' + red: '#89231d' + green: '#146e37' + yellow: '#ae7518' + blue: '#2b55b2' + magenta: '#784e93' + cyan: '#2783a1' + white: '#b4b7b5' + + # Bright colors + bright: + black: '#969896' + red: '#cc342b' + green: '#198844' + yellow: '#fba922' + blue: '#3971ed' + magenta: '#a36ac7' + cyan: '#39c1ed' + white: '#ffffff' + + # Dim colors + # + # If the dim colors are not set, they will be calculated automatically based + # on the `normal` colors. + #dim: + # black: '#131415' + # red: '#864343' + # green: '#777c44' + # yellow: '#9e824c' + # blue: '#556a7d' + # magenta: '#75617b' + # cyan: '#5b7d78' + # white: '#828482' + + # Indexed Colors + # + # The indexed colors include all colors from 16 to 256. + # When these are not set, they're filled with sensible defaults. + # + # Example: + # `- { index: 16, color: '#ff00ff' }` + # + #indexed_colors: [] + +# Bell +# +# The bell is rung every time the BEL control character is received. +bell: + # Visual Bell Animation + # + # Animation effect for flashing the screen when the visual bell is rung. + # + # Values for `animation`: + # - Ease + # - EaseOut + # - EaseOutSine + # - EaseOutQuad + # - EaseOutCubic + # - EaseOutQuart + # - EaseOutQuint + # - EaseOutExpo + # - EaseOutCirc + # - Linear + #animation: EaseOutExpo + + # Duration of the visual bell flash in milliseconds. A `duration` of `0` will + # disable the visual bell animation. + duration: 0 + + # Visual bell animation color. + #color: '#ffffff' + + # Bell Command + # + # This program is executed whenever the bell is rung. + # + # When set to `command: None`, no command will be executed. + # + # Example: + # command: + # program: notify-send + # args: ["Hello, World!"] + # + #command: None + +#selection: + # This string contains all characters that are used as separators for + # "semantic words" in Alacritty. + #semantic_escape_chars: ",│`|:\"' ()[]{}<>\t" + + # When set to `true`, selected text will be copied to the primary clipboard. + #save_to_clipboard: false + +cursor: + # Cursor style + style: + # Cursor shape + # + # Values for `shape`: + # - ▇ Block + # - _ Underline + # - | Beam + shape: Block + + # Cursor blinking state + # + # Values for `blinking`: + # - Never: Prevent the cursor from ever blinking + # - Off: Disable blinking by default + # - On: Enable blinking by default + # - Always: Force the cursor to always blink + blinking: Off + + # Vi mode cursor style + # + # If the vi mode cursor style is `None` or not specified, it will fall back to + # the style of the active value of the normal cursor. + # + # See `cursor.style` for available options. + #vi_mode_style: None + + # Cursor blinking interval in milliseconds. + #blink_interval: 750 + + # If this is `true`, the cursor will be rendered as a hollow box when the + # window is not focused. + #unfocused_hollow: true + + # Thickness of the cursor relative to the cell width as floating point number + # from `0.0` to `1.0`. + #thickness: 0.15 + +# 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: +# - (macOS) /bin/bash --login +# - (Linux/BSD) user login shell +# - (Windows) powershell +# shell: + # program: /bin/ksh + #args: + # - --login + +# Startup directory +# +# Directory the shell is started in. If this is unset, or `None`, the working +# directory of the parent process will be used. +#working_directory: None + +# Send ESC (\x1b) before characters when alt is pressed. +#alt_send_esc: true + +#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 + +# Regex hints +# +# Terminal hints can be used to find text in the visible part of the terminal +# and pipe it to other applications. +#hints: + # Keys used for the hint labels. + #alphabet: "jfkdls;ahgurieowpq" + + # List with all available hints + # + # Each hint must have a `regex` and either an `action` or a `command` field. + # The fields `mouse`, `binding` and `post_processing` are optional. + # + # The fields `command`, `binding.key`, `binding.mods` and `mouse.mods` accept + # the same values as they do in the `key_bindings` section. + # + # The `mouse.enabled` field controls if the hint should be underlined while + # the mouse with all `mouse.mods` keys held or the vi mode cursor is above it. + # + # If the `post_processing` field is set to `true`, heuristics will be used to + # shorten the match if there are characters likely not to be part of the hint + # (e.g. a trailing `.`). This is most useful for URIs. + # + # Values for `action`: + # - Copy + # Copy the hint's text to the clipboard. + # - Paste + # Paste the hint's text to the terminal or search. + # - Select + # Select the hint's text. + # - MoveViModeCursor + # Move the vi mode cursor to the beginning of the hint. + #enabled: + # - regex: "(ipfs:|ipns:|magnet:|mailto:|gemini:|gopher:|https:|http:|news:|file:|git:|ssh:|ftp:)\ + # [^\u0000-\u001F\u007F-\u009F<>\"\\s{-}\\^⟨⟩`]+" + # command: xdg-open + # post_processing: true + # mouse: + # enabled: true + # mods: None + # binding: + # key: U + # mods: Control|Shift + +# Mouse bindings +# +# Mouse bindings are specified as a list of objects, much like the key +# bindings further below. +# +# To trigger mouse bindings when an application running within Alacritty +# captures the mouse, the `Shift` modifier is automatically added as a +# requirement. +# +# Each mouse binding will specify a: +# +# - `mouse`: +# +# - Middle +# - Left +# - Right +# - Numeric identifier such as `5` +# +# - `action` (see key bindings) +# +# And optionally: +# +# - `mods` (see key bindings) +#mouse_bindings: +# - { mouse: Middle, action: PasteSelection } + +# Key bindings +# +# Key bindings are specified as a list of objects. For example, this is the +# default paste binding: +# +# `- { key: V, mods: Control|Shift, action: Paste }` +# +# Each key binding will specify a: +# +# - `key`: Identifier of the key pressed +# +# - A-Z +# - F1-F24 +# - Key0-Key9 +# +# A full list with available key codes can be found here: +# https://docs.rs/glutin/*/glutin/event/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`. +# +# Then exactly one of: +# +# - `chars`: Send a byte sequence to the running application +# +# 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. +# +# - `action`: Execute a predefined action +# +# - ToggleViMode +# - SearchForward +# Start searching toward the right of the search origin. +# - SearchBackward +# Start searching toward the left of the search origin. +# - Copy +# - Paste +# - IncreaseFontSize +# - DecreaseFontSize +# - ResetFontSize +# - ScrollPageUp +# - ScrollPageDown +# - ScrollHalfPageUp +# - ScrollHalfPageDown +# - ScrollLineUp +# - ScrollLineDown +# - ScrollToTop +# - ScrollToBottom +# - ClearHistory +# Remove the terminal's scrollback history. +# - Hide +# Hide the Alacritty window. +# - Minimize +# Minimize the Alacritty window. +# - Quit +# Quit Alacritty. +# - ToggleFullscreen +# - SpawnNewInstance +# Spawn a new instance of Alacritty. +# - ClearLogNotice +# Clear Alacritty's UI warning and error notice. +# - ClearSelection +# Remove the active selection. +# - ReceiveChar +# - None +# +# - Vi mode exclusive actions: +# +# - Open +# Perform the action of the first matching hint under the vi mode cursor +# with `mouse.enabled` set to `true`. +# - ToggleNormalSelection +# - ToggleLineSelection +# - ToggleBlockSelection +# - ToggleSemanticSelection +# Toggle semantic selection based on `selection.semantic_escape_chars`. +# +# - Vi mode exclusive cursor motion actions: +# +# - Up +# One line up. +# - Down +# One line down. +# - Left +# One character left. +# - Right +# One character right. +# - First +# First column, or beginning of the line when already at the first column. +# - Last +# Last column, or beginning of the line when already at the last column. +# - FirstOccupied +# First non-empty cell in this terminal row, or first non-empty cell of +# the line when already at the first cell of the row. +# - High +# Top of the screen. +# - Middle +# Center of the screen. +# - Low +# Bottom of the screen. +# - SemanticLeft +# Start of the previous semantically separated word. +# - SemanticRight +# Start of the next semantically separated word. +# - SemanticLeftEnd +# End of the previous semantically separated word. +# - SemanticRightEnd +# End of the next semantically separated word. +# - WordLeft +# Start of the previous whitespace separated word. +# - WordRight +# Start of the next whitespace separated word. +# - WordLeftEnd +# End of the previous whitespace separated word. +# - WordRightEnd +# End of the next whitespace separated word. +# - Bracket +# Character matching the bracket at the cursor's location. +# - SearchNext +# Beginning of the next match. +# - SearchPrevious +# Beginning of the previous match. +# - SearchStart +# Start of the match to the left of the vi mode cursor. +# - SearchEnd +# End of the match to the right of the vi mode cursor. +# +# - Search mode exclusive actions: +# - SearchFocusNext +# Move the focus to the next search match. +# - SearchFocusPrevious +# Move the focus to the previous search match. +# - SearchConfirm +# - SearchCancel +# - SearchClear +# Reset the search regex. +# - SearchDeleteWord +# Delete the last word in the search regex. +# - SearchHistoryPrevious +# Go to the previous regex in the search history. +# - SearchHistoryNext +# Go to the next regex in the search history. +# +# - macOS exclusive actions: +# - ToggleSimpleFullscreen +# Enter fullscreen without occupying another space. +# +# - Linux/BSD exclusive actions: +# +# - CopySelection +# Copy from the selection buffer. +# - PasteSelection +# Paste from the selection buffer. +# +# - `command`: Fork and execute a specified command plus arguments +# +# The `command` field must be a map containing a `program` string and an +# `args` array of command line parameter strings. For example: +# `{ program: "alacritty", args: ["-e", "vttest"] }` +# +# And optionally: +# +# - `mods`: Key modifiers to filter binding actions +# +# - Command +# - Control +# - Option +# - Super +# - Shift +# - Alt +# +# Multiple `mods` can be combined using `|` like this: +# `mods: Control|Shift`. +# Whitespace and capitalization are relevant and must match the example. +# +# - `mode`: Indicate a binding for only specific terminal reported modes +# +# This is mainly used to send applications the correct escape sequences +# when in different modes. +# +# - AppCursor +# - AppKeypad +# - Search +# - Alt +# - Vi +# +# A `~` operator can be used before a mode to apply the binding whenever +# the mode is *not* active, e.g. `~Alt`. +# +# 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 `ReceiveChar` action. Alternatively, you can use `None` for +# a no-op if you do not wish to receive input characters for that binding. +# +# If the same trigger is assigned to multiple actions, all of them are executed +# in the order they were defined in. +#key_bindings: + #- { key: Paste, action: Paste } + #- { key: Copy, action: Copy } + #- { key: L, mods: Control, action: ClearLogNotice } + #- { key: L, mods: Control, mode: ~Vi|~Search, chars: "\x0c" } + #- { key: PageUp, mods: Shift, mode: ~Alt, action: ScrollPageUp, } + #- { key: PageDown, mods: Shift, mode: ~Alt, action: ScrollPageDown } + #- { key: Home, mods: Shift, mode: ~Alt, action: ScrollToTop, } + #- { key: End, mods: Shift, mode: ~Alt, action: ScrollToBottom } + + # Vi Mode + #- { key: Space, mods: Shift|Control, mode: Vi|~Search, action: ScrollToBottom } + #- { key: Space, mods: Shift|Control, mode: ~Search, action: ToggleViMode } + #- { key: Escape, mode: Vi|~Search, action: ClearSelection } + #- { key: I, mode: Vi|~Search, action: ScrollToBottom } + #- { key: I, mode: Vi|~Search, action: ToggleViMode } + #- { key: C, mods: Control, mode: Vi|~Search, action: ToggleViMode } + #- { key: Y, mods: Control, mode: Vi|~Search, action: ScrollLineUp } + #- { key: E, mods: Control, mode: Vi|~Search, action: ScrollLineDown } + #- { key: G, mode: Vi|~Search, action: ScrollToTop } + #- { key: G, mods: Shift, mode: Vi|~Search, action: ScrollToBottom } + #- { key: B, mods: Control, mode: Vi|~Search, action: ScrollPageUp } + #- { key: F, mods: Control, mode: Vi|~Search, action: ScrollPageDown } + #- { key: U, mods: Control, mode: Vi|~Search, action: ScrollHalfPageUp } + #- { key: D, mods: Control, mode: Vi|~Search, action: ScrollHalfPageDown } + #- { key: Y, mode: Vi|~Search, action: Copy } + #- { key: Y, mode: Vi|~Search, action: ClearSelection } + #- { key: Copy, mode: Vi|~Search, action: ClearSelection } + #- { key: V, mode: Vi|~Search, action: ToggleNormalSelection } + #- { key: V, mods: Shift, mode: Vi|~Search, action: ToggleLineSelection } + #- { key: V, mods: Control, mode: Vi|~Search, action: ToggleBlockSelection } + #- { key: V, mods: Alt, mode: Vi|~Search, action: ToggleSemanticSelection } + #- { key: Return, mode: Vi|~Search, action: Open } + #- { key: K, mode: Vi|~Search, action: Up } + #- { key: J, mode: Vi|~Search, action: Down } + #- { key: H, mode: Vi|~Search, action: Left } + #- { key: L, mode: Vi|~Search, action: Right } + #- { key: Up, mode: Vi|~Search, action: Up } + #- { key: Down, mode: Vi|~Search, action: Down } + #- { key: Left, mode: Vi|~Search, action: Left } + #- { key: Right, mode: Vi|~Search, action: Right } + #- { key: Key0, mode: Vi|~Search, action: First } + #- { key: Key4, mods: Shift, mode: Vi|~Search, action: Last } + #- { key: Key6, mods: Shift, mode: Vi|~Search, action: FirstOccupied } + #- { key: H, mods: Shift, mode: Vi|~Search, action: High } + #- { key: M, mods: Shift, mode: Vi|~Search, action: Middle } + #- { key: L, mods: Shift, mode: Vi|~Search, action: Low } + #- { key: B, mode: Vi|~Search, action: SemanticLeft } + #- { key: W, mode: Vi|~Search, action: SemanticRight } + #- { key: E, mode: Vi|~Search, action: SemanticRightEnd } + #- { key: B, mods: Shift, mode: Vi|~Search, action: WordLeft } + #- { key: W, mods: Shift, mode: Vi|~Search, action: WordRight } + #- { key: E, mods: Shift, mode: Vi|~Search, action: WordRightEnd } + #- { key: Key5, mods: Shift, mode: Vi|~Search, action: Bracket } + #- { key: Slash, mode: Vi|~Search, action: SearchForward } + #- { key: Slash, mods: Shift, mode: Vi|~Search, action: SearchBackward } + #- { key: N, mode: Vi|~Search, action: SearchNext } + #- { key: N, mods: Shift, mode: Vi|~Search, action: SearchPrevious } + + # Search Mode + #- { key: Return, mode: Search|Vi, action: SearchConfirm } + #- { key: Escape, mode: Search, action: SearchCancel } + #- { key: C, mods: Control, mode: Search, action: SearchCancel } + #- { key: U, mods: Control, mode: Search, action: SearchClear } + #- { key: W, mods: Control, mode: Search, action: SearchDeleteWord } + #- { key: P, mods: Control, mode: Search, action: SearchHistoryPrevious } + #- { key: N, mods: Control, mode: Search, action: SearchHistoryNext } + #- { key: Up, mode: Search, action: SearchHistoryPrevious } + #- { key: Down, mode: Search, action: SearchHistoryNext } + #- { key: Return, mode: Search|~Vi, action: SearchFocusNext } + #- { key: Return, mods: Shift, mode: Search|~Vi, action: SearchFocusPrevious } + + # (Windows, Linux, and BSD only) + #- { key: V, mods: Control|Shift, mode: ~Vi, action: Paste } + #- { key: C, mods: Control|Shift, action: Copy } + #- { key: F, mods: Control|Shift, mode: ~Search, action: SearchForward } + #- { key: B, mods: Control|Shift, mode: ~Search, action: SearchBackward } + #- { key: C, mods: Control|Shift, mode: Vi|~Search, action: ClearSelection } + #- { key: Insert, mods: Shift, action: PasteSelection } + #- { key: Key0, mods: Control, action: ResetFontSize } + #- { key: Equals, mods: Control, action: IncreaseFontSize } + #- { key: Plus, mods: Control, action: IncreaseFontSize } + #- { key: NumpadAdd, mods: Control, action: IncreaseFontSize } + #- { key: Minus, mods: Control, action: DecreaseFontSize } + #- { key: NumpadSubtract, mods: Control, action: DecreaseFontSize } + + # (Windows only) + #- { key: Return, mods: Alt, action: ToggleFullscreen } + + # (macOS only) + #- { key: K, mods: Command, mode: ~Vi|~Search, chars: "\x0c" } + #- { key: K, mods: Command, mode: ~Vi|~Search, action: ClearHistory } + #- { key: Key0, mods: Command, action: ResetFontSize } + #- { key: Equals, mods: Command, action: IncreaseFontSize } + #- { key: Plus, mods: Command, action: IncreaseFontSize } + #- { key: NumpadAdd, mods: Command, action: IncreaseFontSize } + #- { key: Minus, mods: Command, action: DecreaseFontSize } + #- { key: NumpadSubtract, mods: Command, action: DecreaseFontSize } + #- { key: V, mods: Command, action: Paste } + #- { key: C, mods: Command, action: Copy } + #- { key: C, mods: Command, mode: Vi|~Search, action: ClearSelection } + #- { key: H, mods: Command, action: Hide } + #- { key: H, mods: Command|Alt, action: HideOtherApplications } + #- { key: M, mods: Command, action: Minimize } + #- { key: Q, mods: Command, action: Quit } + #- { key: W, mods: Command, action: Quit } + #- { key: N, mods: Command, action: SpawnNewInstance } + #- { key: F, mods: Command|Control, action: ToggleFullscreen } + #- { key: F, mods: Command, mode: ~Search, action: SearchForward } + #- { key: B, mods: Command, mode: ~Search, action: SearchBackward } + +#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`: + # - Off + # - Error + # - Warn + # - Info + # - Debug + # - Trace + #log_level: Warn + + # Print all received window events. + #print_events: false diff --git a/autostart.sh b/autostart.sh new file mode 100755 index 0000000..bb5e986 --- /dev/null +++ b/autostart.sh @@ -0,0 +1,50 @@ +#!/bin/sh +runifnot () { + if type $1 >/dev/null; then + echo $1 + if [ -z "$(pgrep -f $1)" ]; then + $@ & + fi + fi +} + +runifnot `crcparse snd` +if type mpd >/dev/null; then + runifnot mpd +elif type musicpd >/dev/null; then + runifnot musicpd +fi +runifnot mpd-mpris -network unix +runifnot mpd-notification +runifnot transmission-daemon +#runifnot dbus-daemon --session --address=unix:path=$XDG_RUNTIME_DIR/bus +runifnot openrazer-daemon +runifnot lxqt-policykit-agent +razer-cli -e static & +#runifnot nextcloud +if [ -z "$WAYLAND_DISPLAY" ]; then + runifnot xss-lock -n notify-send slockd + #if pgrep -x swhkd; then + # doas killall swhkd && pkexec swhkd + #fi + #pkexec swhkd & + #runifnot swhks + runifnot sxhkd + runifnot dunst + runifnot caffeine-ng + if [ "$(crcparse WM)" = "$(which xmonad)" ]; then + runifnot stalonetray + fi + xwallpaper --zoom ~/background.jpg + setxkbmap -option "caps:escape" +else + toggle swaybg -i ~/background.jpg + gsettings set org.gnome.desktop.interface gtk-theme Sweet-Dark-v40 + gsettings set org.gnome.desktop.interface icon-theme Paper-Mono-Dark + runifnot swayidle -w + hotkeys.sh + runifnot mako + if [ "$(crcparse WC)" != "$(which qtile)" ]; then + runifnot waybar + fi +fi diff --git a/awesome b/awesome new file mode 160000 index 0000000..98e36e5 --- /dev/null +++ b/awesome @@ -0,0 +1 @@ +Subproject commit 98e36e5087a8855bf758c95d9e90d6feae15a619 diff --git a/bspwm/bspwmrc b/bspwm/bspwmrc new file mode 100755 index 0000000..5799efb --- /dev/null +++ b/bspwm/bspwmrc @@ -0,0 +1,66 @@ +#! /bin/sh +sxhkd -c ~/.config/sxhkd/sxhkdrc.1 & +launch_polybar.sh 'bspwm' & +pgrep -fl 'pidswallow -gl' || pidswallow -gl +~/.config/autostart.sh + +set_desktops () { + case "$1" in + "2") + bspc monitor "$2" -d I II III IV V + bspc monitor "$3" -d VI VII VIII IX X + ;; + "3") + bspc monitor "$2" -d I II III + bspc monitor "$3" -d IV V VI VIII + bspc monitor "$4" -d VIII IX X + ;; + "4") + bspc monitor "$2" -d I II III + bspc monitor "$3" -d IV V + bspc monitor "$4" -d VI VII + bspc monitor "$5" -d VIII IX X + ;; + "5") + bspc monitor "$2" -d I II + bspc monitor "$3" -d III IV + bspc monitor "$4" -d V VI + bspc monitor "$5" -d VII VIII + bspc monitor "$6" -d IX X + esac +} + +MONITORS=`xrandr | awk '/ connected/ && /[[:digit:]]x[[:digit:]].*+/{print $1}'` +MONITOR_COUNT=`echo "$MONITORS" | wc -l` +if [ "$MONITOR_COUNT" -lt 2 ]; then + bspc monitor -d I II III IV V VI VII VIII IX X +else + set_desktops "$MONITOR_COUNT" `echo "$MONITORS" | sed 's/\n/ /g'` +fi + +bspc config border_width 2 +bspc config window_gap 10 +bspc config top_padding 27 + +bspc config split_ratio 0.50 +bspc config borderless_monocle true +bspc config gapless_monocle true + +bspc config focus_follows_pointer true + +bspc rule -a Thunderbird:\* desktop=X +bspc rule -a Nextcloud:nextcloud state=tiled +bspc rule -a Surf:surf state=tiled +bspc rule -a QjackCtl:qjackctl state=floating +bspc rule -a Ardour-5.12.0:ardour-5.12.0 state=floating + +bspc rule -a sphtop sticky=on state=floating +bspc rule -a spterm sticky=on state=floating +bspc rule -a sppmxr sticky=on state=floating +bspc rule -a spblue sticky=on state=floating +bspc rule -a spncmp sticky=on state=floating +bspc rule -a spmutt sticky=on state=floating +bspc rule -a spprof sticky=on state=floating +bspc rule -a spircc sticky=on state=floating +bspc rule -a sptodo sticky=on state=floating +bspc rule -a sptrem sticky=on state=floating diff --git a/bspwm/noswallow b/bspwm/noswallow new file mode 100644 index 0000000..b75624e --- /dev/null +++ b/bspwm/noswallow @@ -0,0 +1 @@ +REAPER diff --git a/bspwm/terminals b/bspwm/terminals new file mode 100644 index 0000000..974a8d3 --- /dev/null +++ b/bspwm/terminals @@ -0,0 +1,3 @@ +tabbed +st +"tabbed" diff --git a/caffeine/audio_blacklist.txt b/caffeine/audio_blacklist.txt new file mode 100644 index 0000000..e69de29 diff --git a/caffeine/whitelist.txt b/caffeine/whitelist.txt new file mode 100644 index 0000000..e69de29 diff --git a/computerrc.txt b/computerrc.txt new file mode 100644 index 0000000..3f3209b --- /dev/null +++ b/computerrc.txt @@ -0,0 +1,10 @@ +The following fields are expected in computerrc: + +inet: internet interface i.e. eth0, trunk0, em0 +OS: base operating system/kernel i.e. Linux, OpenBSD, FreeBSD +WM: default x11 window manager command i.e. awesome, qtile start +WC: default wayland compositor command i.e. river, qtile start --backend wayland +snd: sound server to launch automatically i.e. pipewire, pulseaudio, sndio, oss +batt: if there is a battery or not i.e. y or n +wayland: if boot into wayland or not i.e. y or n +tsname: touchscreen xorg device i.e. device from xinput diff --git a/cool-retro-term/cool-retro-term.conf b/cool-retro-term/cool-retro-term.conf new file mode 100644 index 0000000..d190d88 --- /dev/null +++ b/cool-retro-term/cool-retro-term.conf @@ -0,0 +1,7 @@ +[QQControlsFileDialog] +favoriteFolders=@Invalid() +height=0 +sidebarSplit=118.575 +sidebarVisible=true +sidebarWidth=80 +width=0 diff --git a/deadbeef/config b/deadbeef/config new file mode 100644 index 0000000..16ff3ae --- /dev/null +++ b/deadbeef/config @@ -0,0 +1,79 @@ +artwork.filemask *cover*.jpg;*front*.jpg;*folder*.jpg;*cover*.png;*front*.png;*folder*.png +cli_add_playlist_name Default +cli_add_to_specific_playlist 1 +close_send_to_tray 1 +deadbeef_version 0.7.2 +filechooser.lastdir file:///home/zachir/Music/Starset/VESSELS +gtkui.columns.playlist [{"title":"♫","id":"1","format":"%playstatus%","size":"50","align":"0","color_override":"0","color":"#ff000000"},{"title":"Artist / Album","id":"-1","format":"%artist% - %album%","size":"161","align":"0","color_override":"0","color":"#ff000000"},{"title":"Track No","id":"-1","format":"%tracknumber%","size":"50","align":"1","color_override":"0","color":"#ff000000"},{"title":"Title","id":"-1","format":"%title%","size":"160","align":"0","color_override":"0","color":"#ff000000"},{"title":"Duration","id":"-1","format":"%length%","size":"50","align":"0","color_override":"0","color":"#ff000000"}] +gtkui.layout.0.6.2 vbox expand="0 1" fill="1 1" homogeneous=0 {hbox expand="0 1 0" fill="1 1 1" homogeneous=0 {playtb {} seekbar {} volumebar {} } hsplitter pos=481 locked=0 {tabbed_playlist hideheaders=0 width=481 {} vsplitter pos=234 locked=0 {spectrum {} coverart {} } } } +gtkui.mmb_delete_playlist 1 +gtkui.name_playlist_from_folder 1 +gtkui.statusbar.visible 1 +gtkui.tabscroll 0 +gtkui.titlebar_playing_tf %artist% - %title% - DeaDBeeF-%_deadbeef_version% +gtkui.titlebar_stopped_tf DeaDBeeF-%_deadbeef_version% +hotkey.key01 "Ctrl f" 0 0 find +hotkey.key02 "Ctrl o" 0 0 open_files +hotkey.key03 "Ctrl q" 0 0 quit +hotkey.key04 "Ctrl n" 0 0 new_playlist +hotkey.key05 "Ctrl a" 0 0 select_all +hotkey.key06 "Escape" 0 0 deselect_all +hotkey.key07 "Ctrl m" 0 0 toggle_stop_after_current +hotkey.key08 "Ctrl j" 0 0 jump_to_current_track +hotkey.key09 "F1" 0 0 help +hotkey.key10 "Delete" 1 0 remove_from_playlist +hotkey.key11 "Ctrl w" 0 0 remove_current_playlist +hotkey.key14 "Return" 0 0 play +hotkey.key15 "Ctrl p" 0 0 toggle_pause +hotkey.key16 "Alt 1" 0 0 playlist1 +hotkey.key17 "Alt 2" 0 0 playlist2 +hotkey.key18 "Alt 3" 0 0 playlist3 +hotkey.key19 "Alt 4" 0 0 playlist4 +hotkey.key20 "Alt 5" 0 0 playlist5 +hotkey.key21 "Alt 6" 0 0 playlist6 +hotkey.key22 "Alt 7" 0 0 playlist7 +hotkey.key23 "Alt 8" 0 0 playlist8 +hotkey.key24 "Alt 9" 0 0 playlist9 +hotkey.key25 "Alt 0" 0 0 playlist10 +hotkey.key26 z 0 0 prev +hotkey.key27 x 0 0 play +hotkey.key28 c 0 0 toggle_pause +hotkey.key29 v 0 0 stop +hotkey.key30 b 0 0 next +hotkey.key31 n 0 0 playback_random +hotkey.key32 "Ctrl k" 0 0 toggle_stop_after_album +hotkeys_created 1 +ignore_archives 1 +junk.enable_cp1251_detection 1 +mainwin.geometry.h 343 +mainwin.geometry.w 946 +mainwin.geometry.x 966 +mainwin.geometry.y 372 +network.http_user_agent deadbeef +network.proxy.port 8080 +network.proxy.type HTTP +playback.loop 0 +playback.order 0 +playback.volume 0.0000000 +playlist.current 2 +playlist.cursor.0 1 +playlist.cursor.1 9 +playlist.cursor.2 2 +playlist.scroll.0 0 +playlist.scroll.1 0 +playlist.scroll.2 0 +playlist.scroll.cursorfollowplayback 1 +playlist.tab.00000 Van Weezer +playlist.tab.00001 Blue Album +playlist.tab.00002 VESSELS +prefwin.geometry.h 511 +prefwin.geometry.w 665 +prefwin.geometry.x 627 +prefwin.geometry.y 284 +replaygain_mode 0 +replaygain_scale 1 +resume.paused 0 +resume.playlist 2 +resume.position -1.000000 +resume.track -1 +streamer.8_to_16 1 diff --git a/deadbeef/dspconfig b/deadbeef/dspconfig new file mode 100644 index 0000000..e69de29 diff --git a/deadbeef/playlists/0.dbpl b/deadbeef/playlists/0.dbpl new file mode 100644 index 0000000..f1fd6b4 Binary files /dev/null and b/deadbeef/playlists/0.dbpl differ diff --git a/deadbeef/playlists/1.dbpl b/deadbeef/playlists/1.dbpl new file mode 100644 index 0000000..11fc9eb Binary files /dev/null and b/deadbeef/playlists/1.dbpl differ diff --git a/deadbeef/playlists/2.dbpl b/deadbeef/playlists/2.dbpl new file mode 100644 index 0000000..7421fa7 Binary files /dev/null and b/deadbeef/playlists/2.dbpl differ diff --git a/doas.conf b/doas.conf new file mode 100644 index 0000000..b4065ab --- /dev/null +++ b/doas.conf @@ -0,0 +1,19 @@ +permit persist zachir +permit nopass zachir cmd make args install +permit nopass zachir cmd rsm args start libvirtd virtlockd virtlogd +permit nopass zachir cmd rsm args stop libvirtd virtlockd virtlogd +permit nopass zachir cmd pacman +permit nopass zachir cmd iptables +permit nopass zachir cmd ip6tables +permit nopass zachir cmd mount +permit nopass zachir cmd mount.exfat +permit nopass zachir cmd umount +permit nopass zachir cmd modprobe +permit nopass zachir cmd zzz +permit nopass zachir cmd sv +permit nopass zachir cmd swhkd args +permit nopass zachir cmd pkill args -HUP swhkd +permit nopass zachir cmd killall args swhkd +permit nopass keepenv zachir as zachir + +permit nopass keepenv root diff --git a/doom/config.el b/doom/config.el new file mode 100644 index 0000000..ccb55a5 --- /dev/null +++ b/doom/config.el @@ -0,0 +1,54 @@ +;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- + +;; Place your private configuration here! Remember, you do not need to run 'doom +;; sync' after modifying this file! + + +;; Some functionality uses this to identify you, e.g. GPG configuration, email +;; clients, file templates and snippets. +(setq user-full-name "ZachIR" + user-mail-address "zachir@librem.one") + +;; Doom exposes five (optional) variables for controlling fonts in Doom. Here +;; are the three important ones: +;; +;; + `doom-font' +;; + `doom-variable-pitch-font' +;; + `doom-big-font' -- used for `doom-big-font-mode'; use this for +;; presentations or streaming. +;; +;; They all accept either a font-spec, font string ("Input Mono-12"), or xlfd +;; font string. You generally only need these two: +;; (setq doom-font (font-spec :family "monospace" :size 12 :weight 'semi-light) +;; doom-variable-pitch-font (font-spec :family "sans" :size 13)) + +;; There are two ways to load a theme. Both assume the theme is installed and +;; available. You can either set `doom-theme' or manually load a theme with the +;; `load-theme' function. This is the default: +(setq doom-theme 'doom-one) + +;; If you use `org' and don't want your org files in the default location below, +;; change `org-directory'. It must be set before org loads! +(setq org-directory "~/org/") + +;; This determines the style of line numbers in effect. If set to `nil', line +;; numbers are disabled. For relative line numbers, set this to `relative'. +(setq display-line-numbers-type t) + + +;; Here are some additional functions/macros that could help you configure Doom: +;; +;; - `load!' for loading external *.el files relative to this one +;; - `use-package!' for configuring packages +;; - `after!' for running code after a package has loaded +;; - `add-load-path!' for adding directories to the `load-path', relative to +;; this file. Emacs searches the `load-path' when you load packages with +;; `require' or `use-package'. +;; - `map!' for binding new keys +;; +;; To get information about any of these functions/macros, move the cursor over +;; the highlighted symbol at press 'K' (non-evil users must press 'C-c c k'). +;; This will open documentation for it, including demos of how they are used. +;; +;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how +;; they are implemented. diff --git a/doom/init.el b/doom/init.el new file mode 100644 index 0000000..c4b979a --- /dev/null +++ b/doom/init.el @@ -0,0 +1,183 @@ +;;; init.el -*- lexical-binding: t; -*- + +;; This file controls what Doom modules are enabled and what order they load +;; in. Remember to run 'doom sync' after modifying it! + +;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's +;; documentation. There you'll find a "Module Index" link where you'll find +;; a comprehensive list of Doom's modules and what flags they support. + +;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or +;; 'C-c c k' for non-vim users) to view its documentation. This works on +;; flags as well (those symbols that start with a plus). +;; +;; Alternatively, press 'gd' (or 'C-c c d') on a module to browse its +;; directory (for easy access to its source code). + +(doom! :input + ;;chinese + ;;japanese + ;;layout ; auie,ctsrnm is the superior home row + + :completion + company ; the ultimate code completion backend + ;;helm ; the *other* search engine for love and life + ;;ido ; the other *other* search engine... + ivy ; a search engine for love and life + + :ui + ;;deft ; notational velocity for Emacs + doom ; what makes DOOM look the way it does + doom-dashboard ; a nifty splash screen for Emacs + doom-quit ; DOOM quit-message prompts when you quit Emacs + ;;fill-column ; a `fill-column' indicator + hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW + ;;hydra + ;;indent-guides ; highlighted indent columns + ;;ligatures ; ligatures and symbols to make your code pretty again + ;;minimap ; show a map of the code on the side + modeline ; snazzy, Atom-inspired modeline, plus API + ;;nav-flash ; blink cursor line after big motions + ;;neotree ; a project drawer, like NERDTree for vim + ophints ; highlight the region an operation acts on + (popup +defaults) ; tame sudden yet inevitable temporary windows + ;;tabs ; a tab bar for Emacs + ;;treemacs ; a project drawer, like neotree but cooler + ;;unicode ; extended unicode support for various languages + vc-gutter ; vcs diff in the fringe + vi-tilde-fringe ; fringe tildes to mark beyond EOB + ;;window-select ; visually switch windows + workspaces ; tab emulation, persistence & separate workspaces + ;;zen ; distraction-free coding or writing + + :editor + (evil +everywhere); come to the dark side, we have cookies + file-templates ; auto-snippets for empty files + fold ; (nigh) universal code folding + ;;(format +onsave) ; automated prettiness + ;;god ; run Emacs commands without modifier keys + ;;lispy ; vim for lisp, for people who don't like vim + ;;multiple-cursors ; editing in many places at once + ;;objed ; text object editing for the innocent + ;;parinfer ; turn lisp into python, sort of + ;;rotate-text ; cycle region at point between text candidates + snippets ; my elves. They type so I don't have to + word-wrap ; soft wrapping with language-aware indent + + :emacs + dired ; making dired pretty [functional] + electric ; smarter, keyword-based electric-indent + ;;ibuffer ; interactive buffer management + undo ; persistent, smarter undo for your inevitable mistakes + vc ; version-control and Emacs, sitting in a tree + + :term + ;;eshell ; the elisp shell that works everywhere + ;;shell ; simple shell REPL for Emacs + ;;term ; basic terminal emulator for Emacs + vterm ; the best terminal emulation in Emacs + + :checkers + syntax ; tasing you for every semicolon you forget + spell ; tasing you for misspelling mispelling + grammar ; tasing grammar mistake every you make + + :tools + ;;ansible + ;;debugger ; FIXME stepping through code, to help you add bugs + ;;direnv + ;;docker + ;;editorconfig ; let someone else argue about tabs vs spaces + ;;ein ; tame Jupyter notebooks with emacs + (eval +overlay) ; run code, run (also, repls) + ;;gist ; interacting with github gists + lookup ; navigate your code and its documentation + ;;lsp + magit ; a git porcelain for Emacs + make ; run make tasks from Emacs + pass ; password manager for nerds + pdf ; pdf enhancements + ;;prodigy ; FIXME managing external services & code builders + rgb ; creating color strings + ;;taskrunner ; taskrunner for all your projects + ;;terraform ; infrastructure as code + tmux ; an API for interacting with tmux + ;;upload ; map local to remote projects via ssh/ftp + + :os + (:if IS-MAC macos) ; improve compatibility with macOS + ;;tty ; improve the terminal Emacs experience + + :lang + ;;agda ; types of types of types of types... + cc ; C/C++/Obj-C madness + ;;clojure ; java with a lisp + ;;common-lisp ; if you've seen one lisp, you've seen them all + ;;coq ; proofs-as-programs + ;;crystal ; ruby at the speed of c + ;;csharp ; unity, .NET, and mono shenanigans + ;;data ; config/data formats + ;;(dart +flutter) ; paint ui and not much else + ;;elixir ; erlang done right + ;;elm ; care for a cup of TEA? + emacs-lisp ; drown in parentheses + ;;erlang ; an elegant language for a more civilized age + ;;ess ; emacs speaks statistics + ;;faust ; dsp, but you get to keep your soul + ;;fsharp ; ML stands for Microsoft's Language + ;;fstar ; (dependent) types and (monadic) effects and Z3 + ;;gdscript ; the language you waited for + ;;(go +lsp) ; the hipster dialect + (haskell +dante) ; a language that's lazier than I am + ;;hy ; readability of scheme w/ speed of python + ;;idris ; + ;;json ; At least it ain't XML + ;;(java +meghanada) ; the poster child for carpal tunnel syndrome + ;;javascript ; all(hope(abandon(ye(who(enter(here)))))) + ;;julia ; a better, faster MATLAB + ;;kotlin ; a better, slicker Java(Script) + ;;latex ; writing papers in Emacs has never been so fun + ;;lean + ;;factor + ;;ledger ; an accounting system in Emacs + lua ; one-based indices? one-based indices + markdown ; writing docs for people to ignore + nim ; python + lisp at the speed of c + ;;nix ; I hereby declare "nix geht mehr!" + ;;ocaml ; an objective camel + org ; organize your plain life in plain text + ;;php ; perl's insecure younger brother + ;;plantuml ; diagrams for confusing people more + ;;purescript ; javascript, but functional + ;;python ; beautiful is better than ugly + ;;qt ; the 'cutest' gui framework ever + ;;racket ; a DSL for DSLs + ;;raku ; the artist formerly known as perl6 + ;;rest ; Emacs as a REST client + ;;rst ; ReST in peace + ;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"} + rust ; Fe2O3.unwrap().unwrap().unwrap().unwrap() + ;;scala ; java, but good + ;;scheme ; a fully conniving family of lisps + sh ; she sells {ba,z,fi}sh shells on the C xor + ;;sml + ;;solidity ; do you need a blockchain? No. + ;;swift ; who asked for emoji variables? + ;;terra ; Earth and Moon in alignment for performance. + ;;web ; the tubes + ;;yaml ; JSON, but readable + + :email + ;;(mu4e +gmail) + ;;notmuch + ;;(wanderlust +gmail) + + :app + ;;calendar + ;;irc ; how neckbeards socialize + ;;(rss +org) ; emacs as an RSS reader + ;;twitter ; twitter client https://twitter.com/vnought + + :config + ;;literate + (default +bindings +smartparens)) diff --git a/doom/packages.el b/doom/packages.el new file mode 100644 index 0000000..b80e9cc --- /dev/null +++ b/doom/packages.el @@ -0,0 +1,50 @@ +;; -*- no-byte-compile: t; -*- +;;; $DOOMDIR/packages.el + +;; To install a package with Doom you must declare them here and run 'doom sync' +;; on the command line, then restart Emacs for the changes to take effect -- or +;; use 'M-x doom/reload'. + + +;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror: +;(package! some-package) + +;; To install a package directly from a remote git repo, you must specify a +;; `:recipe'. You'll find documentation on what `:recipe' accepts here: +;; https://github.com/raxod502/straight.el#the-recipe-format +;(package! another-package +; :recipe (:host github :repo "username/repo")) + +;; If the package you are trying to install does not contain a PACKAGENAME.el +;; file, or is located in a subdirectory of the repo, you'll need to specify +;; `:files' in the `:recipe': +;(package! this-package +; :recipe (:host github :repo "username/repo" +; :files ("some-file.el" "src/lisp/*.el"))) + +;; If you'd like to disable a package included with Doom, you can do so here +;; with the `:disable' property: +;(package! builtin-package :disable t) + +;; You can override the recipe of a built in package without having to specify +;; all the properties for `:recipe'. These will inherit the rest of its recipe +;; from Doom or MELPA/ELPA/Emacsmirror: +;(package! builtin-package :recipe (:nonrecursive t)) +;(package! builtin-package-2 :recipe (:repo "myfork/package")) + +;; Specify a `:branch' to install a package from a particular branch or tag. +;; This is required for some packages whose default branch isn't 'master' (which +;; our package manager can't deal with; see raxod502/straight.el#279) +;(package! builtin-package :recipe (:branch "develop")) + +;; Use `:pin' to specify a particular commit to install. +;(package! builtin-package :pin "1a2b3c4d5e") + + +;; Doom's packages are pinned to a specific commit and updated from release to +;; release. The `unpin!' macro allows you to unpin single packages... +;(unpin! pinned-package) +;; ...or multiple packages +;(unpin! pinned-package another-pinned-package) +;; ...Or *all* packages (NOT RECOMMENDED; will likely break things) +;(unpin! t) diff --git a/dunst/dunstrc b/dunst/dunstrc new file mode 100644 index 0000000..7d8963b --- /dev/null +++ b/dunst/dunstrc @@ -0,0 +1,418 @@ +[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 = "0x0-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 = 10 + + # 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 = frame + + # 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 8 + + # 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: + # bold + # italic + # strikethrough + # underline + # + # For a complete reference see + # . + # + # 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 = "%s\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 = 24 + + # 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 = /usr/bin/firefox -new-tab + + # 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 = 0 + + ### 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 = do_action + mouse_right_click = close_all + +# 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" + +[play_sound] + summary = "*" + script = notify-sound.sh + +# vim: ft=cfg diff --git a/dwm/autostart.sh b/dwm/autostart.sh new file mode 100755 index 0000000..000d580 --- /dev/null +++ b/dwm/autostart.sh @@ -0,0 +1,3 @@ +#!/bin/sh +sh -c ~/.config/autostart.sh +pgrep -x dwmblocks >/dev/null || dwmblocks diff --git a/dwm/autostart_blocking.sh b/dwm/autostart_blocking.sh new file mode 100755 index 0000000..3927441 --- /dev/null +++ b/dwm/autostart_blocking.sh @@ -0,0 +1,2 @@ +#!/bin/sh +sh -c ~/.xprofile & disown diff --git a/ff_enterprise_policy.zip b/ff_enterprise_policy.zip new file mode 100644 index 0000000..a2fc6d9 Binary files /dev/null and b/ff_enterprise_policy.zip differ diff --git a/firejail/disable-exec.local b/firejail/disable-exec.local new file mode 100644 index 0000000..3162dc1 --- /dev/null +++ b/firejail/disable-exec.local @@ -0,0 +1 @@ +ignore noexec ${HOME} diff --git a/firejail/dolphin-emu.local b/firejail/dolphin-emu.local new file mode 100644 index 0000000..43c8046 --- /dev/null +++ b/firejail/dolphin-emu.local @@ -0,0 +1,4 @@ +noblacklist ${HOME}/roms + +mkdir ${HOME}/roms +whitelist ${HOME}/roms diff --git a/firejail/librewolf.local b/firejail/librewolf.local new file mode 100644 index 0000000..cede7d2 --- /dev/null +++ b/firejail/librewolf.local @@ -0,0 +1,4 @@ +noblacklist ${HOME}/dwhelper + +mkdir ${HOME}/dwhelper +whitelist ${HOME}/dwhelper diff --git a/firejail/lynx.local b/firejail/lynx.local new file mode 100644 index 0000000..acdd06c --- /dev/null +++ b/firejail/lynx.local @@ -0,0 +1,3 @@ +noblacklist /tmp/neomutt.html + +whitelist /tmp/neomutt.html diff --git a/firejail/mpv.local b/firejail/mpv.local new file mode 100644 index 0000000..b6915f0 --- /dev/null +++ b/firejail/mpv.local @@ -0,0 +1,3 @@ +whitelist ${HOME}/videos +whitelist ${HOME}/Videos +whitelist ${HOME}/Media diff --git a/firejail/neomutt.local b/firejail/neomutt.local new file mode 100644 index 0000000..ce84d3f --- /dev/null +++ b/firejail/neomutt.local @@ -0,0 +1,24 @@ +noblacklist ${HOME}/.mbsyncrc +noblacklist ${HOME}/.local/scripts +noblacklist ${HOME}/.local/share/mail +noblacklist ${HOME}/.local/share/pass +noblacklist ${HOME}/.local/share/gnupg +noblacklist /etc/ld.so.preload +noblacklist /etc/lynx.cfg +noblacklist /etc/ssl/certs/ca-certificates.crt +noblacklist /usr/share/mutt-wizard + +mkdir ${HOME}/.local/share/mail +mkdir ${HOME}/.local/share/pass +mkdir ${HOME}/.local/share/gnupg +whitelist ${HOME}/.mbsyncrc +whitelist ${HOME}/.local/scripts +whitelist ${HOME}/.local/share/mail +whitelist ${HOME}/.local/share/pass +whitelist ${HOME}/.local/share/gnupg +whitelist /etc/ld.so.preload +whitelist /etc/lynx.cfg +whitelist /etc/ssl/certs/ca-certificates.crt +whitelist /usr/share/mutt-wizard + +ignore apparmor diff --git a/firejail/nextcloud.local b/firejail/nextcloud.local new file mode 100644 index 0000000..94f4aec --- /dev/null +++ b/firejail/nextcloud.local @@ -0,0 +1,4 @@ +noblacklist ${HOME}/nc + +mkdir ${HOME}/nc +whitelist ${HOME}/nc diff --git a/firejail/qutebrowser.local b/firejail/qutebrowser.local new file mode 100644 index 0000000..82a6106 --- /dev/null +++ b/firejail/qutebrowser.local @@ -0,0 +1,4 @@ +noblacklist ${HOME}/.local/share/qutebrowser-profiles + +mkdir ${HOME}/.local/share/qutebrowser-profiles +whitelist ${HOME}/.local/share/qutebrowser-profiles diff --git a/firejail/steam.local b/firejail/steam.local new file mode 100644 index 0000000..33c6b88 --- /dev/null +++ b/firejail/steam.local @@ -0,0 +1,2 @@ +seccomp !ptrace,!mount,!name_to_handle_at,!pivot_root,!umount2,!chroot +ignore seccomp diff --git a/ghostwriter/ghostwriter.conf b/ghostwriter/ghostwriter.conf new file mode 100644 index 0000000..b0789b2 --- /dev/null +++ b/ghostwriter/ghostwriter.conf @@ -0,0 +1,68 @@ +[Application] +locale=en_US + +[Export] +lastUsedExporter=Sundown +smartTypographyEnabled=true + +[FileHistory] +1\cursorPosition=5268 +1\filePath=/home/zachir/Documents/Aquaria/chapter1.md +size=1 + +[HUD] +alternateRowColors=false +cheatSheetHudGeometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\xc8\0\0\0\xc8\0\0\x1\xc1\0\0\x2W\0\0\0\xc8\0\0\0\xc8\0\0\x1\xc1\0\0\x2W\0\0\0\0\0\0\0\0\a\x80\0\0\0\xc8\0\0\0\xc8\0\0\x1\xc1\0\0\x2W) +cheatSheetHudOpen=false +desktopCompositingEnabled=true +documentStatisticsHudGeometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\xc8\0\0\0\xc8\0\0\x1\xc1\0\0\x2W\0\0\0\xc8\0\0\0\xc8\0\0\x1\xc1\0\0\x2W\0\0\0\0\0\0\0\0\a\x80\0\0\0\xc8\0\0\0\xc8\0\0\x1\xc1\0\0\x2W) +documentStatisticsHudOpen=false +opacity=200 +outlineHudGeometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\xc8\0\0\0\xc8\0\0\x1\xc1\0\0\x2W\0\0\0\xc8\0\0\0\xc8\0\0\x1\xc1\0\0\x2W\0\0\0\0\0\0\0\0\a\x80\0\0\0\xc8\0\0\0\xc8\0\0\x1\xc1\0\0\x2W) +outlineHudOpen=false +sessionStatisticsHudGeometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\xc8\0\0\0\xc8\0\0\x1\xc1\0\0\x2W\0\0\0\xc8\0\0\0\xc8\0\0\x1\xc1\0\0\x2W\0\0\0\0\0\0\0\0\a\x80\0\0\0\xc8\0\0\0\xc8\0\0\x1\xc1\0\0\x2W) +sessionStatisticsHudOpen=false +windowButtonLayout=0 + +[Preview] +customStyleSheets=@Invalid() +htmlPreviewOpen=false +lastUsedExporter=Sundown +lastUsedStyleSheet=:/resources/github-dark.css + +[Save] +autoSave=true +backupFile=true +rememberFileHistory=true + +[Spelling] +liveSpellCheck=true +locale=en_US + +[Style] +blockquoteStyle=0 +displayTimeInFullScreen=true +editorWidth=1 +focusMode=1 +font="DejaVu Sans Mono,12,-1,5,50,0,0,0,0,0" +hideHudsOnPreviewEnabled=false +hideHudsWhenTypingEnabled=false +hideMenuBarInFullScreenEnabled=true +highlightLineBreaks=false +interfaceStyle=1 +largeHeadings=true +theme=Classic Dark +underlineInsteadOfItalics=false + +[Tabs] +insertSpacesForTabs=false +tabWidth=4 + +[Typing] +autoMatchEnabled=true +autoMatchFilter=\"'([{*_`< +bulletPointCyclingEnabled=true + +[Window] +mainWindowGeometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\x10\0\0\a\x7f\0\0\x4\x37\0\0\0\0\0\0\0\x10\0\0\a\x7f\0\0\x4\x37\0\0\0\0\0\0\0\0\a\x80\0\0\0\0\0\0\0\x10\0\0\a\x7f\0\0\x4\x37) +mainWindowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\0\0\0\a\x80\0\0\x3\xf1\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\0) diff --git a/gtk-2.0/gtkfilechooser.ini b/gtk-2.0/gtkfilechooser.ini new file mode 100644 index 0000000..62930e9 --- /dev/null +++ b/gtk-2.0/gtkfilechooser.ini @@ -0,0 +1,11 @@ +[Filechooser Settings] +LocationMode=path-bar +ShowHidden=false +ShowSizeColumn=true +GeometryX=-1 +GeometryY=-1 +GeometryWidth=-1 +GeometryHeight=-1 +SortColumn=name +SortOrder=ascending +StartupMode=recent diff --git a/gtk-2.0/gtkrc b/gtk-2.0/gtkrc new file mode 100644 index 0000000..f0f7bf1 --- /dev/null +++ b/gtk-2.0/gtkrc @@ -0,0 +1,19 @@ +# DO NOT EDIT! This file will be overwritten by LXAppearance. +# Any customization should be done in ~/.gtkrc-2.0.mine instead. + +include "/home/zachir/.gtkrc-2.0.mine" +gtk-theme-name="Plata-Noir-Compact" +gtk-icon-theme-name="Paper-Mono-Dark" +gtk-font-name="Sans 10" +gtk-cursor-theme-name="Paper" +gtk-cursor-theme-size=0 +gtk-toolbar-style=GTK_TOOLBAR_BOTH +gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR +gtk-button-images=1 +gtk-menu-images=1 +gtk-enable-event-sounds=1 +gtk-enable-input-feedback-sounds=1 +gtk-xft-antialias=1 +gtk-xft-hinting=1 +gtk-xft-hintstyle="hintfull" +gtk-xft-rgba="rgb" diff --git a/gtk-3.0/gtk.css b/gtk-3.0/gtk.css new file mode 100644 index 0000000..bc747b9 --- /dev/null +++ b/gtk-3.0/gtk.css @@ -0,0 +1,12 @@ +.mate-panel-menu-bar button { + color: transparent; +} +panel-toplevel.background.horizontal, +.mate-panel-menu-bar, +#clock-applet-button, +#clock-applet-button:hover { + color: white; +} +#tasklist-button { + color: white; +} diff --git a/gtk-3.0/settings.ini b/gtk-3.0/settings.ini new file mode 100644 index 0000000..e2f0a04 --- /dev/null +++ b/gtk-3.0/settings.ini @@ -0,0 +1,16 @@ +[Settings] +gtk-theme-name=Sweet-mars-v40 +gtk-icon-theme-name=Paper-Mono-Dark +gtk-font-name=Sans 10 +gtk-cursor-theme-size=0 +gtk-toolbar-style=GTK_TOOLBAR_BOTH +gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR +gtk-button-images=1 +gtk-menu-images=1 +gtk-enable-event-sounds=1 +gtk-enable-input-feedback-sounds=1 +gtk-xft-antialias=1 +gtk-xft-hinting=1 +gtk-xft-hintstyle=hintmedium +gtk-xft-rgba=rgb +gtk-cursor-theme-name=Bibata-Modern-Classic diff --git a/herbstluftwm/README.md b/herbstluftwm/README.md new file mode 100644 index 0000000..e257a35 --- /dev/null +++ b/herbstluftwm/README.md @@ -0,0 +1,3 @@ +# Herbstluftwm Config + +My Herbstluftwm Config \ No newline at end of file diff --git a/herbstluftwm/autostart b/herbstluftwm/autostart new file mode 100755 index 0000000..3f53457 --- /dev/null +++ b/herbstluftwm/autostart @@ -0,0 +1,205 @@ +#!/usr/bin/bash + +# this is a simple config for herbstluftwm + +hc() { + herbstclient "$@" +} + +if [ -n "$XDG_CONFIG_HOME" ]; then + $XDG_CONFIG_HOME/X11/xprofile & + $XDG_CONFIG_HOME/autostart.sh & +else + $HOME/.config/X11/xprofile & + $HOME/.config/autostart.sh & +fi + +launch_polybar.sh herbstluft + +hc emit_hook reload + +# remove all existing keybindings +hc keyunbind --all + +hc pad 0 20 + +hc detect_monitors + +# keybindings +# if you have a super key you will be much happier with Mod set to Mod4 +Mod=Mod1 # Use alt as the main modifier +#Mod=Mod4 # Use the super key as the main modifier +TERMINAL=st + +hc keybind $Mod-Shift-e quit +hc keybind $Mod-Shift-r reload +hc keybind $Mod-Shift-q close +hc keybind $Mod-Return spawn $TERMINAL +hc keybind $Mod-Shift-Return spawn $TERMINAL +#hc keybind Super-l spawn i3lock-fancy +#hc keybind $Mod-m spawn mpcalbum.sh +#hc keybind $Mod-Shift-m spawn mpvlist.sh + +# scratchpads +hc keybind $Mod+Control+z spawn ~/.config/herbstluftwm/sphtop +hc keybind $Mod+Control+x spawn ~/.config/herbstluftwm/spterm +hc keybind $Mod+Control+c spawn ~/.config/herbstluftwm/sppmxr +hc keybind $Mod+Control+v spawn ~/.config/herbstluftwm/spblue +hc keybind $Mod+Control+b spawn ~/.config/herbstluftwm/spncmp +hc keybind $Mod+Control+a spawn ~/.config/herbstluftwm/spmutt +hc keybind $Mod+Control+s spawn ~/.config/herbstluftwm/spprof +hc keybind $Mod+Control+d spawn ~/.config/herbstluftwm/spirss +#hc keybind $Mod+Control+f spawn ~/.config/herbstluftwm/spmpv + +# minimize and unminimize +hc keybind $Mod+n jumpto last-minimized +hc keybind $Mod+Shift+n set_attr clients.focus.minimized toggle + +# basic movement +# focusing clients +hc keybind $Mod-h focus left +hc keybind $Mod-j focus down +hc keybind $Mod-k focus up +hc keybind $Mod-l focus right + +# moving clients +hc keybind $Mod-Shift-h shift left +hc keybind $Mod-Shift-j shift down +hc keybind $Mod-Shift-k shift up +hc keybind $Mod-Shift-l shift right + +# splitting frames +# create an empty frame at the specified direction +hc keybind $Mod-u split bottom 0.5 +hc keybind $Mod-o split right 0.5 +# let the current frame explode into subframes +hc keybind $Mod-Control-space split explode + +# resizing frames +resizestep=0.05 +hc keybind $Mod-Control-h resize left +$resizestep +hc keybind $Mod-Control-j resize down +$resizestep +hc keybind $Mod-Control-k resize up +$resizestep +hc keybind $Mod-Control-l resize right +$resizestep +hc keybind $Mod-Control-Left resize left +$resizestep +hc keybind $Mod-Control-Down resize down +$resizestep +hc keybind $Mod-Control-Up resize up +$resizestep +hc keybind $Mod-Control-Right resize right +$resizestep + +# tags +tag_names=( {1..9} ) +tag_keys=( {1..9} 0 ) + +hc rename default "${tag_names[0]}" || true +for i in ${!tag_names[@]} ; do + hc add "${tag_names[$i]}" + key="${tag_keys[$i]}" + if ! [ -z "$key" ] ; then + hc keybind "$Mod-$key" spawn hwinmv use_index $i + hc keybind "$Mod-Shift-$key" spawn hwinmv move_index "$i" + fi +done + +# cycle through tags +hc keybind $Mod-period use_index +1 --skip-visible +hc keybind $Mod-comma use_index -1 --skip-visible + +# layouting +hc keybind $Mod-e remove +hc keybind $Mod-Shift-f floating toggle +hc keybind $Mod-f fullscreen toggle +# The following cycles through the available layouts within a frame, but skips +# layouts, if the layout change wouldn't affect the actual window positions. +# I.e. if there are two windows within a frame, the grid layout is skipped. +hc keybind $Mod-space \ + or , and . compare tags.focus.curframe_wcount = 2 \ + . cycle_layout +1 vertical horizontal max vertical grid \ + , cycle_layout +1 + +# mouse +hc mouseunbind --all +hc mousebind $Mod-Button1 move +hc mousebind $Mod-Button2 zoom +hc mousebind $Mod-Button3 resize + +# focus +hc keybind $Mod-BackSpace cycle_monitor +hc keybind $Mod-Tab cycle_all +1 +hc keybind $Mod-Shift-Tab cycle_all -1 +hc keybind $Mod-c cycle +hc keybind $Mod-i jumpto urgent + +# theme +hc attr theme.tiling.reset 1 +hc attr theme.floating.reset 1 +hc set frame_border_active_color '#222222' +hc set frame_border_normal_color '#101010' +hc set frame_bg_normal_color '#565656' +hc set frame_bg_active_color '#345F0C' +hc set frame_border_width 1 +hc set always_show_frame 1 +hc set frame_bg_transparent 1 +hc set frame_transparent_width 5 +hc set frame_gap 4 +hc set hide_covered_windows on + +hc attr theme.active.color '#9fbc00' +hc attr theme.normal.color '#454545' +hc attr theme.urgent.color orange +hc attr theme.inner_width 1 +hc attr theme.inner_color black +hc attr theme.border_width 3 +hc attr theme.floating.border_width 4 +hc attr theme.floating.outer_width 1 +hc attr theme.floating.outer_color black +hc attr theme.active.inner_color '#3E4A00' +hc attr theme.active.outer_color '#3E4A00' +hc attr theme.background_color '#141414' + +hc set window_gap 0 +hc set frame_padding 0 +hc set smart_window_surroundings 0 +hc set smart_frame_surroundings 1 +hc set mouse_recenter_gap 0 +hc set focus_follows_mouse 1 + +# rules +hc unrule -F +#hc rule class=XTerm tag=3 # move all xterms to tag 3 +hc rule focus=on # normally focus new clients +#hc rule focus=off # normally do not focus new clients +# give focus to most common terminals +#hc rule class~'(.*[Rr]xvt.*|.*[Tt]erm|Konsole)' focus=on +hc rule windowtype~'_NET_WM_WINDOW_TYPE_(DIALOG|UTILITY|SPLASH)' pseudotile=on +hc rule windowtype='_NET_WM_WINDOW_TYPE_DIALOG' focus=on +hc rule windowtype~'_NET_WM_WINDOW_TYPE_(NOTIFICATION|DOCK|DESKTOP)' manage=off +# scratchpad rules +hc rule instance=sphtop floatplacement=center floating=true floating_geometry=900x600 +hc rule instance=spterm floatplacement=center floating=true floating_geometry=900x600 +hc rule instance=sppmxr floatplacement=center floating=true floating_geometry=900x600 +hc rule instance=spblue floatplacement=center floating=true floating_geometry=900x600 +hc rule instance=spncmp floatplacement=center floating=true floating_geometry=900x600 +hc rule instance=spmutt floatplacement=center floating=true floating_geometry=900x600 +hc rule class=spprof floatplacement=center floating=true floating_geometry=900x600 +hc rule class=spirss floatplacement=center floating=true floating_geometry=900x600 +#hc rule class=mpv floatplacement=center floating=true floating_geometry=900x600 + +hc set tree_style '╾│ ├└╼─┐' + +# unlock, just to be sure +hc unlock + +# do multi monitor setup here, e.g.: +# hc set_monitors 1280x1024+0+0 1280x1024+1280+0 +# or simply: +# hc detect_monitors + +# find the panel +#panel=~/.config/herbstluftwm/backup_panel.sh +#[ -x "$panel" ] || panel=/etc/xdg/herbstluftwm/panel.sh +#for monitor in $(herbstclient list_monitors | cut -d: -f1) ; do +# # start it on each monitor +# "$panel" $monitor & +#done + +sh tagmv 0 diff --git a/herbstluftwm/spblue b/herbstluftwm/spblue new file mode 100755 index 0000000..1f0c395 --- /dev/null +++ b/herbstluftwm/spblue @@ -0,0 +1,17 @@ +#!/bin/sh +scratchpad=/tmp/herbstluftwm:spblue +if xdotool search --onlyvisible --classname 'spblue'; then + if [ "`herbstclient list_monitors | grep '[FOCUS]' | cut -d\\\" -f2`" = "`herbstclient attr clients.$(cat $scratchpad) | grep 's - - tag' | awk '{ print $6 }' | sed 's/\"//g'`" ]; then + xdotool search -onlyvisible -classname 'spblue' windowunmap + exit + fi +fi +if [ -f $scratchpad ]; then + if ! herbstclient bring $(cat $scratchpad); then xdotool search -classname 'spblue' windowmap && exit + fi +fi +if ! xdotool search --classname 'spblue' windowmap; then + setsid -f st -t 'spblue' -n 'spblue' -- zsh -c bluetoothctl + xdotool search -sync -onlyvisible -classname 'spblue' + herbstclient attr clients.focus.winid > $scratchpad +fi diff --git a/herbstluftwm/sphtop b/herbstluftwm/sphtop new file mode 100755 index 0000000..2d55a9f --- /dev/null +++ b/herbstluftwm/sphtop @@ -0,0 +1,18 @@ +#!/bin/sh +scratchpad=/tmp/herbstluftwm:sphtop +if xdotool search --onlyvisible --classname 'sphtop'; then + if [ $(herbstclient list_monitors | grep '[FOCUS]' | cut -d\" -f2) = $(herbstclient attr clients.$(cat $scratchpad) | grep 's - - tag' | awk '{ print $6 }' | sed 's/"//g') ]; then + xdotool search -onlyvisible -classname 'sphtop' windowunmap + exit + fi +fi +if [ -f $scratchpad ]; then + if ! herbstclient bring $(cat $scratchpad); then + xdotool search -classname 'sphtop' windowmap && exit + fi +fi +if ! xdotool search --classname 'sphtop' windowmap; then + setsid -f st -t 'sphtop' -n 'sphtop' -- zsh -c htop + xdotool search -sync -onlyvisible -classname 'sphtop' + herbstclient attr clients.focus.winid > $scratchpad +fi diff --git a/herbstluftwm/spirss b/herbstluftwm/spirss new file mode 100755 index 0000000..eb67989 --- /dev/null +++ b/herbstluftwm/spirss @@ -0,0 +1,18 @@ +#!/bin/sh +scratchpad=/tmp/herbstluftwm:spirss +if xdotool search --class 'spirss'; then + if [ "$(herbstclient list_monitors | grep '[FOCUS]' | cut -d\" -f2)" = "$(herbstclient attr clients.$(cat $scratchpad) | grep 's - - tag' | awk '{ print $6 }' | sed 's/\"//g')" ]; then + xdotool search -class 'spirss' windowunmap + exit + fi +fi +if [ -f $scratchpad ]; then + if ! herbstclient bring $(cat $scratchpad); then + xdotool search -class 'spirss' windowmap && exit + fi +fi +if ! xdotool search -class 'spirss' windowmap; then + . ~/.profile && st -t 'spirss' -c 'spirss' -e irssi & + xdotool search -sync -onlyvisible -class 'spirss' + herbstclient attr clients.focus.winid > $scratchpad +fi diff --git a/herbstluftwm/spmpv b/herbstluftwm/spmpv new file mode 100755 index 0000000..76038ab --- /dev/null +++ b/herbstluftwm/spmpv @@ -0,0 +1,22 @@ +#!/bin/sh +scratchpad=/tmp/herbstluftwm:spmpv +if [ -f "$scratchpad" ]; then + if xdotool search -class 'mpv'; then + if [ "$(herbstclient list_monitors | grep '[FOCUS]' | cut -d\" -f2)" = "$(herbstclient attr clients.$(cat $scratchpad) | grep 's - - tag' | awk '{ print $6 }' | sed 's/\"//g')" ]; then + xdotool search -class 'mpv' windowunmap + exit + fi + fi + if ! herbstclient bring $(cat $scratchpad); then + xdotool search -class 'mpv' windowmap && exit + fi + if ! xdotool search -class 'mpv' windowmap; then + xdotool search -sync -onlyvisible -class 'mpv' + herbstclient attr clients.focus.winid > $scratchpad + fi +else + if ! xdotool search -class 'mpv' windowmap; then + xdotool search -sync -onlyvisible -class 'mpv' + herbstclient attr clients.focus.winid > $scratchpad + fi +fi diff --git a/herbstluftwm/spmutt b/herbstluftwm/spmutt new file mode 100755 index 0000000..510764e --- /dev/null +++ b/herbstluftwm/spmutt @@ -0,0 +1,18 @@ +#!/bin/sh +scratchpad=/tmp/herbstluftwm:spmutt +if xdotool search --onlyvisible --classname 'spmutt'; then + if [ $(herbstclient list_monitors | grep '[FOCUS]' | cut -d\" -f2) = $(herbstclient attr clients.$(cat $scratchpad) | grep 's - - tag' | awk '{ print $6 }' | sed 's/"//g') ]; then + xdotool search -onlyvisible -classname 'spmutt' windowunmap + exit + fi +fi +if [ -f $scratchpad ]; then + if ! herbstclient bring $(cat $scratchpad); then + xdotool search -classname 'spmutt' windowmap && exit + fi +fi +if ! xdotool search --classname 'spmutt' windowmap; then + setsid -f st -t 'spmutt' -n 'spmutt' -- zsh -c neomutt + xdotool search -sync -onlyvisible -classname 'spmutt' + herbstclient attr clients.focus.winid > $scratchpad +fi diff --git a/herbstluftwm/spncmp b/herbstluftwm/spncmp new file mode 100755 index 0000000..0ad5bec --- /dev/null +++ b/herbstluftwm/spncmp @@ -0,0 +1,18 @@ +#!/bin/sh +scratchpad=/tmp/herbstluftwm:spncmp +if xdotool search --onlyvisible --classname 'spncmp'; then + if [ $(herbstclient list_monitors | grep '[FOCUS]' | cut -d\" -f2) = $(herbstclient attr clients.$(cat $scratchpad) | grep 's - - tag' | awk '{ print $6 }' | sed 's/"//g') ]; then + xdotool search -onlyvisible -classname 'spncmp' windowunmap + exit + fi +fi +if [ -f $scratchpad ]; then + if ! herbstclient bring $(cat $scratchpad); then + xdotool search -classname 'spncmp' windowmap && exit + fi +fi +if ! xdotool search --classname 'spncmp' windowmap; then + setsid -f st -t 'spncmp' -n 'spncmp' -- zsh -c ncmpcpp + xdotool search -sync -onlyvisible -classname 'spncmp' + herbstclient attr clients.focus.winid > $scratchpad +fi diff --git a/herbstluftwm/sppmxr b/herbstluftwm/sppmxr new file mode 100755 index 0000000..7499312 --- /dev/null +++ b/herbstluftwm/sppmxr @@ -0,0 +1,18 @@ +#!/bin/sh +scratchpad=/tmp/herbstluftwm:sppmxr +if xdotool search --onlyvisible --classname 'sppmxr'; then + if [ $(herbstclient list_monitors | grep '[FOCUS]' | cut -d\" -f2) = $(herbstclient attr clients.$(cat $scratchpad) | grep 's - - tag' | awk '{ print $6 }' | sed 's/"//g') ]; then + xdotool search -onlyvisible -classname 'sppmxr' windowunmap + exit + fi +fi +if [ -f $scratchpad ]; then + if ! herbstclient bring $(cat $scratchpad); then + xdotool search -classname 'sppmxr' windowmap && exit + fi +fi +if ! xdotool search --classname 'sppmxr' windowmap; then + setsid -f st -t 'sppmxr' -n 'sppmxr' -- zsh -c pulsemixer + xdotool search -sync -onlyvisible -classname 'sppmxr' + herbstclient attr clients.focus.winid > $scratchpad +fi diff --git a/herbstluftwm/spprof b/herbstluftwm/spprof new file mode 100755 index 0000000..1a4dc40 --- /dev/null +++ b/herbstluftwm/spprof @@ -0,0 +1,18 @@ +#!/bin/sh +scratchpad=/tmp/herbstluftwm:spprof +if xdotool search --onlyvisible --class 'spprof'; then + if [ $(herbstclient list_monitors | grep '[FOCUS]' | cut -d\" -f2) = $(herbstclient attr clients.$(cat $scratchpad) | grep 's - - tag' | awk '{ print $6 }' | sed 's/"//g') ]; then + xdotool search -onlyvisible -class 'spprof' windowunmap + exit + fi +fi +if [ -f $scratchpad ]; then + if ! herbstclient bring $(cat $scratchpad); then + xdotool search -class 'spprof' windowmap && exit + fi +fi +if ! xdotool search --class 'spprof' windowmap; then + . ~/.profile && st -t 'spprof' -c 'spprof' -e profanity & + xdotool search -sync -onlyvisible -class 'spprof' + herbstclient attr clients.focus.winid > $scratchpad +fi diff --git a/herbstluftwm/spterm b/herbstluftwm/spterm new file mode 100755 index 0000000..67f4f60 --- /dev/null +++ b/herbstluftwm/spterm @@ -0,0 +1,18 @@ +#!/bin/sh +scratchpad=/tmp/herbstluftwm:spterm +if xdotool search --onlyvisible --classname 'spterm'; then + if [ $(herbstclient list_monitors | grep '[FOCUS]' | cut -d\" -f2) = $(herbstclient attr clients.$(cat $scratchpad) | grep 's - - tag' | awk '{ print $6 }' | sed 's/"//g') ]; then + xdotool search -onlyvisible -classname 'spterm' windowunmap + exit + fi +fi +if [ -f $scratchpad ]; then + if ! herbstclient bring $(cat $scratchpad); then + xdotool search -classname 'spterm' windowmap && exit + fi +fi +if ! xdotool search --classname 'spterm' windowmap; then + st -t ‘spterm’ -n 'spterm' & + xdotool search -sync -onlyvisible -classname 'spterm' + herbstclient attr clients.focus.winid > $scratchpad +fi diff --git a/installers/vimplug_nvim.sh b/installers/vimplug_nvim.sh new file mode 100755 index 0000000..feddd03 --- /dev/null +++ b/installers/vimplug_nvim.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +curl -fLo "${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/autoload/plug.vim --create-dirs \ + https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim diff --git a/installers/vimplug_vim.sh b/installers/vimplug_vim.sh new file mode 100755 index 0000000..7f32b3c --- /dev/null +++ b/installers/vimplug_vim.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ + https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim diff --git a/jellycli.yaml b/jellycli.yaml new file mode 100644 index 0000000..e69de29 diff --git a/jellycli/jellycli.yaml b/jellycli/jellycli.yaml new file mode 100644 index 0000000..e777549 --- /dev/null +++ b/jellycli/jellycli.yaml @@ -0,0 +1,38 @@ +gui: + debug_mode: false + double_click_ms: 220 + enable_filtering: false + enable_results_filtering: true + enable_sorting: false + limit_recently_played: true + mouse_enabled: true + pagesize: 100 + search_results_limit: 30 + search_types: + - Artist + - Album + - Song + - Playlist + volume_steps: 20 +jellyfin: + device_id: "" + music_view: "" + server_id: "" + token: "" + url: "" + userid: "" +player: + audio_buffering_ms: 150 + enable_local_cache: false + enable_remote_control: true + http_buffering_limit_mem: 20 + http_buffering_s: 5 + local_cache_dir: /home/zachir/.cache/jellycli + logfile: /tmp/jellycli.log + loglevel: info + server: jellyfin +subsonic: + salt: "" + token: "" + url: "" + username: "" diff --git a/kshrc b/kshrc new file mode 100644 index 0000000..cd372c4 --- /dev/null +++ b/kshrc @@ -0,0 +1,38 @@ +# zachir's ksh config + +[ -f /etc/ksh.kshrc ] && . /etc/ksh.kshrc + +[ -f $HOME/.config/sh/aliases ] && . $HOME/.config/sh/aliases +[ -f $HOME/.config/sh/functions ] && . $HOME/.config/sh/functions + +RED="\033[1;31m" +GRE="\033[1;32m" +YEL="\033[1;33m" +BLU="\033[1;34m" +PUR="\033[1;35m" +CYA="\033[1;36m" +CLR="\033[1;0m" + +[ -f "$XDG_CONFIG_HOME"/sh/aliases ] && . "$XDG_CONFIG_HOME"/sh/aliases +[ -f "$XDG_CONFIG_HOME"/sh/functions ] && . "$XDG_CONFIG_HOME"/sh/functions + +case "$-" in +*i*) # we are interactive + # we may have su'ed so reset these + HOSTNAME=${HOSTNAME:-$(uname -n)} + HOST=${HOSTNAME%%.*} + + #PROMPT="$USER:!$PS1S" + #PROMPT="<$USER@$HOST:!>$PS1S" + case "$USER" in + "root") COLOR='\e[1;31m' ;; + "git") COLOR='\e[1;32m' ;; + "zachir") COLOR='\e[1;36m' ;; + esac + PROMPT="$COLOR"'[\u@\h]:\e[0m\w'"$COLOR"'\$ \e[0m' + PS1=$PROMPT + + set -o vi + +;; +esac diff --git a/lf/3q b/lf/3q new file mode 100755 index 0000000..06ec272 --- /dev/null +++ b/lf/3q @@ -0,0 +1,2 @@ +#!/bin/sh +chafa "$1" diff --git a/lf/cleaner b/lf/cleaner new file mode 100755 index 0000000..a184d84 --- /dev/null +++ b/lf/cleaner @@ -0,0 +1,4 @@ +#!/bin/sh +if [ -n "$FIFO_UEBERZUG" ]; then + printf '{"action": "remove", "identifier": "PREVIEW"}\n' > "$FIFO_UEBERZUG" +fi diff --git a/lf/image b/lf/image new file mode 100755 index 0000000..77ddb5b --- /dev/null +++ b/lf/image @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +readonly ID_PREVIEW="preview" +main() { + case "$1" in + "clear") + declare -p -A cmd=([action]=remove [identifier]="$ID_PREVIEW") \ + > "$FIFO_UEBERZUG" + ;; + "draw") + declare -p -A cmd=([action]=add [identifier]="$ID_PREVIEW" \ + [x]="$3" [y]="$4" [max_width]="$5" [max_height]="$6" \ + [path]="$2") > "$FIFO_UEBERZUG" + ;; + "*") echo "Unknown command: '$1', '$2'" ;; + esac +} +main "$@" + diff --git a/lf/lfrc b/lf/lfrc new file mode 100644 index 0000000..37c9fc7 --- /dev/null +++ b/lf/lfrc @@ -0,0 +1,351 @@ +set ratios 1:2:3 +set cleaner ~/.config/lf/cleaner +set previewer ~/.config/lf/preview +# Basic Settings +set preview true +set drawbox false +set icons true +set ignorecase true + +# Custom Functions +cmd open ${{ + case $(file --mime-type "$f" -bL) in + text/*|application/json) $EDITOR "$f";; + video/*) mpv "$f";; + audio/*) mpv "$f";; + application/pdf) zathura "$f" ;; + image/*) sxiv "$f" ;; + *) xdg-open "$f" ;; + esac +}} + +cmd mkdir ${{ + printf "Directory Name: " + read ans + mkdir $ans +}} + +cmd mkfile ${{ + printf "File Name: " + read ans + $EDITOR $ans +}} + +cmd chmod ${{ + printf "Mode Bits: " + read ans + + for file in "$fx" + do + chmod $ans $file + done +}} + +cmd sudomkfile ${{ + printf "File Name: " + read ans + doas $EDITOR $ans +}} + +cmd setwallpaper %cp "$f" ~/background.jpg && xwallpaper --center "$f" + +cmd fzf_jump ${{ + res="$(find . -maxdepth 3 | fzf --reverse --header='Jump to location')" + if [ -f "$res" ]; then + cmd="select" + elif [ -d "$res" ]; then + cmd="cd" + fi + lf -remote "send $id $cmd \"$res\"" +}} + +cmd broot_jump ${{ + f=$(mktemp) + res="$(broot --outcmd $f && cat $f | sed 's/cd //')" + rm -f "$f" + if [ -f "$res" ]; then + cmd="select" + elif [ -d "$res" ]; then + cmd="cd" + fi + lf -remote "send $id $cmd \"$res\"" +}} + +cmd open_config ${{ + $EDITOR $(bookmenu -b ~/.config/bookmenu/configs -f fzf -o) +}} + +cmd dragon %dragon-drop -a -x $fx +cmd dragon-stay %dragon-drop -a $fx +cmd dragon-individual %dragon-drop $fx +cmd cpdragon %cpdragon +cmd mvdragon %mvdragon +cmd dlfile %dlfile + +# Archive bindings +cmd unarchive ${{ + case "$f" in + *.zip) unzip "$f" ;; + *.tar.gz) tar -xzvf "$f" ;; + *.tar.bz2) tar -xjvf "$f" ;; + *.tar.xz) tar -xJvf "$f" ;; + *.tar) tar -xvf "$f" ;; + *) echo "Unsupported format" ;; + esac +}} + +cmd gitpull ${{ + git pull + read dummy +}} + +cmd gitadd ${{ + git add $(basename $fx) +}} + +cmd gitaddall ${{ + git add . +}} + +cmd gitpush ${{ + git push + read dummy +}} + +cmd gitcommit ${{ + git commit -S +}} + +cmd gitdiff ${{ + git diff + read dummy +}} + +cmd gitdifffile ${{ + git diff `basename $fx` + read dummy +}} + +cmd gitstatus ${{ + git status | less +}} + +cmd gitrestore ${{ + git restore `basename $fx` + read dummy +}} + +cmd gitsubmoduleupdate ${{ + git submodule update + read dummy +}} + +cmd gitsubmoduleinit ${{ + git submodule update --init + read dummy +}} + +cmd gitsubmoduleadd ${{ + read url + read folder + git submodule add "$url" "$folder" + read dummy +}} + +cmd make ${{ + make -j4 all + read dummy +}} + +cmd makeinstall ${{ + sudo make -j4 install + read dummy +}} + +cmd makeclean ${{ + make -j4 clean + read dummy +}} + +cmd openshell ${{ + zsh +}} + +cmd catclip ${{ + catclip "$fx" +}} + +cmd zip %zip -r "$f" "$f" +cmd tar %tar cvf "$f.tar" "$f" +cmd targz %tar cvzf "$f.tar.gz" "$f" +cmd tarbz2 %tar cjvf "$f.tar.bz2" "$f" + +# Trash cli bindings +cmd trash ${{ + files=$(printf "$fx" | tr '\n' ';') + while [ "$files" ]; do + # extract the substring from start of string up to delimiter. + # this is the first "element" of the string. + file=${files%%;*} + + trash-put "$(basename "$file")" + # if there's only one element left, set `files` to an empty string. + # this causes us to exit this `while` loop. + # else, we delete the first "element" of the string from files, and move onto the next. + if [ "$files" = "$file" ]; then + files='' + else + files="${files#*;}" + fi + done +}} + +cmd clear_trash %trash-empty + +cmd restore_trash ${{ + trash-restore +}} + +cmd stripspace %stripspace "$f" + +# Bindings +# Remove some defaults +map m +map o +map n +map "'" +map '"' +map d +map c +map e +map f +map , + +# ZachIR bindings +map ,gp gitpull +map ,gP gitpush +map ,gc gitcommit +map ,ga gitadd +map ,gA gitaddall +map ,gd gitdifffile +map ,gD gitdiff +map ,gu gitsubmoduleupdate +map ,gi gitsubmoduleinit +map ,gm gitsubmoduleadd +map ,gs gitstatus +map ,gr gitrestore +map ,mk make +map ,mi makeinstall +map ,mC makeclean +map ,ss openshell +map ,sc catclip + + +# Not really image preview +map - $~/.config/lf/draw_img "$f" + +cmd video_preview ${{ + CACHE=$(mktemp /tmp/thumb_cache.XXXXX) + ffmpegthumbnailer -i "$f" -o $CACHE -s 0 + ~/.config/lf/draw_img $CACHE && rm $CACHE +}} +map + :video_preview + +# File Openers +map ee $$EDITOR "$f" +map u $view "$f" + +# Archive Mappings +map az zip +map at tar +map ag targz +map ab targz +map au unarchive + +# Trash Mappings +map dd trash +map tc clear_trash +map tr restore_trash + +# Broot Mapping +map f broot_jump + +# Dragon Mapping +map dr dragon +map ds dragon-stay +map di dragon-individual +map dm mvdragon +map dc cpdragon +map dl dlfile + +map ss stripspace + +# Basic Functions +map . set hidden! +map DD delete +map p paste +map x cut +map y copy +map open +map mf mkfile +map mr sudomkfile +map md mkdir +map ms $mkscript +map ch chmod +map bg setwallpaper +map o open_config +map br $vimv $fx +map r rename +map H top +map L bottom +map R reload +map C clear +map U unselect + +# Movement +map ga cd ~/.config/awesome +map gb cd ~/.local/bin +map gc cd ~/.config +map gdc cd ~/Documents +map gdo cd ~/Downloads +map gdw cd ~/suckless/dwm +map gdb cd ~/.local/src/dwmbar +map ge cd ~/Desktop +map gE cd /etc +map gf cd ~/.var/app +map glb cd ~/.local/bin +map glc cd ~/Games/cache +map gls cd ~/.local/share +map glf cd ~/.config/lf +map gnv cd ~/.config/nvim +map gns cd ~/.natvst +map gp cd ~/Pictures +map gqc cd ~/.config/qutebrowser +map gqp cd ~/.local/share/qutebrowser-profiles +map gqt cd ~/.config/qtile +map gre cd ~/.local/src +map grs cd /etc/runit/sv +map gsc cd ~/.local/scripts +map gsh cd ~/.config/sh +map gsl cd ~/.local/src/slock +map gss cd /etc/s6/sv +map gsx cd ~/.config/sxhkd +map gtr cd ~/.local/share/Trash/files +map gU. cd /usr +map gUs cd /usr/share +map gva cd ~/.var +map gVa cd /var +map gvi cd ~/Videos +map gvs cd ~/.vst +map gv3 cd ~/.vst3 +map gwa cd ~/git/wallpapers +map gwd cd ~/.local/share/wineprefixes/default +map gwD cd ~/.local/share/wineprefixes/default/drive_c/users/zachir/Downloads +map gwr cd ~/.local/share/wineprefixes +map gww cd ~/.local/share/wineprefixes/work +map gx cd ~/.config/X11 +map gyb cd ~/.cache/yay +map gyc cd ~/.config/yay +map gzs cd ~/.config/zsh +map gzx cd ~/Documents/zachir.xyz + diff --git a/lf/preview b/lf/preview new file mode 100755 index 0000000..4b70b2e --- /dev/null +++ b/lf/preview @@ -0,0 +1,83 @@ +#!/bin/sh + +image() { + if [ -n "$DISPLAY" ] && [ -z "$WAYLAND_DISPLAY" ]; then + printf '{"action": "add", "identifier": "PREVIEW", "x": "%s", "y": "%s", "width": "%s", "height": "%s", "scaler": "contain", "path": "%s"}\n' "$4" "$5" "$(($2-1))" "$(($3-1))" "$1" > "$FIFO_UEBERZUG" + exit 1 + else + chafa "$1" -s "$4x" + fi +} + +batorcat() { + file="$1" + shift + if command -v bat > /dev/null 2>&1 + then + bat --color=always --style=plain --pager=never "$file" "$@" + else + cat "$file" + fi +} + +CACHE="$HOME/.cache/lf/thumbnail.$(stat --printf '%n\0%i\0%F\0%s\0%W\0%Y' -- "$(readlink -f "$1")" | sha256sum | awk '{print $1}'))" + +case "$(printf "%s\n" "$(readlink -f "$1")" | awk '{print tolower($0)}')" in + *.tgz|*.tar.gz) tar tzf "$1" ;; + *.tar.bz2|*.tbz2) tar tjf "$1" ;; + *.tar.txz|*.txz) xz --list "$1" ;; + *.tar) tar tf "$1" ;; + *.zip|*.jar|*.war|*.ear|*.oxt) unzip -l "$1" ;; + *.rar) unrar l "$1" ;; + *.md) glow -s dark "$1" ;; + *.7z) 7z l "$1" ;; + *.[1-8]) man "$1" | col -b ;; + *.o) nm "$1";; + *.torrent) transmission-show "$1" ;; + *.iso) iso-info --no-header -l "$1" ;; + *.odt|*.ods|*.odp|*.sxw) odt2txt "$1" ;; + *.doc) catdoc "$1" ;; + *.docx) docx2txt "$1" - ;; + *.xml|*.html) w3m -dump "$1";; + *.xls|*.xlsx) + ssconvert --export-type=Gnumeric_stf:stf_csv "$1" "fd://1" | batorcat --language=csv + ;; + *.wav|*.mp3|*.flac|*.m4a|*.wma|*.ape|*.ac3|*.og[agx]|*.spx|*.opus|*.as[fx]|*.mka) + exiftool "$1" + ;; + *.pdf) + [ ! -f "${CACHE}.jpg" ] && \ + pdftoppm -jpeg -f 1 -singlefile "$1" "$CACHE" + image "${CACHE}.jpg" "$2" "$3" "$4" "$5" + ;; + *.epub) + [ ! -f "$CACHE" ] && \ + epub-thumbnailer "$1" "$CACHE" 1024 + image "$CACHE" "$2" "$3" "$4" "$5" + ;; + *.cbz|*.cbr|*.cbt) + [ ! -f "$CACHE" ] && \ + comicthumb "$1" "$CACHE" 1024 + image "$CACHE" "$2" "$3" "$4" "$5" + ;; + *.avi|*.mp4|*.wmv|*.dat|*.3gp|*.ogv|*.mkv|*.mpg|*.mpeg|*.vob|*.fl[icv]|*.m2v|*.mov|*.webm|*.ts|*.mts|*.m4v|*.r[am]|*.qt|*.divx) + [ ! -f "${CACHE}.jpg" ] && \ + ffmpegthumbnailer -i "$1" -o "${CACHE}.jpg" -s 0 -q 5 + image "${CACHE}.jpg" "$2" "$3" "$4" "$5" + ;; + *.bmp|*.jpg|*.jpeg|*.png|*.xpm|*.webp|*.gif|*.jfif) + image "$1" "$2" "$3" "$4" "$5" + ;; + *.svg) + [ ! -f "${CACHE}.jpg" ] && \ + convert "$1" "${CACHE}.jpg" + image "${CACHE}.jpg" "$2" "$3" "$4" "$5" + ;; + *.ino) + batorcat --language=cpp "$1" + ;; + *) + batorcat "$1" + ;; +esac +exit 0 diff --git a/lxqt/lxqt.conf b/lxqt/lxqt.conf new file mode 100644 index 0000000..1a15670 --- /dev/null +++ b/lxqt/lxqt.conf @@ -0,0 +1,3 @@ +[General] +__userfile__=true +icon_theme=oxygen diff --git a/mksh/mkshalias b/mksh/mkshalias new file mode 100644 index 0000000..c43e240 --- /dev/null +++ b/mksh/mkshalias @@ -0,0 +1,50 @@ +#!/bin/mksh +## CD Ups +alias ...='cd ../..' +alias ....='cd ../../..' +alias .....='cd ../../../..' +alias ......='cd ../../../../..' +alias .......='cd ../../../../../..' +alias ........='cd ../../../../../../..' + +## Base Utils +alias ls="ls -h --color='auto' --group-directories-first" +alias ll='ls -l' +alias la='ls -A' +alias lla='ls -la' +alias md='mkdir -p' +alias ch='cd $HOME' +alias exa='exa --group-directories-first -a' +alias exla='exa -l' + +## Change utils +alias rm='rm -i' +alias cp='cp -i' + +## git stuff +alias gs='git status' +alias commit='git commit -S -m' +alias ga='git add -A' + +## Internet +alias weather='curl http://wttr.in/Pearland' + +## Single Chars +alias r='cd ~ && clear && exec zsh' +alias e='source $ENV' +alias i='sudo ~/scripts/install.sh' +alias q='exit' +alias c='clear' +alias m='make' + +## SSH +alias sshz='ssh zachir@therealir.xyz' + +## Programming +# Rust +alias crr='cargo run --release' +alias cbr='cargo build --release' + +## Arch Linux aliases --sudoloop +#alias yay='yay --sudo doas' +alias yu='yay -Syu --noconfirm' diff --git a/mksh/mkshfunc b/mksh/mkshfunc new file mode 100644 index 0000000..adb6a91 --- /dev/null +++ b/mksh/mkshfunc @@ -0,0 +1,58 @@ +#!/bin/mksh +catclip () { + cat "$@" | xclip -selection clipboard +} + +catpass () { + PASSWD=$(cat ~/pass.txt); echo "$PASSWD\n$PASSWD" | pass insert "$1"; unset PASSWD +} + +sigdwmblocks () { + pkill -RTMIN+$(grep "$1" ~/git/dwmblocks/config.h | awk '{print $4}' | cut -d'}' -f1) dwmblocks +} + +mkcd () { + mkdir $@ && cd $1 +} + +sc () { + if [ "$1" = "" ]; then + cd $HOME + else + case "$1" in + "-l") echo " +a - ~/.config/awesome +cpr- ~/.config/primrose +db - ~/git/dwmbar +dwm- ~/suckless/dwm +g - ~/git +pr - ~/git/primrose +s - ~/.local/scripts +slo- ~/suckless/slock +st - ~/suckless/st +tfd- ~/Documents/fllixel/TheFiniteDemo +tst- !tabbed -c st -w +v - ~/.vst +vsv- ~/.local/volsv +z - ~/.config/zsh +zx - ~/Documents/zachir.xyz +";; + "a") cd $XDG_CONFIG_HOME/awesome/ ;; + "cpr") cd $XDG_CONFIG_HOME/primrose/ ;; + "dwm") cd $HOME/suckless/dwm/ ;; + "db") cd $HOME/git/dwmbar/ ;; + "g") cd $HOME/git/ ;; + "pr") cd $HOME/git/primrose/ ;; + "slo") cd $HOME/suckless/slock/ ;; + "s") cd $HOME/.local/scripts/ ;; + "st") cd $HOME/suckless/st/ ;; + "tfd") cd $HOME/Documents/flixel/TheFiniteDemo/ ;; + "tst") tabbed -c st -w ;; + "v") cd $HOME/.vst/ ;; + "vsv") cd $HOME/.local/volsv ;; + "z") cd $ZDOTDIR/ ;; + "zx") cd $HOME/Documents/zachir.xyz/ ;; + *) cd $1 ;; + esac + fi +} diff --git a/mksh/mkshrc b/mksh/mkshrc new file mode 100644 index 0000000..5b61ae3 --- /dev/null +++ b/mksh/mkshrc @@ -0,0 +1,684 @@ +# $Id$ +# $MirOS: src/bin/mksh/dot.mkshrc,v 1.128 2020/04/13 18:39:03 tg Exp $ +#- +# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, +# 2020 +# mirabilos +# +# Provided that these terms and disclaimer and all copyright notices +# are retained or reproduced in an accompanying document, permission +# is granted to deal in this work without restriction, including un- +# limited rights to use, publicly perform, distribute, sell, modify, +# merge, give away, or sublicence. +# +# This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to +# the utmost extent permitted by applicable law, neither express nor +# implied; without malicious intent or gross negligence. In no event +# may a licensor, author or contributor be held liable for indirect, +# direct, other damage, loss, or other issues arising in any way out +# of dealing in the work, even if advised of the possibility of such +# damage or existence of a defect, except proven that it results out +# of said person's immediate fault when using the work as intended. +#- +# ${ENV:-~/.mkshrc}: mksh initialisation file for interactive shells + +# catch non-mksh, non-lksh, trying to run this file +case ${KSH_VERSION:-} in +*LEGACY\ KSH*|*MIRBSD\ KSH*) ;; +*) \return 0 ;; +esac + +# give MidnightBSD's laffer1 a bit of csh feeling +function setenv { + if (( $# )); then + \\builtin eval '\\builtin export "$1"="${2:-}"' + else + \\builtin typeset -x + fi +} + +# pager (not control character safe) +smores() ( + \\builtin set +m + \\builtin cat "$@" |& + \\builtin trap "rv=\$?; \\\\builtin kill $! >/dev/null 2>&1; \\\\builtin exit \$rv" EXIT + while IFS= \\builtin read -pr line; do + llen=${%line} + (( llen == -1 )) && llen=${#line} + (( llen = llen ? (llen + COLUMNS - 1) / COLUMNS : 1 )) + if (( (curlin += llen) >= LINES )); then + \\builtin print -nr -- $'\e[7m--more--\e[0m' + \\builtin read -u1 || \\builtin exit $? + [[ $REPLY = [Qq]* ]] && \\builtin exit 0 + curlin=$llen + fi + \\builtin print -r -- "$line" + done +) + +# customise your favourite editor here; the first one found is used +for EDITOR in "${EDITOR:-}" jupp jstar mcedit ed vi; do + EDITOR=$(\\builtin whence -p "$EDITOR") || EDITOR= + [[ -n $EDITOR && -x $EDITOR ]] && break + EDITOR=nvim +done + +\\builtin alias ls=ls l='ls -F' la='l -a' ll='l -l' lo='l -alo' +\: "${EDITOR:=/bin/ed}${TERM:=vt100}${USER:=$(\\builtin ulimit -c 0; id -un \ + 2>/dev/null)}${HOSTNAME:=$(\\builtin ulimit -c 0; hostname 2>/dev/null)}" +[[ $HOSTNAME = ?(?(ip6-)localhost?(6)) ]] && HOSTNAME=nil; \\builtin unalias ls +\\builtin export EDITOR HOSTNAME TERM USER="${USER:-?}" + +# minimal support for lksh users +if [[ $KSH_VERSION = *LEGACY\ KSH* ]]; then + PS1='$USER@${HOSTNAME%%.*}:$PWD>' + \\builtin return 0 +else + PS1='$(print -n "\E[1;32m[`logname`@`hostname`]:\E[1;37m";if [ "${PWD#$HOME}" = "$PWD" ]; then print -n "$PWD"; else print -n "~${PWD#$HOME}"; fi; print "\E[1;32m$\E[0m ")' +fi + +# mksh-specific from here +\: "${MKSH:=$(\\builtin whence -p mksh)}${MKSH:=/bin/mksh}" +\\builtin export MKSH + +# prompts +#PS4='[$EPOCHREALTIME] '; PS1='#'; (( USER_ID )) && PS1='$'; PS1=$'\001\r''${| +# \\builtin typeset e=$? +# +# (( e )) && REPLY+="$e|" +# REPLY+=${USER}@${HOSTNAME%%.*}: +# +# \\builtin typeset d=${PWD:-?}/ p=~; [[ $p = ?(*/) ]] || d=${d/#$p\//\~/} +# d=${d%/}; \\builtin typeset m=${%d} n p=...; (( m > 0 )) || m=${#d} +# (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p= +# REPLY+=$p$d +# +# \\builtin return $e +#} '"$PS1 " + +# utilities +\\builtin alias doch='sudo mksh -c "$(\\builtin fc -ln -1)"' +\\builtin command -v rot13 >/dev/null || \\builtin alias rot13='tr \ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \ + nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM' +if \\builtin command -v hd >/dev/null; then + \: +elif \\builtin command -v hexdump >/dev/null; then + function hd { + hexdump -e '"%08.8_ax " 8/1 "%02X " " - " 8/1 "%02X "' \ + -e '" |" "%_p"' -e '"|\n"' "$@" + } +else + function hd { + \\builtin cat "$@" | hd_mksh + } +fi + +# NUL-safe and EBCDIC-safe hexdump (from stdin) +function hd_mksh { + \\builtin typeset -Uui16 -Z11 pos=0 + \\builtin typeset -Uui16 -Z5 hv=2147483647 + \\builtin typeset dasc dn line i + \\builtin set +U + + while \\builtin read -arn 512 line; do + \\builtin typeset -i1 'line[*]' + i=0 + while (( i < ${#line[*]} )); do + dn= + (( (hv = line[i++]) != 0 )) && dn=${line[i-1]#1#} + if (( (pos & 15) == 0 )); then + (( pos )) && \ + \\builtin print -r -- "$dasc|" + \\builtin print -nr "${pos#16#} " + dasc=' |' + fi + \\builtin print -nr "${hv#16#} " + if [[ $dn = [[:print:]] ]]; then + dasc+=$dn + else + dasc+=. + fi + (( (pos++ & 15) == 7 )) && \ + \\builtin print -nr -- '- ' + done + done + while (( pos & 15 )); do + \\builtin print -nr ' ' + (( (pos++ & 15) == 7 )) && \ + \\builtin print -nr -- '- ' + done + (( hv == 2147483647 )) || \\builtin print -r -- "$dasc|" +} + +function which { + \\builtin typeset p x c + \\builtin typeset -i a=0 rv=2 e + \\builtin set +e + \\builtin set -o noglob + + while \\builtin getopts "a" x; do + case $x { + (a) a=1 ;; + (+a) a=0 ;; + (*) \\builtin print -ru2 'Usage: which [-a] name [...]' + \\builtin return 255 ;; + } + done + \\builtin shift $((OPTIND - 1)) + + # vvvvvvvvvvvvvvvvvvvv should be def_path + p=${PATH-/usr/bin$PATHSEP/bin} + # ^ no colon! + + # trailing PATHSEP vs field splitting + [[ $p = *"$PATHSEP" ]] && p+=. + + IFS=$PATHSEP + \\builtin set -A p -- ${p:-.} + IFS=$' \t\n' + + for x in "$@"; do + if (( !a )) || [[ $x = */* ]]; then + \\builtin whence -p -- "$x" + e=$? + else + e=1 + for c in "${p[@]}"; do + PATH=${c:-.} \\builtin whence -p -- "$x" && e=0 + done + fi + (( rv = (e == 0) ? (rv & ~2) : (rv == 2 ? 2 : 1) )) + done + \\builtin return $rv +} + +# Berkeley C shell compatible dirs, popd, and pushd functions +# Z shell compatible chpwd() hook, used to update DIRSTACK[0] +DIRSTACKBASE=$(\\builtin realpath ~/. 2>/dev/null || \ + \\builtin print -nr -- "${HOME:-/}") +\\builtin set -A DIRSTACK +function chpwd { + DIRSTACK[0]=$(\\builtin realpath . 2>/dev/null || \ + \\builtin print -nr -- "$PWD") + [[ $DIRSTACKBASE = ?(*/) ]] || \ + DIRSTACK[0]=${DIRSTACK[0]/#$DIRSTACKBASE/\~} + \: +} +\chpwd . +cd() { + \\builtin cd "$@" || \\builtin return $? + \chpwd "$@" +} +function cd_csh { + \\builtin typeset d t=${1/#\~/$DIRSTACKBASE} + + if ! d=$(\\builtin cd "$t" 2>&1); then + \\builtin print -ru2 "${1}: ${d##*cd: $t: }." + \\builtin return 1 + fi + \cd "$t" +} +function dirs { + \\builtin typeset d dwidth + \\builtin typeset -i fl=0 fv=0 fn=0 cpos=0 + + while \\builtin getopts ":lvn" d; do + case $d { + (l) fl=1 ;; + (v) fv=1 ;; + (n) fn=1 ;; + (*) \\builtin print -ru2 'Usage: dirs [-lvn].' + \\builtin return 1 ;; + } + done + \\builtin shift $((OPTIND - 1)) + if (( $# > 0 )); then + \\builtin print -ru2 'Usage: dirs [-lvn].' + \\builtin return 1 + fi + if (( fv )); then + fv=0 + while (( fv < ${#DIRSTACK[*]} )); do + d=${DIRSTACK[fv]} + (( fl )) && d=${d/#\~/$DIRSTACKBASE} + \\builtin print -r -- "$fv $d" + (( ++fv )) + done + else + fv=0 + while (( fv < ${#DIRSTACK[*]} )); do + d=${DIRSTACK[fv]} + (( fl )) && d=${d/#\~/$DIRSTACKBASE} + (( dwidth = (${%d} > 0 ? ${%d} : ${#d}) )) + if (( fn && (cpos += dwidth + 1) >= 79 && \ + dwidth < 80 )); then + \\builtin print + (( cpos = dwidth + 1 )) + fi + \\builtin print -nr -- "$d " + (( ++fv )) + done + \\builtin print + fi + \\builtin return 0 +} +function popd { + \\builtin typeset d fa + \\builtin typeset -i n=1 + + while \\builtin getopts ":0123456789lvn" d; do + case $d { + (l|v|n) fa+=" -$d" ;; + (+*) n=2 + \\builtin break ;; + (*) \\builtin print -ru2 'Usage: popd [-lvn] [+].' + \\builtin return 1 ;; + } + done + \\builtin shift $((OPTIND - n)) + n=0 + if (( $# > 1 )); then + \\builtin print -ru2 popd: Too many arguments. + \\builtin return 1 + elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then + if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then + \\builtin print -ru2 popd: Directory stack not that deep. + \\builtin return 1 + fi + elif [[ -n $1 ]]; then + \\builtin print -ru2 popd: Bad directory. + \\builtin return 1 + fi + if (( ${#DIRSTACK[*]} < 2 )); then + \\builtin print -ru2 popd: Directory stack empty. + \\builtin return 1 + fi + \\builtin unset DIRSTACK[n] + \\builtin set -A DIRSTACK -- "${DIRSTACK[@]}" + \cd_csh "${DIRSTACK[0]}" || \\builtin return 1 + \dirs $fa +} +function pushd { + \\builtin typeset d fa + \\builtin typeset -i n=1 + + while \\builtin getopts ":0123456789lvn" d; do + case $d { + (l|v|n) fa+=" -$d" ;; + (+*) n=2 + \\builtin break ;; + (*) \\builtin print -ru2 'Usage: pushd [-lvn] [|+].' + \\builtin return 1 ;; + } + done + \\builtin shift $((OPTIND - n)) + if (( $# == 0 )); then + if (( ${#DIRSTACK[*]} < 2 )); then + \\builtin print -ru2 pushd: No other directory. + \\builtin return 1 + fi + d=${DIRSTACK[1]} + DIRSTACK[1]=${DIRSTACK[0]} + \cd_csh "$d" || \\builtin return 1 + elif (( $# > 1 )); then + \\builtin print -ru2 pushd: Too many arguments. + \\builtin return 1 + elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then + if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then + \\builtin print -ru2 pushd: Directory stack not that deep. + \\builtin return 1 + fi + while (( n-- )); do + d=${DIRSTACK[0]} + \\builtin unset DIRSTACK[0] + \\builtin set -A DIRSTACK -- "${DIRSTACK[@]}" "$d" + done + \cd_csh "${DIRSTACK[0]}" || \\builtin return 1 + else + \\builtin set -A DIRSTACK -- placeholder "${DIRSTACK[@]}" + \cd_csh "$1" || \\builtin return 1 + fi + \dirs $fa +} + +# base64 encoder and decoder, RFC compliant, NUL safe, not EBCDIC safe +function Lb64decode { + \\builtin set +U + \\builtin typeset c s="$*" t + [[ -n $s ]] || { s=$(\\builtin cat; \\builtin print x); s=${s%x}; } + \\builtin typeset -i i=0 j=0 n=${#s} p=0 v x + \\builtin typeset -i16 o + + while (( i < n )); do + c=${s:(i++):1} + case $c { + (=) \\builtin break ;; + ([A-Z]) (( v = 1#$c - 65 )) ;; + ([a-z]) (( v = 1#$c - 71 )) ;; + ([0-9]) (( v = 1#$c + 4 )) ;; + (+) v=62 ;; + (/) v=63 ;; + (*) \\builtin continue ;; + } + (( x = (x << 6) | v )) + case $((p++)) { + (0) \\builtin continue ;; + (1) (( o = (x >> 4) & 255 )) ;; + (2) (( o = (x >> 2) & 255 )) ;; + (3) (( o = x & 255 )) + p=0 + ;; + } + t+=\\x${o#16#} + (( ++j & 4095 )) && \\builtin continue + \\builtin print -n $t + t= + done + \\builtin print -n $t +} +function Lb64encode { + \\builtin set +U + \\builtin typeset c s t table + \\builtin set -A table -- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \ + a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + / + if (( $# )); then + \\builtin read -raN-1 s <<<"$*" + \\builtin unset s[${#s[*]}-1] + else + \\builtin read -raN-1 s + fi + \\builtin typeset -i i=0 n=${#s[*]} v + + while (( i < n )); do + (( v = s[i++] << 16 )) + (( v |= s[i++] << 8 )) + (( v |= s[i++] )) + t+=${table[v >> 18]}${table[v >> 12 & 63]} + c=${table[v >> 6 & 63]} + if (( i <= n )); then + t+=$c${table[v & 63]} + elif (( i == n + 1 )); then + t+=$c= + else + t+=== + fi + if (( ${#t} == 76 || i >= n )); then + \\builtin print -r $t + t= + fi + done +} + +# Better Avalanche for the Jenkins Hash +\\builtin typeset -Z11 -Uui16 Lbafh_v +function Lbafh_init { + Lbafh_v=0 +} +function Lbafh_add { + \\builtin set +U + \\builtin typeset s + if (( $# )); then + \\builtin read -raN-1 s <<<"$*" + \\builtin unset s[${#s[*]}-1] + else + \\builtin read -raN-1 s + fi + \\builtin typeset -i i=0 n=${#s[*]} + + while (( i < n )); do + ((# Lbafh_v = (Lbafh_v + s[i++] + 1) * 1025 )) + ((# Lbafh_v ^= Lbafh_v >> 6 )) + done +} +function Lbafh_finish { + \\builtin typeset -Ui t + + ((# t = (((Lbafh_v >> 7) & 0x01010101) * 0x1B) ^ \ + ((Lbafh_v << 1) & 0xFEFEFEFE) )) + ((# Lbafh_v = t ^ (t ^> 8) ^ (Lbafh_v ^> 8) ^ \ + (Lbafh_v ^> 16) ^ (Lbafh_v ^> 24) )) + \: +} + +# strip comments (and leading/trailing whitespace if IFS is set) from +# any file(s) given as argument, or stdin if none, and spew to stdout +function Lstripcom { + \\builtin set -o noglob + \\builtin cat "$@" | while \\builtin read _line; do + _line=${_line%%#*} + [[ -n $_line ]] && \\builtin print -r -- $_line + done +} + +# toggle built-in aliases and utilities, and aliases and functions from mkshrc +function enable { + \\builtin typeset doprnt=0 mode=1 x y z rv=0 + \\builtin typeset b_alias i_alias i_func nalias=0 nfunc=0 i_all + \\builtin set -A b_alias + \\builtin set -A i_alias + \\builtin set -A i_func + + # accumulate mksh built-in aliases, in ASCIIbetical order + i_alias[nalias]=autoload; b_alias[nalias++]='\\builtin typeset -fu' + i_alias[nalias]=functions; b_alias[nalias++]='\\builtin typeset -f' + i_alias[nalias]=hash; b_alias[nalias++]='\\builtin alias -t' + i_alias[nalias]=history; b_alias[nalias++]='\\builtin fc -l' + i_alias[nalias]=integer; b_alias[nalias++]='\\builtin typeset -i' + i_alias[nalias]=local; b_alias[nalias++]='\\builtin typeset' + i_alias[nalias]=login; b_alias[nalias++]='\\builtin exec login' + i_alias[nalias]=nameref; b_alias[nalias++]='\\builtin typeset -n' + i_alias[nalias]=nohup; b_alias[nalias++]='nohup ' + i_alias[nalias]=r; b_alias[nalias++]='\\builtin fc -e -' + i_alias[nalias]=type; b_alias[nalias++]='\\builtin whence -v' + + # accumulate mksh built-in utilities, in definition order, even ifndef + i_func[nfunc++]=. + i_func[nfunc++]=: + i_func[nfunc++]='[' + i_func[nfunc++]=alias + i_func[nfunc++]=break + # \\builtin cannot, by design, be overridden + i_func[nfunc++]=builtin + i_func[nfunc++]=cat + i_func[nfunc++]=cd + i_func[nfunc++]=chdir + i_func[nfunc++]=command + i_func[nfunc++]=continue + i_func[nfunc++]=echo + i_func[nfunc++]=eval + i_func[nfunc++]=exec + i_func[nfunc++]=exit + i_func[nfunc++]=export + i_func[nfunc++]=false + i_func[nfunc++]=fc + i_func[nfunc++]=getopts + i_func[nfunc++]=jobs + i_func[nfunc++]=kill + i_func[nfunc++]=let + i_func[nfunc++]=print + i_func[nfunc++]=pwd + i_func[nfunc++]=read + i_func[nfunc++]=readonly + i_func[nfunc++]=realpath + i_func[nfunc++]=rename + i_func[nfunc++]=return + i_func[nfunc++]=set + i_func[nfunc++]=shift + i_func[nfunc++]=source + i_func[nfunc++]=suspend + i_func[nfunc++]=test + i_func[nfunc++]=times + i_func[nfunc++]=trap + i_func[nfunc++]=true + i_func[nfunc++]=typeset + i_func[nfunc++]=ulimit + i_func[nfunc++]=umask + i_func[nfunc++]=unalias + i_func[nfunc++]=unset + i_func[nfunc++]=wait + i_func[nfunc++]=whence + i_func[nfunc++]=bg + i_func[nfunc++]=fg + i_func[nfunc++]=bind + i_func[nfunc++]=mknod + i_func[nfunc++]=printf + i_func[nfunc++]=sleep + i_func[nfunc++]=domainname + i_func[nfunc++]=extproc + + # accumulate aliases from dot.mkshrc, in definition order + i_alias[nalias]=l; b_alias[nalias++]='ls -F' + i_alias[nalias]=la; b_alias[nalias++]='l -a' + i_alias[nalias]=ll; b_alias[nalias++]='l -l' + i_alias[nalias]=lo; b_alias[nalias++]='l -alo' + i_alias[nalias]=doch; b_alias[nalias++]='sudo mksh -c "$(\\builtin fc -ln -1)"' + i_alias[nalias]=rot13; b_alias[nalias++]='tr abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM' + i_alias[nalias]=cls; b_alias[nalias++]='\\builtin print -n \\ec' + + # accumulate functions from dot.mkshrc, in definition order + i_func[nfunc++]=setenv + i_func[nfunc++]=smores + i_func[nfunc++]=hd + i_func[nfunc++]=hd_mksh + i_func[nfunc++]=which + i_func[nfunc++]=chpwd + i_func[nfunc++]=cd + i_func[nfunc++]=cd_csh + i_func[nfunc++]=dirs + i_func[nfunc++]=popd + i_func[nfunc++]=pushd + i_func[nfunc++]=Lb64decode + i_func[nfunc++]=Lb64encode + i_func[nfunc++]=Lbafh_init + i_func[nfunc++]=Lbafh_add + i_func[nfunc++]=Lbafh_finish + i_func[nfunc++]=Lstripcom + i_func[nfunc++]=enable + + # collect all identifiers, sorted ASCIIbetically + \\builtin set -sA i_all -- "${i_alias[@]}" "${i_func[@]}" + + # handle options, we don't do dynamic loading + while \\builtin getopts "adf:nps" x; do + case $x { + (a) + mode=-1 + ;; + (d) + # deliberately causing an error, like bash-static + ;| + (f) + \\builtin print -ru2 enable: dynamic loading not available + \\builtin return 2 + ;; + (n) + mode=0 + ;; + (p) + doprnt=1 + ;; + (s) + \\builtin set -sA i_all -- . : break continue eval \ + exec exit export readonly return set shift times \ + trap unset + ;; + (*) + \\builtin print -ru2 enable: usage: \ + "enable [-adnps] [-f filename] [name ...]" + return 2 + ;; + } + done + \\builtin shift $((OPTIND - 1)) + + # display builtins enabled/disabled/all/special? + if (( doprnt || ($# == 0) )); then + for x in "${i_all[@]}"; do + y=$(\\builtin alias "$x") || y= + [[ $y = "$x='\\\\builtin whence -p $x >/dev/null || (\\\\builtin print -r mksh: $x: not found; \\\\builtin exit 127) && \$(\\\\builtin whence -p $x)'" ]]; z=$? + case $mode:$z { + (-1:0|0:0) + \\builtin print -r -- "enable -n $x" + ;; + (-1:1|1:1) + \\builtin print -r -- "enable $x" + ;; + } + done + \\builtin return 0 + fi + + for x in "$@"; do + z=0 + for y in "${i_alias[@]}" "${i_func[@]}"; do + [[ $x = "$y" ]] || \\builtin continue + z=1 + \\builtin break + done + if (( !z )); then + \\builtin print -ru2 enable: "$x": not a shell builtin + rv=1 + \\builtin continue + fi + if (( !mode )); then + # disable this + \\builtin alias "$x=\\\\builtin whence -p $x >/dev/null || (\\\\builtin print -r mksh: $x: not found; \\\\builtin exit 127) && \$(\\\\builtin whence -p $x)" + else + # find out if this is an alias or not, first + z=0 + y=-1 + while (( ++y < nalias )); do + [[ $x = "${i_alias[y]}" ]] || \\builtin continue + z=1 + \\builtin break + done + if (( z )); then + # re-enable the original alias body + \\builtin alias "$x=${b_alias[y]}" + else + # re-enable the original utility/function + \\builtin unalias "$x" + fi + fi + done + \\builtin return $rv +} + +\: place customisations below this line + +# some defaults / samples which you are supposed to adjust to your +# liking; by default we add ~/.etc/bin and ~/bin (whichever exist) +# to $PATH, set $SHELL to mksh, set some defaults for man and less +# and show a few more possible things for users to begin moving in + +for p in ~/.etc/bin ~/bin; do + [[ -d $p/. ]] || \\builtin continue + [[ $PATHSEP$PATH$PATHSEP = *"$PATHSEP$p$PATHSEP"* ]] || \ + PATH=$p$PATHSEP$PATH +done + +\\builtin export SHELL=$MKSH MANWIDTH=80 LESSHISTFILE=- +\\builtin alias cls='\\builtin print -n \\ec' + +#\\builtin unset LC_ADDRESS LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ +# LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ +# LC_TELEPHONE LC_TIME LANGUAGE LANG LC_ALL +#p=en_GB.UTF-8 +#\\builtin export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p +#\\builtin export LANG=C.UTF-8 LC_CTYPE=C.UTF-8 +#\\builtin export LC_ALL=C.UTF-8 +#\\builtin set -U +#[[ ${LC_ALL:-${LC_CTYPE:-${LANG:-}}} = *[Uu][Tt][Ff]?(-)8* ]] || \\builtin set +U + +\\builtin unset p + +set -o vi + +[ -r $MKSHDIR/mkshfunc ] && source $MKSHDIR/mkshfunc +[ -r $MKSHDIR/mkshalias ] && source $MKSHDIR/mkshalias + +HISTFILE="$MKSHDIR"/history + +\: place customisations above this line diff --git a/modprobed-db.conf b/modprobed-db.conf new file mode 100644 index 0000000..42b32af --- /dev/null +++ b/modprobed-db.conf @@ -0,0 +1,21 @@ +# For documentation, see the manpage for modprobed-db + +# Path where database will reside. +# Do NOT use a variable in the following path like $HOME +# You MUST use a fully qualified path or else invoking the script via sudo +# will trick it into thinking that the db is in /root/foo/bar +DBPATH="/home/zachir/.config" + +# Define the background of your terminal theme here. +# A setting of dark will produce colors that nicely contrast a dark background. +# A setting of light will produce colors that nicely contrast a light background. +COLORS=dark +#COLORS=light + + +# Add modules in the ignore array that you do NOT want counted, for example out-of-tree +# modules and those provided by another package. +# +# For Arch Linux, some examples are given below but this is not an fully inclusive list. + +IGNORE=(nvidia nvidia_drm nvidia_modeset nvidia_uvm vboxdrv vboxnetadp vboxnetflt vboxpci acpi_call tp_smapi-dkms) diff --git a/mpd/mpd.conf b/mpd/mpd.conf new file mode 100644 index 0000000..e26dbd1 --- /dev/null +++ b/mpd/mpd.conf @@ -0,0 +1,401 @@ +# An example configuration file for MPD. +# Read the user manual for documentation: http://www.musicpd.org/doc/user/ + + +# Files and directories ####################################################### +# +# This setting controls the top directory which MPD will search to discover the +# available audio files and add them to the daemon's online database. This +# setting defaults to the XDG directory, otherwise the music directory will be +# be disabled and audio files will only be accepted over ipc socket (using +# file:// protocol) or streaming files over an accepted protocol. +# +music_directory "~/Music" +# +# This setting sets the MPD internal playlist directory. The purpose of this +# directory is storage for playlists created by MPD. The server will use +# playlist files not created by the server but only if they are in the MPD +# format. This setting defaults to playlist saving being disabled. +# +playlist_directory "~/.config/mpd/playlists" +# +# This setting sets the location of the MPD database. This file is used to +# load the database at server start up and store the database while the +# server is not up. This setting defaults to disabled which will allow +# MPD to accept files over ipc socket (using file:// protocol) or streaming +# files over an accepted protocol. +# +db_file "~/.config/mpd/database" +# +# These settings are the locations for the daemon log files for the daemon. +# These logs are great for troubleshooting, depending on your log_level +# settings. +# +# The special value "syslog" makes MPD use the local syslog daemon. This +# setting defaults to logging to syslog. +# +log_file "~/.config/mpd/log" +# +# This setting sets the location of the file which stores the process ID +# for use of mpd --kill and some init scripts. This setting is disabled by +# default and the pid file will not be stored. +# +pid_file "~/.config/mpd/pid" +# +# This setting sets the location of the file which contains information about +# most variables to get MPD back into the same general shape it was in before +# it was brought down. This setting is disabled by default and the server +# state will be reset on server start up. +# +state_file "~/.config/mpd/state" +# +# The location of the sticker database. This is a database which +# manages dynamic information attached to songs. +# +sticker_file "~/.config/mpd/sticker.sql" +# +############################################################################### + + +# General music daemon options ################################################ +# +# This setting specifies the user that MPD will run as. MPD should never run as +# root and you may use this setting to make MPD change its user ID after +# initialization. This setting is disabled by default and MPD is run as the +# current user. +# +#user "nobody" +# +# This setting specifies the group that MPD will run as. If not specified +# primary group of user specified with "user" setting will be used (if set). +# This is useful if MPD needs to be a member of group such as "audio" to +# have permission to use sound card. +# +#group "nogroup" +# +# This setting sets the address for the daemon to listen on. Careful attention +# should be paid if this is assigned to anything other then the default, any. +# This setting can deny access to control of the daemon. Not effective if +# systemd socket activiation is in use. +# +# For network +# bind_to_address "127.0.0.1" +# +# And for Unix Socket +bind_to_address "~/.config/mpd/socket" +# +# This setting is the TCP port that is desired for the daemon to get assigned +# to. +# +#port "6600" +# +# This setting controls the type of information which is logged. Available +# setting arguments are "default", "secure" or "verbose". The "verbose" setting +# argument is recommended for troubleshooting, though can quickly stretch +# available resources on limited hardware storage. +# +log_level "default" +# +# Setting "restore_paused" to "yes" puts MPD into pause mode instead +# of starting playback after startup. +# +restore_paused "yes" +# +# This setting enables MPD to create playlists in a format usable by other +# music players. +# +save_absolute_paths_in_playlists "yes" +# +# This setting defines a list of tag types that will be extracted during the +# audio file discovery process. The complete list of possible values can be +# found in the user manual. +metadata_to_use "artist,album,title,track,name,genre,date,composer,performer,disc" +# +# This example just enables the "comment" tag without disabling all +# the other supported tags: +#metadata_to_use "+comment" +# +# This setting enables automatic update of MPD's database when files in +# music_directory are changed. +# +auto_update "yes" +# +# Limit the depth of the directories being watched, 0 means only watch +# the music directory itself. There is no limit by default. +# +auto_update_depth "0" +# +############################################################################### + + +# Symbolic link behavior ###################################################### +# +# If this setting is set to "yes", MPD will discover audio files by following +# symbolic links outside of the configured music_directory. +# +follow_outside_symlinks "yes" +# +# If this setting is set to "yes", MPD will discover audio files by following +# symbolic links inside of the configured music_directory. +# +#follow_inside_symlinks "yes" +# +############################################################################### + + +# Zeroconf / Avahi Service Discovery ########################################## +# +# If this setting is set to "yes", service information will be published with +# Zeroconf / Avahi. +# +#zeroconf_enabled "yes" +# +# The argument to this setting will be the Zeroconf / Avahi unique name for +# this MPD server on the network. %h will be replaced with the hostname. +# +#zeroconf_name "Music Player @ %h" +# +############################################################################### + + +# Permissions ################################################################# +# +# If this setting is set, MPD will require password authorization. The password +# setting can be specified multiple times for different password profiles. +# +#password "password@read,add,control,admin" +# +# This setting specifies the permissions a user has who has not yet logged in. +# +#default_permissions "read,add,control,admin" +# +############################################################################### + + +# Database ####################################################################### +# + +#database { +# plugin "proxy" +# host "other.mpd.host" +# port "6600" +#} + +# Input ####################################################################### +# + +input { + plugin "curl" +# proxy "proxy.isp.com:8080" +# proxy_user "user" +# proxy_password "password" +} + +# +############################################################################### + +# Audio Output ################################################################ +# +# MPD supports various audio output types, as well as playing through multiple +# audio outputs at the same time, through multiple audio_output settings +# blocks. Setting this block is optional, though the server will only attempt +# autodetection for one sound card. +# +# An example of an ALSA output: +# +#audio_output { +# # type "alsa" +# # name "Master" +# # device "hw:2" # optional +## mixer_type "hardware" # optional +## mixer_device "default" # optional +## mixer_control "PCM" # optional +## mixer_index "0" # optional +#} +# +# An example of an OSS output: +# +#audio_output { +# type "oss" +# name "My OSS Device" +## device "/dev/dsp" # optional +## mixer_type "hardware" # optional +## mixer_device "/dev/mixer" # optional +## mixer_control "PCM" # optional +#} +# +# An example of a shout output (for streaming to Icecast): +# +#audio_output { +# type "shout" +# encoder "vorbis" # optional +# name "My Shout Stream" +# host "localhost" +# port "8000" +# mount "/mpd.ogg" +# password "hackme" +# quality "5.0" +# bitrate "128" +# format "44100:16:1" +## protocol "icecast2" # optional +## user "source" # optional +## description "My Stream Description" # optional +## url "http://example.com" # optional +## genre "jazz" # optional +## public "no" # optional +## timeout "2" # optional +## mixer_type "software" # optional +#} +# +# An example of a recorder output: +# +#audio_output { +# type "recorder" +# name "My recorder" +# encoder "vorbis" # optional, vorbis or lame +# path "/var/lib/mpd/recorder/mpd.ogg" +## quality "5.0" # do not define if bitrate is defined +# bitrate "128" # do not define if quality is defined +# format "44100:16:1" +#} +# +# An example of a httpd output (built-in HTTP streaming server): +# +#audio_output { +# type "httpd" +# name "My HTTP Stream" +# encoder "vorbis" # optional, vorbis or lame +# port "8000" +# bind_to_address "0.0.0.0" # optional, IPv4 or IPv6 +## quality "5.0" # do not define if bitrate is defined +# bitrate "128" # do not define if quality is defined +# format "44100:16:1" +# max_clients "0" # optional 0=no limit +#} +# +# An example of a pulseaudio output (streaming to a remote pulseaudio server) +# +audio_output { + type "pulse" + name "My Pulse Output" +# server "remote_server" # optional +# sink "remote_server_sink" # optional +} + +audio_output { + type "fifo" + name "my_fifo" + path "/tmp/mpd.fifo" + format "44100:16:2" +} +# +# An example of a winmm output (Windows multimedia API). +# +#audio_output { +# type "winmm" +# name "My WinMM output" +## device "Digital Audio (S/PDIF) (High Definition Audio Device)" # optional +# or +## device "0" # optional +## mixer_type "hardware" # optional +#} +# +# An example of an openal output. +# +#audio_output { +# type "openal" +# name "My OpenAL output" +## device "Digital Audio (S/PDIF) (High Definition Audio Device)" # optional +#} +# +# An example of an sndio output. +# +#audio_output { +# type "sndio" +# name "sndio output" +# mixer_type "hardware" +#} +# +# An example of an OS X output: +# +#audio_output { +# type "osx" +# name "My OS X Device" +## device "Built-in Output" # optional +## channel_map "-1,-1,0,1" # optional +#} +# +## Example "pipe" output: +# +#audio_output { +# type "pipe" +# name "my pipe" +# command "aplay -f cd 2>/dev/null" +## Or if you're want to use AudioCompress +# command "AudioCompress -m | aplay -f cd 2>/dev/null" +## Or to send raw PCM stream through PCM: +# command "nc example.org 8765" +# format "44100:16:2" +#} +# +## An example of a null output (for no audio output): +# +#audio_output { +# type "null" +# name "My Null Output" +# mixer_type "none" # optional +#} +#audio_output { +# type "jack" +# name "MPD" +#} +# +############################################################################### + + +# Normalization automatic volume adjustments ################################## +# +# This setting specifies the type of ReplayGain to use. This setting can have +# the argument "off", "album", "track" or "auto". "auto" is a special mode that +# chooses between "track" and "album" depending on the current state of +# random playback. If random playback is enabled then "track" mode is used. +# See for more details about ReplayGain. +# This setting is off by default. +# +replaygain "auto" +# +# This setting sets the pre-amp used for files that have ReplayGain tags. By +# default this setting is disabled. +# +replaygain_preamp "0" +# +# This setting sets the pre-amp used for files that do NOT have ReplayGain tags. +# By default this setting is disabled. +# +replaygain_missing_preamp "0" +# +# This setting enables or disables ReplayGain limiting. +# MPD calculates actual amplification based on the ReplayGain tags +# and replaygain_preamp / replaygain_missing_preamp setting. +# If replaygain_limit is enabled MPD will never amplify audio signal +# above its original level. If replaygain_limit is disabled such amplification +# might occur. By default this setting is enabled. +# +replaygain_limit "yes" +# +# This setting enables on-the-fly normalization volume adjustment. This will +# result in the volume of all playing audio to be adjusted so the output has +# equal "loudness". This setting is disabled by default. +# +volume_normalization "no" +# +############################################################################### + +# Character Encoding ########################################################## +# +# If file or directory names do not display correctly for your locale then you +# may need to modify this setting. +# +#filesystem_charset "UTF-8" +# +############################################################################### diff --git a/mpv/input.conf b/mpv/input.conf new file mode 100644 index 0000000..d28ab28 --- /dev/null +++ b/mpv/input.conf @@ -0,0 +1,2 @@ +Ctrl+f script-binding quality_menu/video_formats_toggle +Ctrl+a script-binding quality_menu/audio_formats_toggle diff --git a/mpv/mpv.conf b/mpv/mpv.conf new file mode 100644 index 0000000..63f8119 --- /dev/null +++ b/mpv/mpv.conf @@ -0,0 +1,5 @@ +save-position-on-quit +osc=no +ao=pulse +vo=gpu +audio-channels=2 diff --git a/mpv/script-opts/quality-menu.conf b/mpv/script-opts/quality-menu.conf new file mode 100644 index 0000000..80ab845 --- /dev/null +++ b/mpv/script-opts/quality-menu.conf @@ -0,0 +1,95 @@ +# KEY BINDINGS + +# move the menu cursor up +up_binding=UP WHEEL_UP +# move the menu cursor down +down_binding=DOWN WHEEL_DOWN +# select menu entry +select_binding=ENTER MBTN_LEFT +# close menu +close_menu_binding=ESC MBTN_RIGHT Ctrl+f Alt+f + +# youtube-dl version(could be youtube-dl or yt-dlp, or something else) +ytdl_ver=yt-dlp + +# formatting / cursors +selected_and_active=▶ - +selected_and_inactive=● - +unselected_and_active=▷ - +unselected_and_inactive=○ - + +# font size scales by window, if false requires larger font and padding sizes +scale_playlist_by_window=yes + +# playlist ass style overrides inside curly brackets, \keyvalue is one field, extra \ for escape in lua +# example {\\fnUbuntu\\fs10\\b0\\bord1} equals: font=Ubuntu, size=10, bold=no, border=1 +# read http://docs.aegisub.org/3.2/ASS_Tags/ for reference of tags +# undeclared tags will use default osd settings +# these styles will be used for the whole playlist. More specific styling will need to be hacked in +# +# (a monospaced font is recommended but not required) +style_ass_tags={\\fnmonospace\\fs10\\bord1} + +# paddings for top left corner +text_padding_x=5 +text_padding_y=5 + +# how many seconds until the quality menu times out +# setting this to 0 deactivates the timeout +menu_timeout=6 + +# use youtube-dl to fetch a list of available formats (overrides quality_strings) +fetch_formats=yes + +# list of ytdl-format strings to choose from +quality_strings=[ {"4320p" : "bestvideo[height<=?4320p]+bestaudio/best"}, {"2160p" : "bestvideo[height<=?2160]+bestaudio/best"}, {"1440p" : "bestvideo[height<=?1440]+bestaudio/best"}, {"1080p" : "bestvideo[height<=?1080]+bestaudio/best"}, {"720p" : "bestvideo[height<=?720]+bestaudio/best"}, {"480p" : "bestvideo[height<=?480]+bestaudio/best"}, {"360p" : "bestvideo[height<=?360]+bestaudio/best"}, {"240p" : "bestvideo[height<=?240]+bestaudio/best"}, {"144p" : "bestvideo[height<=?144]+bestaudio/best"} ] + +# reset youtube-dl format to the original format string when changing files (e.g. going to the next playlist entry) +# if file was opened previously, reset to previously selected format +reset_format=yes + +# automatically fetch available formats when opening an url +fetch_on_start=yes + +# show the video format menu after opening an url +start_with_menu=no + +# include unknown formats in the list +# Unfortunately choosing which formats are video or audio is not always perfect. +# Set to true to make sure you don't miss any formats, but then the list +# might also include formats that aren't actually video or audio. +# Formats that are known to not be video or audio are still filtered out. +include_unknown=no + +# hide columns that are identical for all formats +hide_identical_columns=yes + +# which columns are shown in which order +# comma separated list, prefix column with "-" to align left +# +# columns that might be useful are: +# resolution, width, height, fps, dynamic_range, tbr, vbr, abr, asr, +# filesize, filesize_approx, vcodec, acodec, ext, video_ext, audio_ext, +# language, format, format_note, quality +# +# columns that are derived from the above, but with special treatment: +# frame_rate, bitrate_total, bitrate_video, bitrate_audio, +# codec_video, codec_audio, audio_sample_rate +# +# If those still aren't enough or you're just curious, run: +# yt-dlp -j +# This outputs unformatted JSON. +# Format it and look under "formats" to see what's available. +# +# Not all videos have all columns available. +# Be careful, misspelled columns simply won't be displayed, there is no error. +columns_video=-resolution,frame_rate,dynamic_range,language,bitrate_total,size,-codec_video,-codec_audio +columns_audio=audio_sample_rate,bitrate_total,size,language,-codec_audio + +# columns used for sorting, see "columns_video" for available columns +# comma separated list, prefix column with "-" to reverse sorting order +# Leaving this empty keeps the order from yt-dlp/youtube-dl. +# Be careful, misspelled columns won't result in an error, +# but they might influence the result. +sort_video=height,fps,tbr,size,format_id +sort_audio=asr,tbr,size,format_id diff --git a/mpv/script-opts/youtube-download.conf b/mpv/script-opts/youtube-download.conf new file mode 100644 index 0000000..33630bf --- /dev/null +++ b/mpv/script-opts/youtube-download.conf @@ -0,0 +1,48 @@ +# KEY BINDINGS +download_video_binding=ctrl+d +download_audio_binding=ctrl+a +#download_subtitle_binding=ctrl+s +#download_video_embed_subtitle_binding=ctrl+i +#select_range_binding=ctrl+r + +# Specify audio format: "best", "aac","flac", "mp3", "m4a", "opus", "vorbis", or "wav" +audio_format=best + +# Specify ffmpeg/avconv audio quality +# insert a value between 0 (better) and 9 (worse) for VBR or a specific bitrate like 128K +audio_quality=0 + +# Same as youtube-dl --format FORMAT +# see https://github.com/ytdl-org/youtube-dl/blob/master/README.md#format-selection +# set to "current" to download the same quality that is currently playing +video_format=best + +# Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm|mkv|avi) +# recode_video="mp4" + +# Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames +restrict_filenames=yes + +# Download the whole playlist (no) or only one video (yes) +# Same as youtube-dl --no-playlist +no_playlist=yes + +# Use an archive file, see youtube-dl --download-archive +# You have these options: +# * Set to empty string "" to not use an archive file +# * Set an absolute path to use one archive for all downloads e.g. download_archive="/home/user/archive.txt" +# * Set a relative path/only a filename to use one archive per directory e.g. download_archive="archive.txt" +# * Use $PLAYLIST to create one archive per playlist e.g. download_archive="/home/user/archives/$PLAYLIST.txt" +download_archive=~/Videos/archive/archive.txt + +# Filename or full path +# Same youtube-dl -o +# see https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template +filename=~/Videos/%(title)s.%(ext)s + +# Use a cookies file for youtube-dl +# Same as youtube-dl --cookies +#cookies=C:\Users\username\cookies.txt + +# Write download errors to a log file +log_file=~/.config/mpv/download.log diff --git a/mpv/scripts/quality-menu-osc.lua b/mpv/scripts/quality-menu-osc.lua new file mode 100644 index 0000000..0a2f6c2 --- /dev/null +++ b/mpv/scripts/quality-menu-osc.lua @@ -0,0 +1,2911 @@ +local assdraw = require 'mp.assdraw' +local msg = require 'mp.msg' +local opt = require 'mp.options' +local utils = require 'mp.utils' + +-- +-- Parameters +-- +-- default user option values +-- do not touch, change them in osc.conf +local user_opts = { + showwindowed = true, -- show OSC when windowed? + showfullscreen = true, -- show OSC when fullscreen? + idlescreen = true, -- show mpv logo on idle + scalewindowed = 1, -- scaling of the controller when windowed + scalefullscreen = 1, -- scaling of the controller when fullscreen + scaleforcedwindow = 2, -- scaling when rendered on a forced window + vidscale = true, -- scale the controller with the video? + valign = 0.8, -- vertical alignment, -1 (top) to 1 (bottom) + halign = 0, -- horizontal alignment, -1 (left) to 1 (right) + barmargin = 0, -- vertical margin of top/bottombar + boxalpha = 80, -- alpha of the background box, + -- 0 (opaque) to 255 (fully transparent) + hidetimeout = 500, -- duration in ms until the OSC hides if no + -- mouse movement. enforced non-negative for the + -- user, but internally negative is "always-on". + fadeduration = 200, -- duration of fade out in ms, 0 = no fade + deadzonesize = 0.5, -- size of deadzone + minmousemove = 0, -- minimum amount of pixels the mouse has to + -- move between ticks to make the OSC show up + iamaprogrammer = false, -- use native mpv values and disable OSC + -- internal track list management (and some + -- functions that depend on it) + layout = "bottombar", + seekbarstyle = "bar", -- bar, diamond or knob + seekbarhandlesize = 0.6, -- size ratio of the diamond and knob handle + seekrangestyle = "inverted",-- bar, line, slider, inverted or none + seekrangeseparate = true, -- whether the seekranges overlay on the bar-style seekbar + seekrangealpha = 200, -- transparency of seekranges + seekbarkeyframes = true, -- use keyframes when dragging the seekbar + title = "${media-title}", -- string compatible with property-expansion + -- to be shown as OSC title + tooltipborder = 1, -- border of tooltip in bottom/topbar + timetotal = false, -- display total time instead of remaining time? + timems = false, -- display timecodes with milliseconds? + tcspace = 100, -- timecode spacing (compensate font size estimation) + visibility = "auto", -- only used at init to set visibility_mode(...) + boxmaxchars = 80, -- title crop threshold for box layout + boxvideo = false, -- apply osc_param.video_margins to video + windowcontrols = "auto", -- whether to show window controls + windowcontrols_alignment = "right", -- which side to show window controls on + greenandgrumpy = false, -- disable santa hat + livemarkers = true, -- update seekbar chapter markers on duration change + chapters_osd = true, -- whether to show chapters OSD on next/prev + playlist_osd = true, -- whether to show playlist OSD on next/prev + chapter_fmt = "Chapter: %s", -- chapter print format for seekbar-hover. "no" to disable + unicodeminus = false, -- whether to use the Unicode minus sign character +} + +-- read options from config and command-line +opt.read_options(user_opts, "osc", function(list) update_options(list) end) + +local osc_param = { -- calculated by osc_init() + playresy = 0, -- canvas size Y + playresx = 0, -- canvas size X + display_aspect = 1, + unscaled_y = 0, + areas = {}, + video_margins = { + l = 0, r = 0, t = 0, b = 0, -- left/right/top/bottom + }, +} + +local osc_styles = { + bigButtons = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs50\\fnmpv-osd-symbols}", + smallButtonsL = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs19\\fnmpv-osd-symbols}", + smallButtonsLlabel = "{\\fscx105\\fscy105\\fn" .. mp.get_property("options/osd-font") .. "}", + smallButtonsR = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs30\\fnmpv-osd-symbols}", + topButtons = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs12\\fnmpv-osd-symbols}", + + elementDown = "{\\1c&H999999}", + timecodes = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs20}", + vidtitle = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs12\\q2}", + box = "{\\rDefault\\blur0\\bord1\\1c&H000000\\3c&HFFFFFF}", + + topButtonsBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs18\\fnmpv-osd-symbols}", + smallButtonsBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs28\\fnmpv-osd-symbols}", + timecodesBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs27}", + timePosBar = "{\\blur0\\bord".. user_opts.tooltipborder .."\\1c&HFFFFFF\\3c&H000000\\fs30}", + vidtitleBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs18\\q2}", + + wcButtons = "{\\1c&HFFFFFF\\fs24\\fnmpv-osd-symbols}", + wcTitle = "{\\1c&HFFFFFF\\fs24\\q2}", + wcBar = "{\\1c&H000000}", +} + +-- internal states, do not touch +local state = { + showtime, -- time of last invocation (last mouse move) + osc_visible = false, + anistart, -- time when the animation started + anitype, -- current type of animation + animation, -- current animation alpha + mouse_down_counter = 0, -- used for softrepeat + active_element = nil, -- nil = none, 0 = background, 1+ = see elements[] + active_event_source = nil, -- the "button" that issued the current event + rightTC_trem = not user_opts.timetotal, -- if the right timecode should display total or remaining time + tc_ms = user_opts.timems, -- Should the timecodes display their time with milliseconds + mp_screen_sizeX, mp_screen_sizeY, -- last screen-resolution, to detect resolution changes to issue reINITs + initREQ = false, -- is a re-init request pending? + marginsREQ = false, -- is a margins update pending? + last_mouseX, last_mouseY, -- last mouse position, to detect significant mouse movement + mouse_in_window = false, + message_text, + message_hide_timer, + fullscreen = false, + tick_timer = nil, + tick_last_time = 0, -- when the last tick() was run + hide_timer = nil, + cache_state = nil, + idle = false, + enabled = true, + input_enabled = true, + showhide_enabled = false, + dmx_cache = 0, + using_video_margins = false, + border = true, + maximized = false, + osd = mp.create_osd_overlay("ass-events"), + chapter_list = {}, -- sorted by time +} + +local window_control_box_width = 80 +local tick_delay = 0.03 + +local is_december = os.date("*t").month == 12 + +-- +-- Helperfunctions +-- + +function kill_animation() + state.anistart = nil + state.animation = nil + state.anitype = nil +end + +function set_osd(res_x, res_y, text) + if state.osd.res_x == res_x and + state.osd.res_y == res_y and + state.osd.data == text then + return + end + state.osd.res_x = res_x + state.osd.res_y = res_y + state.osd.data = text + state.osd.z = 1000 + state.osd:update() +end + +local margins_opts = { + {"l", "video-margin-ratio-left"}, + {"r", "video-margin-ratio-right"}, + {"t", "video-margin-ratio-top"}, + {"b", "video-margin-ratio-bottom"}, +} + +-- scale factor for translating between real and virtual ASS coordinates +function get_virt_scale_factor() + local w, h = mp.get_osd_size() + if w <= 0 or h <= 0 then + return 0, 0 + end + return osc_param.playresx / w, osc_param.playresy / h +end + +-- return mouse position in virtual ASS coordinates (playresx/y) +function get_virt_mouse_pos() + if state.mouse_in_window then + local sx, sy = get_virt_scale_factor() + local x, y = mp.get_mouse_pos() + return x * sx, y * sy + else + return -1, -1 + end +end + +function set_virt_mouse_area(x0, y0, x1, y1, name) + local sx, sy = get_virt_scale_factor() + mp.set_mouse_area(x0 / sx, y0 / sy, x1 / sx, y1 / sy, name) +end + +function scale_value(x0, x1, y0, y1, val) + local m = (y1 - y0) / (x1 - x0) + local b = y0 - (m * x0) + return (m * val) + b +end + +-- returns hitbox spanning coordinates (top left, bottom right corner) +-- according to alignment +function get_hitbox_coords(x, y, an, w, h) + + local alignments = { + [1] = function () return x, y-h, x+w, y end, + [2] = function () return x-(w/2), y-h, x+(w/2), y end, + [3] = function () return x-w, y-h, x, y end, + + [4] = function () return x, y-(h/2), x+w, y+(h/2) end, + [5] = function () return x-(w/2), y-(h/2), x+(w/2), y+(h/2) end, + [6] = function () return x-w, y-(h/2), x, y+(h/2) end, + + [7] = function () return x, y, x+w, y+h end, + [8] = function () return x-(w/2), y, x+(w/2), y+h end, + [9] = function () return x-w, y, x, y+h end, + } + + return alignments[an]() +end + +function get_hitbox_coords_geo(geometry) + return get_hitbox_coords(geometry.x, geometry.y, geometry.an, + geometry.w, geometry.h) +end + +function get_element_hitbox(element) + return element.hitbox.x1, element.hitbox.y1, + element.hitbox.x2, element.hitbox.y2 +end + +function mouse_hit(element) + return mouse_hit_coords(get_element_hitbox(element)) +end + +function mouse_hit_coords(bX1, bY1, bX2, bY2) + local mX, mY = get_virt_mouse_pos() + return (mX >= bX1 and mX <= bX2 and mY >= bY1 and mY <= bY2) +end + +function limit_range(min, max, val) + if val > max then + val = max + elseif val < min then + val = min + end + return val +end + +-- translate value into element coordinates +function get_slider_ele_pos_for(element, val) + + local ele_pos = scale_value( + element.slider.min.value, element.slider.max.value, + element.slider.min.ele_pos, element.slider.max.ele_pos, + val) + + return limit_range( + element.slider.min.ele_pos, element.slider.max.ele_pos, + ele_pos) +end + +-- translates global (mouse) coordinates to value +function get_slider_value_at(element, glob_pos) + + local val = scale_value( + element.slider.min.glob_pos, element.slider.max.glob_pos, + element.slider.min.value, element.slider.max.value, + glob_pos) + + return limit_range( + element.slider.min.value, element.slider.max.value, + val) +end + +-- get value at current mouse position +function get_slider_value(element) + return get_slider_value_at(element, get_virt_mouse_pos()) +end + +function countone(val) + if not (user_opts.iamaprogrammer) then + val = val + 1 + end + return val +end + +-- align: -1 .. +1 +-- frame: size of the containing area +-- obj: size of the object that should be positioned inside the area +-- margin: min. distance from object to frame (as long as -1 <= align <= +1) +function get_align(align, frame, obj, margin) + return (frame / 2) + (((frame / 2) - margin - (obj / 2)) * align) +end + +-- multiplies two alpha values, formular can probably be improved +function mult_alpha(alphaA, alphaB) + return 255 - (((1-(alphaA/255)) * (1-(alphaB/255))) * 255) +end + +function add_area(name, x1, y1, x2, y2) + -- create area if needed + if (osc_param.areas[name] == nil) then + osc_param.areas[name] = {} + end + table.insert(osc_param.areas[name], {x1=x1, y1=y1, x2=x2, y2=y2}) +end + +function ass_append_alpha(ass, alpha, modifier) + local ar = {} + + for ai, av in pairs(alpha) do + av = mult_alpha(av, modifier) + if state.animation then + av = mult_alpha(av, state.animation) + end + ar[ai] = av + end + + ass:append(string.format("{\\1a&H%X&\\2a&H%X&\\3a&H%X&\\4a&H%X&}", + ar[1], ar[2], ar[3], ar[4])) +end + +function ass_draw_rr_h_cw(ass, x0, y0, x1, y1, r1, hexagon, r2) + if hexagon then + ass:hexagon_cw(x0, y0, x1, y1, r1, r2) + else + ass:round_rect_cw(x0, y0, x1, y1, r1, r2) + end +end + +function ass_draw_rr_h_ccw(ass, x0, y0, x1, y1, r1, hexagon, r2) + if hexagon then + ass:hexagon_ccw(x0, y0, x1, y1, r1, r2) + else + ass:round_rect_ccw(x0, y0, x1, y1, r1, r2) + end +end + + +-- +-- Tracklist Management +-- + +local nicetypes = {video = "Video", audio = "Audio", sub = "Subtitle"} + +-- updates the OSC internal playlists, should be run each time the track-layout changes +function update_tracklist() + local tracktable = mp.get_property_native("track-list", {}) + + -- by osc_id + tracks_osc = {} + tracks_osc.video, tracks_osc.audio, tracks_osc.sub = {}, {}, {} + -- by mpv_id + tracks_mpv = {} + tracks_mpv.video, tracks_mpv.audio, tracks_mpv.sub = {}, {}, {} + for n = 1, #tracktable do + if not (tracktable[n].type == "unknown") then + local type = tracktable[n].type + local mpv_id = tonumber(tracktable[n].id) + + -- by osc_id + table.insert(tracks_osc[type], tracktable[n]) + + -- by mpv_id + tracks_mpv[type][mpv_id] = tracktable[n] + tracks_mpv[type][mpv_id].osc_id = #tracks_osc[type] + end + end +end + +-- return a nice list of tracks of the given type (video, audio, sub) +function get_tracklist(type) + local msg = "Available " .. nicetypes[type] .. " Tracks: " + if not tracks_osc or #tracks_osc[type] == 0 then + msg = msg .. "none" + else + for n = 1, #tracks_osc[type] do + local track = tracks_osc[type][n] + local lang, title, selected = "unknown", "", "○" + if not(track.lang == nil) then lang = track.lang end + if not(track.title == nil) then title = track.title end + if (track.id == tonumber(mp.get_property(type))) then + selected = "●" + end + msg = msg.."\n"..selected.." "..n..": ["..lang.."] "..title + end + end + return msg +end + +-- relatively change the track of given by tracks + --(+1 -> next, -1 -> previous) +function set_track(type, next) + local current_track_mpv, current_track_osc + if (mp.get_property(type) == "no") then + current_track_osc = 0 + else + current_track_mpv = tonumber(mp.get_property(type)) + current_track_osc = tracks_mpv[type][current_track_mpv].osc_id + end + local new_track_osc = (current_track_osc + next) % (#tracks_osc[type] + 1) + local new_track_mpv + if new_track_osc == 0 then + new_track_mpv = "no" + else + new_track_mpv = tracks_osc[type][new_track_osc].id + end + + mp.commandv("set", type, new_track_mpv) + + if (new_track_osc == 0) then + show_message(nicetypes[type] .. " Track: none") + else + show_message(nicetypes[type] .. " Track: " + .. new_track_osc .. "/" .. #tracks_osc[type] + .. " [".. (tracks_osc[type][new_track_osc].lang or "unknown") .."] " + .. (tracks_osc[type][new_track_osc].title or "")) + end +end + +-- get the currently selected track of , OSC-style counted +function get_track(type) + local track = mp.get_property(type) + if track ~= "no" and track ~= nil then + local tr = tracks_mpv[type][tonumber(track)] + if tr then + return tr.osc_id + end + end + return 0 +end + +-- WindowControl helpers +function window_controls_enabled() + val = user_opts.windowcontrols + if val == "auto" then + return not state.border + else + return val ~= "no" + end +end + +function window_controls_alignment() + return user_opts.windowcontrols_alignment +end + +-- +-- Element Management +-- + +local elements = {} + +function prepare_elements() + + -- remove elements without layout or invisble + local elements2 = {} + for n, element in pairs(elements) do + if not (element.layout == nil) and (element.visible) then + table.insert(elements2, element) + end + end + elements = elements2 + + function elem_compare (a, b) + return a.layout.layer < b.layout.layer + end + + table.sort(elements, elem_compare) + + + for _,element in pairs(elements) do + + local elem_geo = element.layout.geometry + + -- Calculate the hitbox + local bX1, bY1, bX2, bY2 = get_hitbox_coords_geo(elem_geo) + element.hitbox = {x1 = bX1, y1 = bY1, x2 = bX2, y2 = bY2} + + local style_ass = assdraw.ass_new() + + -- prepare static elements + style_ass:append("{}") -- hack to troll new_event into inserting a \n + style_ass:new_event() + style_ass:pos(elem_geo.x, elem_geo.y) + style_ass:an(elem_geo.an) + style_ass:append(element.layout.style) + + element.style_ass = style_ass + + local static_ass = assdraw.ass_new() + + + if (element.type == "box") then + --draw box + static_ass:draw_start() + ass_draw_rr_h_cw(static_ass, 0, 0, elem_geo.w, elem_geo.h, + element.layout.box.radius, element.layout.box.hexagon) + static_ass:draw_stop() + + elseif (element.type == "slider") then + --draw static slider parts + + local r1 = 0 + local r2 = 0 + local slider_lo = element.layout.slider + -- offset between element outline and drag-area + local foV = slider_lo.border + slider_lo.gap + + -- calculate positions of min and max points + if (slider_lo.stype ~= "bar") then + r1 = elem_geo.h / 2 + element.slider.min.ele_pos = elem_geo.h / 2 + element.slider.max.ele_pos = elem_geo.w - (elem_geo.h / 2) + if (slider_lo.stype == "diamond") then + r2 = (elem_geo.h - 2 * slider_lo.border) / 2 + elseif (slider_lo.stype == "knob") then + r2 = r1 + end + else + element.slider.min.ele_pos = + slider_lo.border + slider_lo.gap + element.slider.max.ele_pos = + elem_geo.w - (slider_lo.border + slider_lo.gap) + end + + element.slider.min.glob_pos = + element.hitbox.x1 + element.slider.min.ele_pos + element.slider.max.glob_pos = + element.hitbox.x1 + element.slider.max.ele_pos + + -- -- -- + + static_ass:draw_start() + + -- the box + ass_draw_rr_h_cw(static_ass, 0, 0, elem_geo.w, elem_geo.h, r1, slider_lo.stype == "diamond") + + -- the "hole" + ass_draw_rr_h_ccw(static_ass, slider_lo.border, slider_lo.border, + elem_geo.w - slider_lo.border, elem_geo.h - slider_lo.border, + r2, slider_lo.stype == "diamond") + + -- marker nibbles + if not (element.slider.markerF == nil) and (slider_lo.gap > 0) then + local markers = element.slider.markerF() + for _,marker in pairs(markers) do + if (marker > element.slider.min.value) and + (marker < element.slider.max.value) then + + local s = get_slider_ele_pos_for(element, marker) + + if (slider_lo.gap > 1) then -- draw triangles + + local a = slider_lo.gap / 0.5 --0.866 + + --top + if (slider_lo.nibbles_top) then + static_ass:move_to(s - (a/2), slider_lo.border) + static_ass:line_to(s + (a/2), slider_lo.border) + static_ass:line_to(s, foV) + end + + --bottom + if (slider_lo.nibbles_bottom) then + static_ass:move_to(s - (a/2), + elem_geo.h - slider_lo.border) + static_ass:line_to(s, + elem_geo.h - foV) + static_ass:line_to(s + (a/2), + elem_geo.h - slider_lo.border) + end + + else -- draw 2x1px nibbles + + --top + if (slider_lo.nibbles_top) then + static_ass:rect_cw(s - 1, slider_lo.border, + s + 1, slider_lo.border + slider_lo.gap); + end + + --bottom + if (slider_lo.nibbles_bottom) then + static_ass:rect_cw(s - 1, + elem_geo.h -slider_lo.border -slider_lo.gap, + s + 1, elem_geo.h - slider_lo.border); + end + end + end + end + end + end + + element.static_ass = static_ass + + + -- if the element is supposed to be disabled, + -- style it accordingly and kill the eventresponders + if not (element.enabled) then + element.layout.alpha[1] = 136 + element.eventresponder = nil + end + end +end + + +-- +-- Element Rendering +-- + +-- returns nil or a chapter element from the native property chapter-list +function get_chapter(possec) + local cl = state.chapter_list -- sorted, get latest before possec, if any + + for n=#cl,1,-1 do + if possec >= cl[n].time then + return cl[n] + end + end +end + +function render_elements(master_ass) + + -- when the slider is dragged or hovered and we have a target chapter name + -- then we use it instead of the normal title. we calculate it before the + -- render iterations because the title may be rendered before the slider. + state.forced_title = nil + local se, ae = state.slider_element, elements[state.active_element] + if user_opts.chapter_fmt ~= "no" and se and (ae == se or (not ae and mouse_hit(se))) then + local dur = mp.get_property_number("duration", 0) + if dur > 0 then + local possec = get_slider_value(se) * dur / 100 -- of mouse pos + local ch = get_chapter(possec) + if ch and ch.title and ch.title ~= "" then + state.forced_title = string.format(user_opts.chapter_fmt, ch.title) + end + end + end + + for n=1, #elements do + local element = elements[n] + + local style_ass = assdraw.ass_new() + style_ass:merge(element.style_ass) + ass_append_alpha(style_ass, element.layout.alpha, 0) + + if element.eventresponder and (state.active_element == n) then + + -- run render event functions + if not (element.eventresponder.render == nil) then + element.eventresponder.render(element) + end + + if mouse_hit(element) then + -- mouse down styling + if (element.styledown) then + style_ass:append(osc_styles.elementDown) + end + + if (element.softrepeat) and (state.mouse_down_counter >= 15 + and state.mouse_down_counter % 5 == 0) then + + element.eventresponder[state.active_event_source.."_down"](element) + end + state.mouse_down_counter = state.mouse_down_counter + 1 + end + + end + + local elem_ass = assdraw.ass_new() + + elem_ass:merge(style_ass) + + if not (element.type == "button") then + elem_ass:merge(element.static_ass) + end + + if (element.type == "slider") then + + local slider_lo = element.layout.slider + local elem_geo = element.layout.geometry + local s_min = element.slider.min.value + local s_max = element.slider.max.value + + -- draw pos marker + local foH, xp + local pos = element.slider.posF() + local foV = slider_lo.border + slider_lo.gap + local innerH = elem_geo.h - (2 * foV) + local seekRanges = element.slider.seekRangesF() + local seekRangeLineHeight = innerH / 5 + + if slider_lo.stype ~= "bar" then + foH = elem_geo.h / 2 + else + foH = slider_lo.border + slider_lo.gap + end + + if pos then + xp = get_slider_ele_pos_for(element, pos) + + if slider_lo.stype ~= "bar" then + local r = (user_opts.seekbarhandlesize * innerH) / 2 + ass_draw_rr_h_cw(elem_ass, xp - r, foH - r, + xp + r, foH + r, + r, slider_lo.stype == "diamond") + else + local h = 0 + if seekRanges and user_opts.seekrangeseparate and slider_lo.rtype ~= "inverted" then + h = seekRangeLineHeight + end + elem_ass:rect_cw(foH, foV, xp, elem_geo.h - foV - h) + + if seekRanges and not user_opts.seekrangeseparate and slider_lo.rtype ~= "inverted" then + -- Punch holes for the seekRanges to be drawn later + for _,range in pairs(seekRanges) do + if range["start"] < pos then + local pstart = get_slider_ele_pos_for(element, range["start"]) + local pend = xp + + if pos > range["end"] then + pend = get_slider_ele_pos_for(element, range["end"]) + end + elem_ass:rect_ccw(pstart, elem_geo.h - foV - seekRangeLineHeight, pend, elem_geo.h - foV) + end + end + end + end + + if slider_lo.rtype == "slider" then + ass_draw_rr_h_cw(elem_ass, foH - innerH / 6, foH - innerH / 6, + xp, foH + innerH / 6, + innerH / 6, slider_lo.stype == "diamond", 0) + ass_draw_rr_h_cw(elem_ass, xp, foH - innerH / 15, + elem_geo.w - foH + innerH / 15, foH + innerH / 15, + 0, slider_lo.stype == "diamond", innerH / 15) + for _,range in pairs(seekRanges or {}) do + local pstart = get_slider_ele_pos_for(element, range["start"]) + local pend = get_slider_ele_pos_for(element, range["end"]) + ass_draw_rr_h_ccw(elem_ass, pstart, foH - innerH / 21, + pend, foH + innerH / 21, + innerH / 21, slider_lo.stype == "diamond") + end + end + end + + if seekRanges then + if slider_lo.rtype ~= "inverted" then + elem_ass:draw_stop() + elem_ass:merge(element.style_ass) + ass_append_alpha(elem_ass, element.layout.alpha, user_opts.seekrangealpha) + elem_ass:merge(element.static_ass) + end + + for _,range in pairs(seekRanges) do + local pstart = get_slider_ele_pos_for(element, range["start"]) + local pend = get_slider_ele_pos_for(element, range["end"]) + + if slider_lo.rtype == "slider" then + ass_draw_rr_h_cw(elem_ass, pstart, foH - innerH / 21, + pend, foH + innerH / 21, + innerH / 21, slider_lo.stype == "diamond") + elseif slider_lo.rtype == "line" then + if slider_lo.stype == "bar" then + elem_ass:rect_cw(pstart, elem_geo.h - foV - seekRangeLineHeight, pend, elem_geo.h - foV) + else + ass_draw_rr_h_cw(elem_ass, pstart - innerH / 8, foH - innerH / 8, + pend + innerH / 8, foH + innerH / 8, + innerH / 8, slider_lo.stype == "diamond") + end + elseif slider_lo.rtype == "bar" then + if slider_lo.stype ~= "bar" then + ass_draw_rr_h_cw(elem_ass, pstart - innerH / 2, foV, + pend + innerH / 2, foV + innerH, + innerH / 2, slider_lo.stype == "diamond") + elseif range["end"] >= (pos or 0) then + elem_ass:rect_cw(pstart, foV, pend, elem_geo.h - foV) + else + elem_ass:rect_cw(pstart, elem_geo.h - foV - seekRangeLineHeight, pend, elem_geo.h - foV) + end + elseif slider_lo.rtype == "inverted" then + if slider_lo.stype ~= "bar" then + ass_draw_rr_h_ccw(elem_ass, pstart, (elem_geo.h / 2) - 1, pend, + (elem_geo.h / 2) + 1, + 1, slider_lo.stype == "diamond") + else + elem_ass:rect_ccw(pstart, (elem_geo.h / 2) - 1, pend, (elem_geo.h / 2) + 1) + end + end + end + end + + elem_ass:draw_stop() + + -- add tooltip + if not (element.slider.tooltipF == nil) then + + if mouse_hit(element) then + local sliderpos = get_slider_value(element) + local tooltiplabel = element.slider.tooltipF(sliderpos) + + local an = slider_lo.tooltip_an + + local ty + + if (an == 2) then + ty = element.hitbox.y1 - slider_lo.border + else + ty = element.hitbox.y1 + elem_geo.h/2 + end + + local tx = get_virt_mouse_pos() + if (slider_lo.adjust_tooltip) then + if (an == 2) then + if (sliderpos < (s_min + 3)) then + an = an - 1 + elseif (sliderpos > (s_max - 3)) then + an = an + 1 + end + elseif (sliderpos > (s_max-s_min)/2) then + an = an + 1 + tx = tx - 5 + else + an = an - 1 + tx = tx + 10 + end + end + + -- tooltip label + elem_ass:new_event() + elem_ass:pos(tx, ty) + elem_ass:an(an) + elem_ass:append(slider_lo.tooltip_style) + ass_append_alpha(elem_ass, slider_lo.alpha, 0) + elem_ass:append(tooltiplabel) + + end + end + + elseif (element.type == "button") then + + local buttontext + if type(element.content) == "function" then + buttontext = element.content() -- function objects + elseif not (element.content == nil) then + buttontext = element.content -- text objects + end + + local maxchars = element.layout.button.maxchars + if not (maxchars == nil) and (#buttontext > maxchars) then + local max_ratio = 1.25 -- up to 25% more chars while shrinking + local limit = math.max(0, math.floor(maxchars * max_ratio) - 3) + if (#buttontext > limit) then + while (#buttontext > limit) do + buttontext = buttontext:gsub(".[\128-\191]*$", "") + end + buttontext = buttontext .. "..." + end + local _, nchars2 = buttontext:gsub(".[\128-\191]*", "") + local stretch = (maxchars/#buttontext)*100 + buttontext = string.format("{\\fscx%f}", + (maxchars/#buttontext)*100) .. buttontext + end + + elem_ass:append(buttontext) + end + + master_ass:merge(elem_ass) + end +end + +-- +-- Message display +-- + +-- pos is 1 based +function limited_list(prop, pos) + local proplist = mp.get_property_native(prop, {}) + local count = #proplist + if count == 0 then + return count, proplist + end + + local fs = tonumber(mp.get_property('options/osd-font-size')) + local max = math.ceil(osc_param.unscaled_y*0.75 / fs) + if max % 2 == 0 then + max = max - 1 + end + local delta = math.ceil(max / 2) - 1 + local begi = math.max(math.min(pos - delta, count - max + 1), 1) + local endi = math.min(begi + max - 1, count) + + local reslist = {} + for i=begi, endi do + local item = proplist[i] + item.current = (i == pos) and true or nil + table.insert(reslist, item) + end + return count, reslist +end + +function get_playlist() + local pos = mp.get_property_number('playlist-pos', 0) + 1 + local count, limlist = limited_list('playlist', pos) + if count == 0 then + return 'Empty playlist.' + end + + local message = string.format('Playlist [%d/%d]:\n', pos, count) + for i, v in ipairs(limlist) do + local title = v.title + local _, filename = utils.split_path(v.filename) + if title == nil then + title = filename + end + message = string.format('%s %s %s\n', message, + (v.current and '●' or '○'), title) + end + return message +end + +function get_chapterlist() + local pos = mp.get_property_number('chapter', 0) + 1 + local count, limlist = limited_list('chapter-list', pos) + if count == 0 then + return 'No chapters.' + end + + local message = string.format('Chapters [%d/%d]:\n', pos, count) + for i, v in ipairs(limlist) do + local time = mp.format_time(v.time) + local title = v.title + if title == nil then + title = string.format('Chapter %02d', i) + end + message = string.format('%s[%s] %s %s\n', message, time, + (v.current and '●' or '○'), title) + end + return message +end + +function show_message(text, duration) + + --print("text: "..text.." duration: " .. duration) + if duration == nil then + duration = tonumber(mp.get_property("options/osd-duration")) / 1000 + elseif not type(duration) == "number" then + print("duration: " .. duration) + end + + -- cut the text short, otherwise the following functions + -- may slow down massively on huge input + text = string.sub(text, 0, 4000) + + -- replace actual linebreaks with ASS linebreaks + text = string.gsub(text, "\n", "\\N") + + state.message_text = text + + if not state.message_hide_timer then + state.message_hide_timer = mp.add_timeout(0, request_tick) + end + state.message_hide_timer:kill() + state.message_hide_timer.timeout = duration + state.message_hide_timer:resume() + request_tick() +end + +function render_message(ass) + if state.message_hide_timer and state.message_hide_timer:is_enabled() and + state.message_text + then + local _, lines = string.gsub(state.message_text, "\\N", "") + + local fontsize = tonumber(mp.get_property("options/osd-font-size")) + local outline = tonumber(mp.get_property("options/osd-border-size")) + local maxlines = math.ceil(osc_param.unscaled_y*0.75 / fontsize) + local counterscale = osc_param.playresy / osc_param.unscaled_y + + fontsize = fontsize * counterscale / math.max(0.65 + math.min(lines/maxlines, 1), 1) + outline = outline * counterscale / math.max(0.75 + math.min(lines/maxlines, 1)/2, 1) + + local style = "{\\bord" .. outline .. "\\fs" .. fontsize .. "}" + + + ass:new_event() + ass:append(style .. state.message_text) + else + state.message_text = nil + end +end + +-- +-- Initialisation and Layout +-- + +function new_element(name, type) + elements[name] = {} + elements[name].type = type + + -- add default stuff + elements[name].eventresponder = {} + elements[name].visible = true + elements[name].enabled = true + elements[name].softrepeat = false + elements[name].styledown = (type == "button") + elements[name].state = {} + + if (type == "slider") then + elements[name].slider = {min = {value = 0}, max = {value = 100}} + end + + + return elements[name] +end + +function add_layout(name) + if not (elements[name] == nil) then + -- new layout + elements[name].layout = {} + + -- set layout defaults + elements[name].layout.layer = 50 + elements[name].layout.alpha = {[1] = 0, [2] = 255, [3] = 255, [4] = 255} + + if (elements[name].type == "button") then + elements[name].layout.button = { + maxchars = nil, + } + elseif (elements[name].type == "slider") then + -- slider defaults + elements[name].layout.slider = { + border = 1, + gap = 1, + nibbles_top = true, + nibbles_bottom = true, + stype = "slider", + adjust_tooltip = true, + tooltip_style = "", + tooltip_an = 2, + alpha = {[1] = 0, [2] = 255, [3] = 88, [4] = 255}, + } + elseif (elements[name].type == "box") then + elements[name].layout.box = {radius = 0, hexagon = false} + end + + return elements[name].layout + else + msg.error("Can't add_layout to element \""..name.."\", doesn't exist.") + end +end + +-- Window Controls +function window_controls(topbar) + local wc_geo = { + x = 0, + y = 30 + user_opts.barmargin, + an = 1, + w = osc_param.playresx, + h = 30, + } + + local alignment = window_controls_alignment() + local controlbox_w = window_control_box_width + local titlebox_w = wc_geo.w - controlbox_w + + -- Default alignment is "right" + local controlbox_left = wc_geo.w - controlbox_w + local titlebox_left = wc_geo.x + local titlebox_right = wc_geo.w - controlbox_w + + if alignment == "left" then + controlbox_left = wc_geo.x + titlebox_left = wc_geo.x + controlbox_w + titlebox_right = wc_geo.w + end + + add_area("window-controls", + get_hitbox_coords(controlbox_left, wc_geo.y, wc_geo.an, + controlbox_w, wc_geo.h)) + + local lo + + -- Background Bar + new_element("wcbar", "box") + lo = add_layout("wcbar") + lo.geometry = wc_geo + lo.layer = 10 + lo.style = osc_styles.wcBar + lo.alpha[1] = user_opts.boxalpha + + local button_y = wc_geo.y - (wc_geo.h / 2) + local first_geo = + {x = controlbox_left + 5, y = button_y, an = 4, w = 25, h = 25} + local second_geo = + {x = controlbox_left + 30, y = button_y, an = 4, w = 25, h = 25} + local third_geo = + {x = controlbox_left + 55, y = button_y, an = 4, w = 25, h = 25} + + -- Window control buttons use symbols in the custom mpv osd font + -- because the official unicode codepoints are sufficiently + -- exotic that a system might lack an installed font with them, + -- and libass will complain that they are not present in the + -- default font, even if another font with them is available. + + -- Close: 🗙 + ne = new_element("close", "button") + ne.content = "\238\132\149" + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("quit") end + lo = add_layout("close") + lo.geometry = alignment == "left" and first_geo or third_geo + lo.style = osc_styles.wcButtons + + -- Minimize: 🗕 + ne = new_element("minimize", "button") + ne.content = "\238\132\146" + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("cycle", "window-minimized") end + lo = add_layout("minimize") + lo.geometry = alignment == "left" and second_geo or first_geo + lo.style = osc_styles.wcButtons + + -- Maximize: 🗖 /🗗 + ne = new_element("maximize", "button") + if state.maximized or state.fullscreen then + ne.content = "\238\132\148" + else + ne.content = "\238\132\147" + end + ne.eventresponder["mbtn_left_up"] = + function () + if state.fullscreen then + mp.commandv("cycle", "fullscreen") + else + mp.commandv("cycle", "window-maximized") + end + end + lo = add_layout("maximize") + lo.geometry = alignment == "left" and third_geo or second_geo + lo.style = osc_styles.wcButtons + + -- deadzone below window controls + local sh_area_y0, sh_area_y1 + sh_area_y0 = user_opts.barmargin + sh_area_y1 = (wc_geo.y + (wc_geo.h / 2)) + + get_align(1 - (2 * user_opts.deadzonesize), + osc_param.playresy - (wc_geo.y + (wc_geo.h / 2)), 0, 0) + add_area("showhide_wc", wc_geo.x, sh_area_y0, wc_geo.w, sh_area_y1) + + if topbar then + -- The title is already there as part of the top bar + return + else + -- Apply boxvideo margins to the control bar + osc_param.video_margins.t = wc_geo.h / osc_param.playresy + end + + -- Window Title + ne = new_element("wctitle", "button") + ne.content = function () + local title = mp.command_native({"expand-text", user_opts.title}) + -- escape ASS, and strip newlines and trailing slashes + title = title:gsub("\\n", " "):gsub("\\$", ""):gsub("{","\\{") + return not (title == "") and title or "mpv" + end + local left_pad = 5 + local right_pad = 10 + lo = add_layout("wctitle") + lo.geometry = + { x = titlebox_left + left_pad, y = wc_geo.y - 3, an = 1, + w = titlebox_w, h = wc_geo.h } + lo.style = string.format("%s{\\clip(%f,%f,%f,%f)}", + osc_styles.wcTitle, + titlebox_left + left_pad, wc_geo.y - wc_geo.h, + titlebox_right - right_pad , wc_geo.y + wc_geo.h) + + add_area("window-controls-title", + titlebox_left, 0, titlebox_right, wc_geo.h) +end + +-- +-- Layouts +-- + +local layouts = {} + +-- Classic box layout +layouts["box"] = function () + + local osc_geo = { + w = 550, -- width + h = 138, -- height + r = 10, -- corner-radius + p = 15, -- padding + } + + -- make sure the OSC actually fits into the video + if (osc_param.playresx < (osc_geo.w + (2 * osc_geo.p))) then + osc_param.playresy = (osc_geo.w+(2*osc_geo.p))/osc_param.display_aspect + osc_param.playresx = osc_param.playresy * osc_param.display_aspect + end + + -- position of the controller according to video aspect and valignment + local posX = math.floor(get_align(user_opts.halign, osc_param.playresx, + osc_geo.w, 0)) + local posY = math.floor(get_align(user_opts.valign, osc_param.playresy, + osc_geo.h, 0)) + + -- position offset for contents aligned at the borders of the box + local pos_offsetX = (osc_geo.w - (2*osc_geo.p)) / 2 + local pos_offsetY = (osc_geo.h - (2*osc_geo.p)) / 2 + + osc_param.areas = {} -- delete areas + + -- area for active mouse input + add_area("input", get_hitbox_coords(posX, posY, 5, osc_geo.w, osc_geo.h)) + + -- area for show/hide + local sh_area_y0, sh_area_y1 + if user_opts.valign > 0 then + -- deadzone above OSC + sh_area_y0 = get_align(-1 + (2*user_opts.deadzonesize), + posY - (osc_geo.h / 2), 0, 0) + sh_area_y1 = osc_param.playresy + else + -- deadzone below OSC + sh_area_y0 = 0 + sh_area_y1 = (posY + (osc_geo.h / 2)) + + get_align(1 - (2*user_opts.deadzonesize), + osc_param.playresy - (posY + (osc_geo.h / 2)), 0, 0) + end + add_area("showhide", 0, sh_area_y0, osc_param.playresx, sh_area_y1) + + -- fetch values + local osc_w, osc_h, osc_r, osc_p = + osc_geo.w, osc_geo.h, osc_geo.r, osc_geo.p + + local lo + + -- + -- Background box + -- + + new_element("bgbox", "box") + lo = add_layout("bgbox") + + lo.geometry = {x = posX, y = posY, an = 5, w = osc_w, h = osc_h} + lo.layer = 10 + lo.style = osc_styles.box + lo.alpha[1] = user_opts.boxalpha + lo.alpha[3] = user_opts.boxalpha + lo.box.radius = osc_r + + -- + -- Title row + -- + + local titlerowY = posY - pos_offsetY - 10 + + lo = add_layout("title") + lo.geometry = {x = posX, y = titlerowY, an = 8, w = 496, h = 12} + lo.style = osc_styles.vidtitle + lo.button.maxchars = user_opts.boxmaxchars + + lo = add_layout("pl_prev") + lo.geometry = + {x = (posX - pos_offsetX), y = titlerowY, an = 7, w = 12, h = 12} + lo.style = osc_styles.topButtons + + lo = add_layout("pl_next") + lo.geometry = + {x = (posX + pos_offsetX), y = titlerowY, an = 9, w = 12, h = 12} + lo.style = osc_styles.topButtons + + -- + -- Big buttons + -- + + local bigbtnrowY = posY - pos_offsetY + 35 + local bigbtndist = 60 + + lo = add_layout("playpause") + lo.geometry = + {x = posX, y = bigbtnrowY, an = 5, w = 40, h = 40} + lo.style = osc_styles.bigButtons + + lo = add_layout("skipback") + lo.geometry = + {x = posX - bigbtndist, y = bigbtnrowY, an = 5, w = 40, h = 40} + lo.style = osc_styles.bigButtons + + lo = add_layout("skipfrwd") + lo.geometry = + {x = posX + bigbtndist, y = bigbtnrowY, an = 5, w = 40, h = 40} + lo.style = osc_styles.bigButtons + + lo = add_layout("ch_prev") + lo.geometry = + {x = posX - (bigbtndist * 2), y = bigbtnrowY, an = 5, w = 40, h = 40} + lo.style = osc_styles.bigButtons + + lo = add_layout("ch_next") + lo.geometry = + {x = posX + (bigbtndist * 2), y = bigbtnrowY, an = 5, w = 40, h = 40} + lo.style = osc_styles.bigButtons + + lo = add_layout("cy_audio") + lo.geometry = + {x = posX - pos_offsetX, y = bigbtnrowY, an = 1, w = 70, h = 18} + lo.style = osc_styles.smallButtonsL + + lo = add_layout("cy_sub") + lo.geometry = + {x = posX - pos_offsetX, y = bigbtnrowY, an = 7, w = 70, h = 18} + lo.style = osc_styles.smallButtonsL + + lo = add_layout("tog_fs") + lo.geometry = + {x = posX+pos_offsetX - 25, y = bigbtnrowY, an = 4, w = 25, h = 25} + lo.style = osc_styles.smallButtonsR + + lo = add_layout("volume") + lo.geometry = + {x = posX+pos_offsetX - (25 * 2) - osc_geo.p, + y = bigbtnrowY, an = 4, w = 25, h = 25} + lo.style = osc_styles.smallButtonsR + + -- + -- Seekbar + -- + + lo = add_layout("seekbar") + lo.geometry = + {x = posX, y = posY+pos_offsetY-22, an = 2, w = pos_offsetX*2, h = 15} + lo.style = osc_styles.timecodes + lo.slider.tooltip_style = osc_styles.vidtitle + lo.slider.stype = user_opts["seekbarstyle"] + lo.slider.rtype = user_opts["seekrangestyle"] + + -- + -- Timecodes + Cache + -- + + local bottomrowY = posY + pos_offsetY - 5 + + lo = add_layout("tc_left") + lo.geometry = + {x = posX - pos_offsetX, y = bottomrowY, an = 4, w = 110, h = 18} + lo.style = osc_styles.timecodes + + lo = add_layout("tc_right") + lo.geometry = + {x = posX + pos_offsetX, y = bottomrowY, an = 6, w = 110, h = 18} + lo.style = osc_styles.timecodes + + lo = add_layout("cache") + lo.geometry = + {x = posX, y = bottomrowY, an = 5, w = 110, h = 18} + lo.style = osc_styles.timecodes + +end + +-- slim box layout +layouts["slimbox"] = function () + + local osc_geo = { + w = 660, -- width + h = 70, -- height + r = 10, -- corner-radius + } + + -- make sure the OSC actually fits into the video + if (osc_param.playresx < (osc_geo.w)) then + osc_param.playresy = (osc_geo.w)/osc_param.display_aspect + osc_param.playresx = osc_param.playresy * osc_param.display_aspect + end + + -- position of the controller according to video aspect and valignment + local posX = math.floor(get_align(user_opts.halign, osc_param.playresx, + osc_geo.w, 0)) + local posY = math.floor(get_align(user_opts.valign, osc_param.playresy, + osc_geo.h, 0)) + + osc_param.areas = {} -- delete areas + + -- area for active mouse input + add_area("input", get_hitbox_coords(posX, posY, 5, osc_geo.w, osc_geo.h)) + + -- area for show/hide + local sh_area_y0, sh_area_y1 + if user_opts.valign > 0 then + -- deadzone above OSC + sh_area_y0 = get_align(-1 + (2*user_opts.deadzonesize), + posY - (osc_geo.h / 2), 0, 0) + sh_area_y1 = osc_param.playresy + else + -- deadzone below OSC + sh_area_y0 = 0 + sh_area_y1 = (posY + (osc_geo.h / 2)) + + get_align(1 - (2*user_opts.deadzonesize), + osc_param.playresy - (posY + (osc_geo.h / 2)), 0, 0) + end + add_area("showhide", 0, sh_area_y0, osc_param.playresx, sh_area_y1) + + local lo + + local tc_w, ele_h, inner_w = 100, 20, osc_geo.w - 100 + + -- styles + local styles = { + box = "{\\rDefault\\blur0\\bord1\\1c&H000000\\3c&HFFFFFF}", + timecodes = "{\\1c&HFFFFFF\\3c&H000000\\fs20\\bord2\\blur1}", + tooltip = "{\\1c&HFFFFFF\\3c&H000000\\fs12\\bord1\\blur0.5}", + } + + + new_element("bgbox", "box") + lo = add_layout("bgbox") + + lo.geometry = {x = posX, y = posY - 1, an = 2, w = inner_w, h = ele_h} + lo.layer = 10 + lo.style = osc_styles.box + lo.alpha[1] = user_opts.boxalpha + lo.alpha[3] = 0 + if not (user_opts["seekbarstyle"] == "bar") then + lo.box.radius = osc_geo.r + lo.box.hexagon = user_opts["seekbarstyle"] == "diamond" + end + + + lo = add_layout("seekbar") + lo.geometry = + {x = posX, y = posY - 1, an = 2, w = inner_w, h = ele_h} + lo.style = osc_styles.timecodes + lo.slider.border = 0 + lo.slider.gap = 1.5 + lo.slider.tooltip_style = styles.tooltip + lo.slider.stype = user_opts["seekbarstyle"] + lo.slider.rtype = user_opts["seekrangestyle"] + lo.slider.adjust_tooltip = false + + -- + -- Timecodes + -- + + lo = add_layout("tc_left") + lo.geometry = + {x = posX - (inner_w/2) + osc_geo.r, y = posY + 1, + an = 7, w = tc_w, h = ele_h} + lo.style = styles.timecodes + lo.alpha[3] = user_opts.boxalpha + + lo = add_layout("tc_right") + lo.geometry = + {x = posX + (inner_w/2) - osc_geo.r, y = posY + 1, + an = 9, w = tc_w, h = ele_h} + lo.style = styles.timecodes + lo.alpha[3] = user_opts.boxalpha + + -- Cache + + lo = add_layout("cache") + lo.geometry = + {x = posX, y = posY + 1, + an = 8, w = tc_w, h = ele_h} + lo.style = styles.timecodes + lo.alpha[3] = user_opts.boxalpha + + +end + +function bar_layout(direction) + local osc_geo = { + x = -2, + y, + an = (direction < 0) and 7 or 1, + w, + h = 56, + } + + local padX = 9 + local padY = 3 + local buttonW = 27 + local tcW = (state.tc_ms) and 170 or 110 + if user_opts.tcspace >= 50 and user_opts.tcspace <= 200 then + -- adjust our hardcoded font size estimation + tcW = tcW * user_opts.tcspace / 100 + end + + local tsW = 90 + local minW = (buttonW + padX)*5 + (tcW + padX)*4 + (tsW + padX)*2 + + -- Special topbar handling when window controls are present + local padwc_l + local padwc_r + if direction < 0 or not window_controls_enabled() then + padwc_l = 0 + padwc_r = 0 + elseif window_controls_alignment() == "left" then + padwc_l = window_control_box_width + padwc_r = 0 + else + padwc_l = 0 + padwc_r = window_control_box_width + end + + if ((osc_param.display_aspect > 0) and (osc_param.playresx < minW)) then + osc_param.playresy = minW / osc_param.display_aspect + osc_param.playresx = osc_param.playresy * osc_param.display_aspect + end + + osc_geo.y = direction * (54 + user_opts.barmargin) + osc_geo.w = osc_param.playresx + 4 + if direction < 0 then + osc_geo.y = osc_geo.y + osc_param.playresy + end + + local line1 = osc_geo.y - direction * (9 + padY) + local line2 = osc_geo.y - direction * (36 + padY) + + osc_param.areas = {} + + add_area("input", get_hitbox_coords(osc_geo.x, osc_geo.y, osc_geo.an, + osc_geo.w, osc_geo.h)) + + local sh_area_y0, sh_area_y1 + if direction > 0 then + -- deadzone below OSC + sh_area_y0 = user_opts.barmargin + sh_area_y1 = (osc_geo.y + (osc_geo.h / 2)) + + get_align(1 - (2*user_opts.deadzonesize), + osc_param.playresy - (osc_geo.y + (osc_geo.h / 2)), 0, 0) + else + -- deadzone above OSC + sh_area_y0 = get_align(-1 + (2*user_opts.deadzonesize), + osc_geo.y - (osc_geo.h / 2), 0, 0) + sh_area_y1 = osc_param.playresy - user_opts.barmargin + end + add_area("showhide", 0, sh_area_y0, osc_param.playresx, sh_area_y1) + + local lo, geo + + -- Background bar + new_element("bgbox", "box") + lo = add_layout("bgbox") + + lo.geometry = osc_geo + lo.layer = 10 + lo.style = osc_styles.box + lo.alpha[1] = user_opts.boxalpha + + + -- Playlist prev/next + geo = { x = osc_geo.x + padX, y = line1, + an = 4, w = 18, h = 18 - padY } + lo = add_layout("pl_prev") + lo.geometry = geo + lo.style = osc_styles.topButtonsBar + + geo = { x = geo.x + geo.w + padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } + lo = add_layout("pl_next") + lo.geometry = geo + lo.style = osc_styles.topButtonsBar + + local t_l = geo.x + geo.w + padX + + -- Cache + geo = { x = osc_geo.x + osc_geo.w - padX, y = geo.y, + an = 6, w = 150, h = geo.h } + lo = add_layout("cache") + lo.geometry = geo + lo.style = osc_styles.vidtitleBar + + local t_r = geo.x - geo.w - padX*2 + + -- Title + geo = { x = t_l, y = geo.y, an = 4, + w = t_r - t_l, h = geo.h } + lo = add_layout("title") + lo.geometry = geo + lo.style = string.format("%s{\\clip(%f,%f,%f,%f)}", + osc_styles.vidtitleBar, + geo.x, geo.y-geo.h, geo.w, geo.y+geo.h) + + + -- Playback control buttons + geo = { x = osc_geo.x + padX + padwc_l, y = line2, an = 4, + w = buttonW, h = 36 - padY*2} + lo = add_layout("playpause") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + geo = { x = geo.x + geo.w + padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } + lo = add_layout("ch_prev") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + geo = { x = geo.x + geo.w + padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } + lo = add_layout("ch_next") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + -- Left timecode + geo = { x = geo.x + geo.w + padX + tcW, y = geo.y, an = 6, + w = tcW, h = geo.h } + lo = add_layout("tc_left") + lo.geometry = geo + lo.style = osc_styles.timecodesBar + + local sb_l = geo.x + padX + + -- Fullscreen button + geo = { x = osc_geo.x + osc_geo.w - buttonW - padX - padwc_r, y = geo.y, an = 4, + w = buttonW, h = geo.h } + lo = add_layout("tog_fs") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + -- START quality-menu + geo = { x = geo.x - geo.w - padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } + lo = add_layout("quality-menu") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + -- END quality-menu + + -- Volume + geo = { x = geo.x - geo.w - padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } + lo = add_layout("volume") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + -- Track selection buttons + geo = { x = geo.x - tsW - padX, y = geo.y, an = geo.an, w = tsW, h = geo.h } + lo = add_layout("cy_sub") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + geo = { x = geo.x - geo.w - padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } + lo = add_layout("cy_audio") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + + -- Right timecode + geo = { x = geo.x - padX - tcW - 10, y = geo.y, an = geo.an, + w = tcW, h = geo.h } + lo = add_layout("tc_right") + lo.geometry = geo + lo.style = osc_styles.timecodesBar + + local sb_r = geo.x - padX + + + -- Seekbar + geo = { x = sb_l, y = geo.y, an = geo.an, + w = math.max(0, sb_r - sb_l), h = geo.h } + new_element("bgbar1", "box") + lo = add_layout("bgbar1") + + lo.geometry = geo + lo.layer = 15 + lo.style = osc_styles.timecodesBar + lo.alpha[1] = + math.min(255, user_opts.boxalpha + (255 - user_opts.boxalpha)*0.8) + if not (user_opts["seekbarstyle"] == "bar") then + lo.box.radius = geo.h / 2 + lo.box.hexagon = user_opts["seekbarstyle"] == "diamond" + end + + lo = add_layout("seekbar") + lo.geometry = geo + lo.style = osc_styles.timecodesBar + lo.slider.border = 0 + lo.slider.gap = 2 + lo.slider.tooltip_style = osc_styles.timePosBar + lo.slider.tooltip_an = 5 + lo.slider.stype = user_opts["seekbarstyle"] + lo.slider.rtype = user_opts["seekrangestyle"] + + if direction < 0 then + osc_param.video_margins.b = osc_geo.h / osc_param.playresy + else + osc_param.video_margins.t = osc_geo.h / osc_param.playresy + end +end + +layouts["bottombar"] = function() + bar_layout(-1) +end + +layouts["topbar"] = function() + bar_layout(1) +end + +-- Validate string type user options +function validate_user_opts() + if layouts[user_opts.layout] == nil then + msg.warn("Invalid setting \""..user_opts.layout.."\" for layout") + user_opts.layout = "bottombar" + end + + if user_opts.seekbarstyle ~= "bar" and + user_opts.seekbarstyle ~= "diamond" and + user_opts.seekbarstyle ~= "knob" then + msg.warn("Invalid setting \"" .. user_opts.seekbarstyle + .. "\" for seekbarstyle") + user_opts.seekbarstyle = "bar" + end + + if user_opts.seekrangestyle ~= "bar" and + user_opts.seekrangestyle ~= "line" and + user_opts.seekrangestyle ~= "slider" and + user_opts.seekrangestyle ~= "inverted" and + user_opts.seekrangestyle ~= "none" then + msg.warn("Invalid setting \"" .. user_opts.seekrangestyle + .. "\" for seekrangestyle") + user_opts.seekrangestyle = "inverted" + end + + if user_opts.seekrangestyle == "slider" and + user_opts.seekbarstyle == "bar" then + msg.warn("Using \"slider\" seekrangestyle together with \"bar\" seekbarstyle is not supported") + user_opts.seekrangestyle = "inverted" + end + + if user_opts.windowcontrols ~= "auto" and + user_opts.windowcontrols ~= "yes" and + user_opts.windowcontrols ~= "no" then + msg.warn("windowcontrols cannot be \"" .. + user_opts.windowcontrols .. "\". Ignoring.") + user_opts.windowcontrols = "auto" + end + if user_opts.windowcontrols_alignment ~= "right" and + user_opts.windowcontrols_alignment ~= "left" then + msg.warn("windowcontrols_alignment cannot be \"" .. + user_opts.windowcontrols_alignment .. "\". Ignoring.") + user_opts.windowcontrols_alignment = "right" + end +end + +function update_options(list) + validate_user_opts() + request_tick() + visibility_mode(user_opts.visibility, true) + update_duration_watch() + request_init() +end + +local UNICODE_MINUS = string.char(0xe2, 0x88, 0x92) -- UTF-8 for U+2212 MINUS SIGN + +-- OSC INIT +function osc_init() + msg.debug("osc_init") + + -- set canvas resolution according to display aspect and scaling setting + local baseResY = 720 + local display_w, display_h, display_aspect = mp.get_osd_size() + local scale = 1 + + if (mp.get_property("video") == "no") then -- dummy/forced window + scale = user_opts.scaleforcedwindow + elseif state.fullscreen then + scale = user_opts.scalefullscreen + else + scale = user_opts.scalewindowed + end + + if user_opts.vidscale then + osc_param.unscaled_y = baseResY + else + osc_param.unscaled_y = display_h + end + osc_param.playresy = osc_param.unscaled_y / scale + if (display_aspect > 0) then + osc_param.display_aspect = display_aspect + end + osc_param.playresx = osc_param.playresy * osc_param.display_aspect + + -- stop seeking with the slider to prevent skipping files + state.active_element = nil + + osc_param.video_margins = {l = 0, r = 0, t = 0, b = 0} + + elements = {} + + -- some often needed stuff + local pl_count = mp.get_property_number("playlist-count", 0) + local have_pl = (pl_count > 1) + local pl_pos = mp.get_property_number("playlist-pos", 0) + 1 + local have_ch = (mp.get_property_number("chapters", 0) > 0) + local loop = mp.get_property("loop-playlist", "no") + + local ne + + -- title + ne = new_element("title", "button") + + ne.content = function () + local title = state.forced_title or + mp.command_native({"expand-text", user_opts.title}) + -- escape ASS, and strip newlines and trailing slashes + title = title:gsub("\\n", " "):gsub("\\$", ""):gsub("{","\\{") + return not (title == "") and title or "mpv" + end + + ne.eventresponder["mbtn_left_up"] = function () + local title = mp.get_property_osd("media-title") + if (have_pl) then + title = string.format("[%d/%d] %s", countone(pl_pos - 1), + pl_count, title) + end + show_message(title) + end + + ne.eventresponder["mbtn_right_up"] = + function () show_message(mp.get_property_osd("filename")) end + + -- playlist buttons + + -- prev + ne = new_element("pl_prev", "button") + + ne.content = "\238\132\144" + ne.enabled = (pl_pos > 1) or (loop ~= "no") + ne.eventresponder["mbtn_left_up"] = + function () + mp.commandv("playlist-prev", "weak") + if user_opts.playlist_osd then + show_message(get_playlist(), 3) + end + end + ne.eventresponder["shift+mbtn_left_up"] = + function () show_message(get_playlist(), 3) end + ne.eventresponder["mbtn_right_up"] = + function () show_message(get_playlist(), 3) end + + --next + ne = new_element("pl_next", "button") + + ne.content = "\238\132\129" + ne.enabled = (have_pl and (pl_pos < pl_count)) or (loop ~= "no") + ne.eventresponder["mbtn_left_up"] = + function () + mp.commandv("playlist-next", "weak") + if user_opts.playlist_osd then + show_message(get_playlist(), 3) + end + end + ne.eventresponder["shift+mbtn_left_up"] = + function () show_message(get_playlist(), 3) end + ne.eventresponder["mbtn_right_up"] = + function () show_message(get_playlist(), 3) end + + + -- big buttons + + --playpause + ne = new_element("playpause", "button") + + ne.content = function () + if mp.get_property("pause") == "yes" then + return ("\238\132\129") + else + return ("\238\128\130") + end + end + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("cycle", "pause") end + + --skipback + ne = new_element("skipback", "button") + + ne.softrepeat = true + ne.content = "\238\128\132" + ne.eventresponder["mbtn_left_down"] = + function () mp.commandv("seek", -5, "relative", "keyframes") end + ne.eventresponder["shift+mbtn_left_down"] = + function () mp.commandv("frame-back-step") end + ne.eventresponder["mbtn_right_down"] = + function () mp.commandv("seek", -30, "relative", "keyframes") end + + --skipfrwd + ne = new_element("skipfrwd", "button") + + ne.softrepeat = true + ne.content = "\238\128\133" + ne.eventresponder["mbtn_left_down"] = + function () mp.commandv("seek", 10, "relative", "keyframes") end + ne.eventresponder["shift+mbtn_left_down"] = + function () mp.commandv("frame-step") end + ne.eventresponder["mbtn_right_down"] = + function () mp.commandv("seek", 60, "relative", "keyframes") end + + --ch_prev + ne = new_element("ch_prev", "button") + + ne.enabled = have_ch + ne.content = "\238\132\132" + ne.eventresponder["mbtn_left_up"] = + function () + mp.commandv("add", "chapter", -1) + if user_opts.chapters_osd then + show_message(get_chapterlist(), 3) + end + end + ne.eventresponder["shift+mbtn_left_up"] = + function () show_message(get_chapterlist(), 3) end + ne.eventresponder["mbtn_right_up"] = + function () show_message(get_chapterlist(), 3) end + + --ch_next + ne = new_element("ch_next", "button") + + ne.enabled = have_ch + ne.content = "\238\132\133" + ne.eventresponder["mbtn_left_up"] = + function () + mp.commandv("add", "chapter", 1) + if user_opts.chapters_osd then + show_message(get_chapterlist(), 3) + end + end + ne.eventresponder["shift+mbtn_left_up"] = + function () show_message(get_chapterlist(), 3) end + ne.eventresponder["mbtn_right_up"] = + function () show_message(get_chapterlist(), 3) end + + -- + update_tracklist() + + --cy_audio + ne = new_element("cy_audio", "button") + + ne.enabled = (#tracks_osc.audio > 0) + ne.content = function () + local aid = "–" + if not (get_track("audio") == 0) then + aid = get_track("audio") + end + return ("\238\132\134" .. osc_styles.smallButtonsLlabel + .. " " .. aid .. "/" .. #tracks_osc.audio) + end + ne.eventresponder["mbtn_left_up"] = + function () set_track("audio", 1) end + ne.eventresponder["mbtn_right_up"] = + function () set_track("audio", -1) end + ne.eventresponder["shift+mbtn_left_down"] = + function () show_message(get_tracklist("audio"), 2) end + + --cy_sub + ne = new_element("cy_sub", "button") + + ne.enabled = (#tracks_osc.sub > 0) + ne.content = function () + local sid = "–" + if not (get_track("sub") == 0) then + sid = get_track("sub") + end + return ("\238\132\135" .. osc_styles.smallButtonsLlabel + .. " " .. sid .. "/" .. #tracks_osc.sub) + end + ne.eventresponder["mbtn_left_up"] = + function () set_track("sub", 1) end + ne.eventresponder["mbtn_right_up"] = + function () set_track("sub", -1) end + ne.eventresponder["shift+mbtn_left_down"] = + function () show_message(get_tracklist("sub"), 2) end + + --tog_fs + ne = new_element("tog_fs", "button") + ne.content = function () + if (state.fullscreen) then + return ("\238\132\137") + else + return ("\238\132\136") + end + end + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("cycle", "fullscreen") end + + --seekbar + ne = new_element("seekbar", "slider") + + ne.enabled = not (mp.get_property("percent-pos") == nil) + state.slider_element = ne.enabled and ne or nil -- used for forced_title + ne.slider.markerF = function () + local duration = mp.get_property_number("duration", nil) + if not (duration == nil) then + local chapters = mp.get_property_native("chapter-list", {}) + local markers = {} + for n = 1, #chapters do + markers[n] = (chapters[n].time / duration * 100) + end + return markers + else + return {} + end + end + ne.slider.posF = + function () return mp.get_property_number("percent-pos", nil) end + ne.slider.tooltipF = function (pos) + local duration = mp.get_property_number("duration", nil) + if not ((duration == nil) or (pos == nil)) then + possec = duration * (pos / 100) + return mp.format_time(possec) + else + return "" + end + end + ne.slider.seekRangesF = function() + if user_opts.seekrangestyle == "none" then + return nil + end + local cache_state = state.cache_state + if not cache_state then + return nil + end + local duration = mp.get_property_number("duration", nil) + if (duration == nil) or duration <= 0 then + return nil + end + local ranges = cache_state["seekable-ranges"] + if #ranges == 0 then + return nil + end + local nranges = {} + for _, range in pairs(ranges) do + nranges[#nranges + 1] = { + ["start"] = 100 * range["start"] / duration, + ["end"] = 100 * range["end"] / duration, + } + end + return nranges + end + ne.eventresponder["mouse_move"] = --keyframe seeking when mouse is dragged + function (element) + -- mouse move events may pile up during seeking and may still get + -- sent when the user is done seeking, so we need to throw away + -- identical seeks + local seekto = get_slider_value(element) + if (element.state.lastseek == nil) or + (not (element.state.lastseek == seekto)) then + local flags = "absolute-percent" + if not user_opts.seekbarkeyframes then + flags = flags .. "+exact" + end + mp.commandv("seek", seekto, flags) + element.state.lastseek = seekto + end + + end + ne.eventresponder["mbtn_left_down"] = --exact seeks on single clicks + function (element) mp.commandv("seek", get_slider_value(element), + "absolute-percent", "exact") end + ne.eventresponder["reset"] = + function (element) element.state.lastseek = nil end + + + -- tc_left (current pos) + ne = new_element("tc_left", "button") + + ne.content = function () + if (state.tc_ms) then + return (mp.get_property_osd("playback-time/full")) + else + return (mp.get_property_osd("playback-time")) + end + end + ne.eventresponder["mbtn_left_up"] = function () + state.tc_ms = not state.tc_ms + request_init() + end + + -- tc_right (total/remaining time) + ne = new_element("tc_right", "button") + + ne.visible = (mp.get_property_number("duration", 0) > 0) + ne.content = function () + if (state.rightTC_trem) then + local minus = user_opts.unicodeminus and UNICODE_MINUS or "-" + if state.tc_ms then + return (minus..mp.get_property_osd("playtime-remaining/full")) + else + return (minus..mp.get_property_osd("playtime-remaining")) + end + else + if state.tc_ms then + return (mp.get_property_osd("duration/full")) + else + return (mp.get_property_osd("duration")) + end + end + end + ne.eventresponder["mbtn_left_up"] = + function () state.rightTC_trem = not state.rightTC_trem end + + -- cache + ne = new_element("cache", "button") + + ne.content = function () + local cache_state = state.cache_state + if not (cache_state and cache_state["seekable-ranges"] and + #cache_state["seekable-ranges"] > 0) then + -- probably not a network stream + return "" + end + local dmx_cache = cache_state and cache_state["cache-duration"] + local thresh = math.min(state.dmx_cache * 0.05, 5) -- 5% or 5s + if dmx_cache and math.abs(dmx_cache - state.dmx_cache) >= thresh then + state.dmx_cache = dmx_cache + else + dmx_cache = state.dmx_cache + end + local min = math.floor(dmx_cache / 60) + local sec = math.floor(dmx_cache % 60) -- don't round e.g. 59.9 to 60 + return "Cache: " .. (min > 0 and + string.format("%sm%02.0fs", min, sec) or + string.format("%3.0fs", sec)) + end + + -- START quality-menu + ne = new_element("quality-menu", "button") + ne.content = function() + return ("≚") + end + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("script-message", "video_formats_toggle") end + ne.eventresponder["mbtn_right_up"] = + function () mp.commandv("script-message", "audio_formats_toggle") end + -- END quality-menu + + -- volume + ne = new_element("volume", "button") + + ne.content = function() + local volume = mp.get_property_number("volume", 0) + local mute = mp.get_property_native("mute") + local volicon = {"\238\132\139", "\238\132\140", + "\238\132\141", "\238\132\142"} + if volume == 0 or mute then + return "\238\132\138" + else + return volicon[math.min(4,math.ceil(volume / (100/3)))] + end + end + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("cycle", "mute") end + + ne.eventresponder["wheel_up_press"] = + function () mp.commandv("osd-auto", "add", "volume", 5) end + ne.eventresponder["wheel_down_press"] = + function () mp.commandv("osd-auto", "add", "volume", -5) end + + + -- load layout + layouts[user_opts.layout]() + + -- load window controls + if window_controls_enabled() then + window_controls(user_opts.layout == "topbar") + end + + --do something with the elements + prepare_elements() + + update_margins() +end + +function reset_margins() + if state.using_video_margins then + for _, opt in ipairs(margins_opts) do + mp.set_property_number(opt[2], 0.0) + end + state.using_video_margins = false + end +end + +function update_margins() + local margins = osc_param.video_margins + + -- Don't use margins if it's visible only temporarily. + if (not state.osc_visible) or (get_hidetimeout() >= 0) or + (state.fullscreen and not user_opts.showfullscreen) or + (not state.fullscreen and not user_opts.showwindowed) + then + margins = {l = 0, r = 0, t = 0, b = 0} + end + + if user_opts.boxvideo then + -- check whether any margin option has a non-default value + local margins_used = false + + if not state.using_video_margins then + for _, opt in ipairs(margins_opts) do + if mp.get_property_number(opt[2], 0.0) ~= 0.0 then + margins_used = true + end + end + end + + if not margins_used then + for _, opt in ipairs(margins_opts) do + local v = margins[opt[1]] + if (v ~= 0) or state.using_video_margins then + mp.set_property_number(opt[2], v) + state.using_video_margins = true + end + end + end + else + reset_margins() + end + + utils.shared_script_property_set("osc-margins", + string.format("%f,%f,%f,%f", margins.l, margins.r, margins.t, margins.b)) +end + +function shutdown() + reset_margins() + utils.shared_script_property_set("osc-margins", nil) +end + +-- +-- Other important stuff +-- + + +function show_osc() + -- show when disabled can happen (e.g. mouse_move) due to async/delayed unbinding + if not state.enabled then return end + + msg.trace("show_osc") + --remember last time of invocation (mouse move) + state.showtime = mp.get_time() + + osc_visible(true) + + if (user_opts.fadeduration > 0) then + state.anitype = nil + end +end + +function hide_osc() + msg.trace("hide_osc") + if not state.enabled then + -- typically hide happens at render() from tick(), but now tick() is + -- no-op and won't render again to remove the osc, so do that manually. + state.osc_visible = false + render_wipe() + elseif (user_opts.fadeduration > 0) then + if not(state.osc_visible == false) then + state.anitype = "out" + request_tick() + end + else + osc_visible(false) + end +end + +function osc_visible(visible) + if state.osc_visible ~= visible then + state.osc_visible = visible + update_margins() + end + request_tick() +end + +function pause_state(name, enabled) + state.paused = enabled + request_tick() +end + +function cache_state(name, st) + state.cache_state = st + request_tick() +end + +-- Request that tick() is called (which typically re-renders the OSC). +-- The tick is then either executed immediately, or rate-limited if it was +-- called a small time ago. +function request_tick() + if state.tick_timer == nil then + state.tick_timer = mp.add_timeout(0, tick) + end + + if not state.tick_timer:is_enabled() then + local now = mp.get_time() + local timeout = tick_delay - (now - state.tick_last_time) + if timeout < 0 then + timeout = 0 + end + state.tick_timer.timeout = timeout + state.tick_timer:resume() + end +end + +function mouse_leave() + if get_hidetimeout() >= 0 then + hide_osc() + end + -- reset mouse position + state.last_mouseX, state.last_mouseY = nil, nil + state.mouse_in_window = false +end + +function request_init() + state.initREQ = true + request_tick() +end + +-- Like request_init(), but also request an immediate update +function request_init_resize() + request_init() + -- ensure immediate update + state.tick_timer:kill() + state.tick_timer.timeout = 0 + state.tick_timer:resume() +end + +function render_wipe() + msg.trace("render_wipe()") + state.osd.data = "" -- allows set_osd to immediately update on enable + state.osd:remove() +end + +function render() + msg.trace("rendering") + local current_screen_sizeX, current_screen_sizeY, aspect = mp.get_osd_size() + local mouseX, mouseY = get_virt_mouse_pos() + local now = mp.get_time() + + -- check if display changed, if so request reinit + if not (state.mp_screen_sizeX == current_screen_sizeX + and state.mp_screen_sizeY == current_screen_sizeY) then + + request_init_resize() + + state.mp_screen_sizeX = current_screen_sizeX + state.mp_screen_sizeY = current_screen_sizeY + end + + -- init management + if state.active_element then + -- mouse is held down on some element - keep ticking and igore initReq + -- till it's released, or else the mouse-up (click) will misbehave or + -- get ignored. that's because osc_init() recreates the osc elements, + -- but mouse handling depends on the elements staying unmodified + -- between mouse-down and mouse-up (using the index active_element). + request_tick() + elseif state.initREQ then + osc_init() + state.initREQ = false + + -- store initial mouse position + if (state.last_mouseX == nil or state.last_mouseY == nil) + and not (mouseX == nil or mouseY == nil) then + + state.last_mouseX, state.last_mouseY = mouseX, mouseY + end + end + + + -- fade animation + if not(state.anitype == nil) then + + if (state.anistart == nil) then + state.anistart = now + end + + if (now < state.anistart + (user_opts.fadeduration/1000)) then + + if (state.anitype == "in") then --fade in + osc_visible(true) + state.animation = scale_value(state.anistart, + (state.anistart + (user_opts.fadeduration/1000)), + 255, 0, now) + elseif (state.anitype == "out") then --fade out + state.animation = scale_value(state.anistart, + (state.anistart + (user_opts.fadeduration/1000)), + 0, 255, now) + end + + else + if (state.anitype == "out") then + osc_visible(false) + end + kill_animation() + end + else + kill_animation() + end + + --mouse show/hide area + for k,cords in pairs(osc_param.areas["showhide"]) do + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, "showhide") + end + if osc_param.areas["showhide_wc"] then + for k,cords in pairs(osc_param.areas["showhide_wc"]) do + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, "showhide_wc") + end + else + set_virt_mouse_area(0, 0, 0, 0, "showhide_wc") + end + do_enable_keybindings() + + --mouse input area + local mouse_over_osc = false + + for _,cords in ipairs(osc_param.areas["input"]) do + if state.osc_visible then -- activate only when OSC is actually visible + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, "input") + end + if state.osc_visible ~= state.input_enabled then + if state.osc_visible then + mp.enable_key_bindings("input") + else + mp.disable_key_bindings("input") + end + state.input_enabled = state.osc_visible + end + + if (mouse_hit_coords(cords.x1, cords.y1, cords.x2, cords.y2)) then + mouse_over_osc = true + end + end + + if osc_param.areas["window-controls"] then + for _,cords in ipairs(osc_param.areas["window-controls"]) do + if state.osc_visible then -- activate only when OSC is actually visible + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, "window-controls") + mp.enable_key_bindings("window-controls") + else + mp.disable_key_bindings("window-controls") + end + + if (mouse_hit_coords(cords.x1, cords.y1, cords.x2, cords.y2)) then + mouse_over_osc = true + end + end + end + + if osc_param.areas["window-controls-title"] then + for _,cords in ipairs(osc_param.areas["window-controls-title"]) do + if (mouse_hit_coords(cords.x1, cords.y1, cords.x2, cords.y2)) then + mouse_over_osc = true + end + end + end + + -- autohide + if not (state.showtime == nil) and (get_hidetimeout() >= 0) then + local timeout = state.showtime + (get_hidetimeout()/1000) - now + if timeout <= 0 then + if (state.active_element == nil) and not (mouse_over_osc) then + hide_osc() + end + else + -- the timer is only used to recheck the state and to possibly run + -- the code above again + if not state.hide_timer then + state.hide_timer = mp.add_timeout(0, tick) + end + state.hide_timer.timeout = timeout + -- re-arm + state.hide_timer:kill() + state.hide_timer:resume() + end + end + + + -- actual rendering + local ass = assdraw.ass_new() + + -- Messages + render_message(ass) + + -- actual OSC + if state.osc_visible then + render_elements(ass) + end + + -- submit + set_osd(osc_param.playresy * osc_param.display_aspect, + osc_param.playresy, ass.text) +end + +-- +-- Eventhandling +-- + +local function element_has_action(element, action) + return element and element.eventresponder and + element.eventresponder[action] +end + +function process_event(source, what) + local action = string.format("%s%s", source, + what and ("_" .. what) or "") + + if what == "down" or what == "press" then + + for n = 1, #elements do + + if mouse_hit(elements[n]) and + elements[n].eventresponder and + (elements[n].eventresponder[source .. "_up"] or + elements[n].eventresponder[action]) then + + if what == "down" then + state.active_element = n + state.active_event_source = source + end + -- fire the down or press event if the element has one + if element_has_action(elements[n], action) then + elements[n].eventresponder[action](elements[n]) + end + + end + end + + elseif what == "up" then + + if elements[state.active_element] then + local n = state.active_element + + if n == 0 then + --click on background (does not work) + elseif element_has_action(elements[n], action) and + mouse_hit(elements[n]) then + + elements[n].eventresponder[action](elements[n]) + end + + --reset active element + if element_has_action(elements[n], "reset") then + elements[n].eventresponder["reset"](elements[n]) + end + + end + state.active_element = nil + state.mouse_down_counter = 0 + + elseif source == "mouse_move" then + + state.mouse_in_window = true + + local mouseX, mouseY = get_virt_mouse_pos() + if (user_opts.minmousemove == 0) or + (not ((state.last_mouseX == nil) or (state.last_mouseY == nil)) and + ((math.abs(mouseX - state.last_mouseX) >= user_opts.minmousemove) + or (math.abs(mouseY - state.last_mouseY) >= user_opts.minmousemove) + ) + ) then + show_osc() + end + state.last_mouseX, state.last_mouseY = mouseX, mouseY + + local n = state.active_element + if element_has_action(elements[n], action) then + elements[n].eventresponder[action](elements[n]) + end + end + + -- ensure rendering after any (mouse) event - icons could change etc + request_tick() +end + + +local logo_lines = { + -- White border + "{\\c&HE5E5E5&\\p6}m 895 10 b 401 10 0 410 0 905 0 1399 401 1800 895 1800 1390 1800 1790 1399 1790 905 1790 410 1390 10 895 10 {\\p0}", + -- Purple fill + "{\\c&H682167&\\p6}m 925 42 b 463 42 87 418 87 880 87 1343 463 1718 925 1718 1388 1718 1763 1343 1763 880 1763 418 1388 42 925 42{\\p0}", + -- Darker fill + "{\\c&H430142&\\p6}m 1605 828 b 1605 1175 1324 1456 977 1456 631 1456 349 1175 349 828 349 482 631 200 977 200 1324 200 1605 482 1605 828{\\p0}", + -- White fill + "{\\c&HDDDBDD&\\p6}m 1296 910 b 1296 1131 1117 1310 897 1310 676 1310 497 1131 497 910 497 689 676 511 897 511 1117 511 1296 689 1296 910{\\p0}", + -- Triangle + "{\\c&H691F69&\\p6}m 762 1113 l 762 708 b 881 776 1000 843 1119 911 1000 978 881 1046 762 1113{\\p0}", +} + +local santa_hat_lines = { + -- Pompoms + "{\\c&HC0C0C0&\\p6}m 500 -323 b 491 -322 481 -318 475 -311 465 -312 456 -319 446 -318 434 -314 427 -304 417 -297 410 -290 404 -282 395 -278 390 -274 387 -267 381 -265 377 -261 379 -254 384 -253 397 -244 409 -232 425 -228 437 -228 446 -218 457 -217 462 -216 466 -213 468 -209 471 -205 477 -203 482 -206 491 -211 499 -217 508 -222 532 -235 556 -249 576 -267 584 -272 584 -284 578 -290 569 -305 550 -312 533 -309 523 -310 515 -316 507 -321 505 -323 503 -323 500 -323{\\p0}", + "{\\c&HE0E0E0&\\p6}m 315 -260 b 286 -258 259 -240 246 -215 235 -210 222 -215 211 -211 204 -188 177 -176 172 -151 170 -139 163 -128 154 -121 143 -103 141 -81 143 -60 139 -46 125 -34 129 -17 132 -1 134 16 142 30 145 56 161 80 181 96 196 114 210 133 231 144 266 153 303 138 328 115 373 79 401 28 423 -24 446 -73 465 -123 483 -174 487 -199 467 -225 442 -227 421 -232 402 -242 384 -254 364 -259 342 -250 322 -260 320 -260 317 -261 315 -260{\\p0}", + -- Main cap + "{\\c&H0000F0&\\p6}m 1151 -523 b 1016 -516 891 -458 769 -406 693 -369 624 -319 561 -262 526 -252 465 -235 479 -187 502 -147 551 -135 588 -111 1115 165 1379 232 1909 761 1926 800 1952 834 1987 858 2020 883 2053 912 2065 952 2088 1000 2146 962 2139 919 2162 836 2156 747 2143 662 2131 615 2116 567 2122 517 2120 410 2090 306 2089 199 2092 147 2071 99 2034 64 1987 5 1928 -41 1869 -86 1777 -157 1712 -256 1629 -337 1578 -389 1521 -436 1461 -476 1407 -509 1343 -507 1284 -515 1240 -519 1195 -521 1151 -523{\\p0}", + -- Cap shadow + "{\\c&H0000AA&\\p6}m 1657 248 b 1658 254 1659 261 1660 267 1669 276 1680 284 1689 293 1695 302 1700 311 1707 320 1716 325 1726 330 1735 335 1744 347 1752 360 1761 371 1753 352 1754 331 1753 311 1751 237 1751 163 1751 90 1752 64 1752 37 1767 14 1778 -3 1785 -24 1786 -45 1786 -60 1786 -77 1774 -87 1760 -96 1750 -78 1751 -65 1748 -37 1750 -8 1750 20 1734 78 1715 134 1699 192 1694 211 1689 231 1676 246 1671 251 1661 255 1657 248 m 1909 541 b 1914 542 1922 549 1917 539 1919 520 1921 502 1919 483 1918 458 1917 433 1915 407 1930 373 1942 338 1947 301 1952 270 1954 238 1951 207 1946 214 1947 229 1945 239 1939 278 1936 318 1924 356 1923 362 1913 382 1912 364 1906 301 1904 237 1891 175 1887 150 1892 126 1892 101 1892 68 1893 35 1888 2 1884 -9 1871 -20 1859 -14 1851 -6 1854 9 1854 20 1855 58 1864 95 1873 132 1883 179 1894 225 1899 273 1908 362 1910 451 1909 541{\\p0}", + -- Brim and tip pompom + "{\\c&HF8F8F8&\\p6}m 626 -191 b 565 -155 486 -196 428 -151 387 -115 327 -101 304 -47 273 2 267 59 249 113 219 157 217 213 215 265 217 309 260 302 285 283 373 264 465 264 555 257 608 252 655 292 709 287 759 294 816 276 863 298 903 340 972 324 1012 367 1061 394 1125 382 1167 424 1213 462 1268 482 1322 506 1385 546 1427 610 1479 662 1510 690 1534 725 1566 752 1611 796 1664 830 1703 880 1740 918 1747 986 1805 1005 1863 991 1897 932 1916 880 1914 823 1945 777 1961 725 1979 673 1957 622 1938 575 1912 534 1862 515 1836 473 1790 417 1755 351 1697 305 1658 266 1633 216 1593 176 1574 138 1539 116 1497 110 1448 101 1402 77 1371 37 1346 -16 1295 15 1254 6 1211 -27 1170 -62 1121 -86 1072 -104 1027 -128 976 -133 914 -130 851 -137 794 -162 740 -181 679 -168 626 -191 m 2051 917 b 1971 932 1929 1017 1919 1091 1912 1149 1923 1214 1970 1254 2000 1279 2027 1314 2066 1325 2139 1338 2212 1295 2254 1238 2281 1203 2287 1158 2282 1116 2292 1061 2273 1006 2229 970 2206 941 2167 938 2138 918{\\p0}", +} + +-- called by mpv on every frame +function tick() + if state.marginsREQ == true then + update_margins() + state.marginsREQ = false + end + + if (not state.enabled) then return end + + if (state.idle) then + + -- render idle message + msg.trace("idle message") + local icon_x, icon_y = 320 - 26, 140 + local line_prefix = ("{\\rDefault\\an7\\1a&H00&\\bord0\\shad0\\pos(%f,%f)}"):format(icon_x, icon_y) + + local ass = assdraw.ass_new() + -- mpv logo + if user_opts.idlescreen then + for i, line in ipairs(logo_lines) do + ass:new_event() + ass:append(line_prefix .. line) + end + end + + -- Santa hat + if is_december and user_opts.idlescreen and not user_opts.greenandgrumpy then + for i, line in ipairs(santa_hat_lines) do + ass:new_event() + ass:append(line_prefix .. line) + end + end + + if user_opts.idlescreen then + ass:new_event() + ass:pos(320, icon_y+65) + ass:an(8) + ass:append("Drop files or URLs to play here.") + end + set_osd(640, 360, ass.text) + + if state.showhide_enabled then + mp.disable_key_bindings("showhide") + mp.disable_key_bindings("showhide_wc") + state.showhide_enabled = false + end + + + elseif (state.fullscreen and user_opts.showfullscreen) + or (not state.fullscreen and user_opts.showwindowed) then + + -- render the OSC + render() + else + -- Flush OSD + render_wipe() + end + + state.tick_last_time = mp.get_time() + + if state.anitype ~= nil then + -- state.anistart can be nil - animation should now start, or it can + -- be a timestamp when it started. state.idle has no animation. + if not state.idle and + (not state.anistart or + mp.get_time() < 1 + state.anistart + user_opts.fadeduration/1000) + then + -- animating or starting, or still within 1s past the deadline + request_tick() + else + kill_animation() + end + end +end + +function do_enable_keybindings() + if state.enabled then + if not state.showhide_enabled then + mp.enable_key_bindings("showhide", "allow-vo-dragging+allow-hide-cursor") + mp.enable_key_bindings("showhide_wc", "allow-vo-dragging+allow-hide-cursor") + end + state.showhide_enabled = true + end +end + +function enable_osc(enable) + state.enabled = enable + if enable then + do_enable_keybindings() + else + hide_osc() -- acts immediately when state.enabled == false + if state.showhide_enabled then + mp.disable_key_bindings("showhide") + mp.disable_key_bindings("showhide_wc") + end + state.showhide_enabled = false + end +end + +-- duration is observed for the sole purpose of updating chapter markers +-- positions. live streams with chapters are very rare, and the update is also +-- expensive (with request_init), so it's only observed when we have chapters +-- and the user didn't disable the livemarkers option (update_duration_watch). +function on_duration() request_init() end + +local duration_watched = false +function update_duration_watch() + local want_watch = user_opts.livemarkers and + (mp.get_property_number("chapters", 0) or 0) > 0 and + true or false -- ensure it's a boolean + + if (want_watch ~= duration_watched) then + if want_watch then + mp.observe_property("duration", nil, on_duration) + else + mp.unobserve_property(on_duration) + end + duration_watched = want_watch + end +end + +validate_user_opts() +update_duration_watch() + +mp.register_event("shutdown", shutdown) +mp.register_event("start-file", request_init) +mp.observe_property("track-list", nil, request_init) +mp.observe_property("playlist", nil, request_init) +mp.observe_property("chapter-list", "native", function(_, list) + list = list or {} -- safety, shouldn't return nil + table.sort(list, function(a, b) return a.time < b.time end) + state.chapter_list = list + update_duration_watch() + request_init() +end) + +mp.register_script_message("osc-message", show_message) +mp.register_script_message("osc-chapterlist", function(dur) + show_message(get_chapterlist(), dur) +end) +mp.register_script_message("osc-playlist", function(dur) + show_message(get_playlist(), dur) +end) +mp.register_script_message("osc-tracklist", function(dur) + local msg = {} + for k,v in pairs(nicetypes) do + table.insert(msg, get_tracklist(k)) + end + show_message(table.concat(msg, '\n\n'), dur) +end) + +mp.observe_property("fullscreen", "bool", + function(name, val) + state.fullscreen = val + state.marginsREQ = true + request_init_resize() + end +) +mp.observe_property("border", "bool", + function(name, val) + state.border = val + request_init_resize() + end +) +mp.observe_property("window-maximized", "bool", + function(name, val) + state.maximized = val + request_init_resize() + end +) +mp.observe_property("idle-active", "bool", + function(name, val) + state.idle = val + request_tick() + end +) +mp.observe_property("pause", "bool", pause_state) +mp.observe_property("demuxer-cache-state", "native", cache_state) +mp.observe_property("vo-configured", "bool", function(name, val) + request_tick() +end) +mp.observe_property("playback-time", "number", function(name, val) + request_tick() +end) +mp.observe_property("osd-dimensions", "native", function(name, val) + -- (we could use the value instead of re-querying it all the time, but then + -- we might have to worry about property update ordering) + request_init_resize() +end) + +-- mouse show/hide bindings +mp.set_key_bindings({ + {"mouse_move", function(e) process_event("mouse_move", nil) end}, + {"mouse_leave", mouse_leave}, +}, "showhide", "force") +mp.set_key_bindings({ + {"mouse_move", function(e) process_event("mouse_move", nil) end}, + {"mouse_leave", mouse_leave}, +}, "showhide_wc", "force") +do_enable_keybindings() + +--mouse input bindings +mp.set_key_bindings({ + {"mbtn_left", function(e) process_event("mbtn_left", "up") end, + function(e) process_event("mbtn_left", "down") end}, + {"shift+mbtn_left", function(e) process_event("shift+mbtn_left", "up") end, + function(e) process_event("shift+mbtn_left", "down") end}, + {"mbtn_right", function(e) process_event("mbtn_right", "up") end, + function(e) process_event("mbtn_right", "down") end}, + -- alias to shift_mbtn_left for single-handed mouse use + {"mbtn_mid", function(e) process_event("shift+mbtn_left", "up") end, + function(e) process_event("shift+mbtn_left", "down") end}, + {"wheel_up", function(e) process_event("wheel_up", "press") end}, + {"wheel_down", function(e) process_event("wheel_down", "press") end}, + {"mbtn_left_dbl", "ignore"}, + {"shift+mbtn_left_dbl", "ignore"}, + {"mbtn_right_dbl", "ignore"}, +}, "input", "force") +mp.enable_key_bindings("input") + +mp.set_key_bindings({ + {"mbtn_left", function(e) process_event("mbtn_left", "up") end, + function(e) process_event("mbtn_left", "down") end}, +}, "window-controls", "force") +mp.enable_key_bindings("window-controls") + +function get_hidetimeout() + if user_opts.visibility == "always" then + return -1 -- disable autohide + end + return user_opts.hidetimeout +end + +function always_on(val) + if state.enabled then + if val then + show_osc() + else + hide_osc() + end + end +end + +-- mode can be auto/always/never/cycle +-- the modes only affect internal variables and not stored on its own. +function visibility_mode(mode, no_osd) + if mode == "cycle" then + if not state.enabled then + mode = "auto" + elseif user_opts.visibility ~= "always" then + mode = "always" + else + mode = "never" + end + end + + if mode == "auto" then + always_on(false) + enable_osc(true) + elseif mode == "always" then + enable_osc(true) + always_on(true) + elseif mode == "never" then + enable_osc(false) + else + msg.warn("Ignoring unknown visibility mode '" .. mode .. "'") + return + end + + user_opts.visibility = mode + utils.shared_script_property_set("osc-visibility", mode) + + if not no_osd and tonumber(mp.get_property("osd-level")) >= 1 then + mp.osd_message("OSC visibility: " .. mode) + end + + -- Reset the input state on a mode change. The input state will be + -- recalculated on the next render cycle, except in 'never' mode where it + -- will just stay disabled. + mp.disable_key_bindings("input") + mp.disable_key_bindings("window-controls") + state.input_enabled = false + + update_margins() + request_tick() +end + +function idlescreen_visibility(mode, no_osd) + if mode == "cycle" then + if user_opts.idlescreen then + mode = "no" + else + mode = "yes" + end + end + + if mode == "yes" then + user_opts.idlescreen = true + else + user_opts.idlescreen = false + end + + utils.shared_script_property_set("osc-idlescreen", mode) + + if not no_osd and tonumber(mp.get_property("osd-level")) >= 1 then + mp.osd_message("OSC logo visibility: " .. tostring(mode)) + end + + request_tick() +end + +visibility_mode(user_opts.visibility, true) +mp.register_script_message("osc-visibility", visibility_mode) +mp.add_key_binding(nil, "visibility", function() visibility_mode("cycle") end) + +mp.register_script_message("osc-idlescreen", idlescreen_visibility) + +set_virt_mouse_area(0, 0, 0, 0, "input") +set_virt_mouse_area(0, 0, 0, 0, "window-controls") diff --git a/mpv/scripts/quality-menu.lua b/mpv/scripts/quality-menu.lua new file mode 100644 index 0000000..c5da0d3 --- /dev/null +++ b/mpv/scripts/quality-menu.lua @@ -0,0 +1,806 @@ +-- quality-menu.lua +-- +-- Change the stream video and audio quality on the fly. +-- +-- Usage: +-- add bindings to input.conf: +-- Ctrl+f script-message-to quality_menu video_formats_toggle +-- Alt+f script-message-to quality_menu audio_formats_toggle +-- +-- Displays a menu that lets you switch to different ytdl-format settings while +-- you're in the middle of a video (just like you were using the web player). + +local mp = require 'mp' +local utils = require 'mp.utils' +local msg = require 'mp.msg' +local assdraw = require 'mp.assdraw' +local opt = require('mp.options') + +local opts = { + --key bindings + up_binding = "UP WHEEL_UP", + down_binding = "DOWN WHEEL_DOWN", + select_binding = "ENTER MBTN_LEFT", + close_menu_binding = "ESC MBTN_RIGHT Ctrl+f Alt+f", + + --youtube-dl version(could be youtube-dl or yt-dlp, or something else) + ytdl_ver = "yt-dlp", + + --formatting / cursors + selected_and_active = "▶ - ", + selected_and_inactive = "● - ", + unselected_and_active = "▷ - ", + unselected_and_inactive = "○ - ", + + --font size scales by window, if false requires larger font and padding sizes + scale_playlist_by_window=true, + + --playlist ass style overrides inside curly brackets, \keyvalue is one field, extra \ for escape in lua + --example {\\fnUbuntu\\fs10\\b0\\bord1} equals: font=Ubuntu, size=10, bold=no, border=1 + --read http://docs.aegisub.org/3.2/ASS_Tags/ for reference of tags + --undeclared tags will use default osd settings + --these styles will be used for the whole playlist. More specific styling will need to be hacked in + -- + --(a monospaced font is recommended but not required) + style_ass_tags = "{\\fnmonospace\\fs10\\bord1}", + + --paddings for top left corner + text_padding_x = 5, + text_padding_y = 5, + + --how many seconds until the quality menu times out + --setting this to 0 deactivates the timeout + menu_timeout = 6, + + --use youtube-dl to fetch a list of available formats (overrides quality_strings) + fetch_formats = true, + + --default menu entries + quality_strings=[[ + [ + {"4320p" : "bestvideo[height<=?4320p]+bestaudio/best"}, + {"2160p" : "bestvideo[height<=?2160]+bestaudio/best"}, + {"1440p" : "bestvideo[height<=?1440]+bestaudio/best"}, + {"1080p" : "bestvideo[height<=?1080]+bestaudio/best"}, + {"720p" : "bestvideo[height<=?720]+bestaudio/best"}, + {"480p" : "bestvideo[height<=?480]+bestaudio/best"}, + {"360p" : "bestvideo[height<=?360]+bestaudio/best"}, + {"240p" : "bestvideo[height<=?240]+bestaudio/best"}, + {"144p" : "bestvideo[height<=?144]+bestaudio/best"} + ] + ]], + + --reset ytdl-format to the original format string when changing files (e.g. going to the next playlist entry) + --if file was opened previously, reset to previously selected format + reset_format = true, + + --automatically fetch available formats when opening an url + fetch_on_start = true, + + --show the video format menu after opening an url + start_with_menu = false, + + --include unknown formats in the list + --Unfortunately choosing which formats are video or audio is not always perfect. + --Set to true to make sure you don't miss any formats, but then the list + --might also include formats that aren't actually video or audio. + --Formats that are known to not be video or audio are still filtered out. + include_unknown = false, + + --hide columns that are identical for all formats + hide_identical_columns = true, + + --which columns are shown in which order + --comma separated list, prefix column with "-" to align left + -- + --columns that might be useful are: + --resolution, width, height, fps, dynamic_range, tbr, vbr, abr, asr, + --filesize, filesize_approx, vcodec, acodec, ext, video_ext, audio_ext, + --language, format, format_note, quality + -- + --columns that are derived from the above, but with special treatment: + --frame_rate, bitrate_total, bitrate_video, bitrate_audio, + --codec_video, codec_audio, audio_sample_rate + -- + --If those still aren't enough or you're just curious, run: + --yt-dlp -j + --This outputs unformatted JSON. + --Format it and look under "formats" to see what's available. + -- + --Not all videos have all columns available. + --Be careful, misspelled columns simply won't be displayed, there is no error. + columns_video = '-resolution,frame_rate,dynamic_range,language,bitrate_total,size,-codec_video,-codec_audio', + columns_audio = 'audio_sample_rate,bitrate_total,size,language,-codec_audio', + + --columns used for sorting, see "columns_video" for available columns + --comma separated list, prefix column with "-" to reverse sorting order + --Leaving this empty keeps the order from yt-dlp/youtube-dl. + --Be careful, misspelled columns won't result in an error, + --but they might influence the result. + sort_video = 'height,fps,tbr,size,format_id', + sort_audio = 'asr,tbr,size,format_id', +} +opt.read_options(opts, "quality-menu") +opts.quality_strings = utils.parse_json(opts.quality_strings) + +-- special thanks to reload.lua (https://github.com/4e6/mpv-reload/) +local function reload_resume() + local playlist_pos = mp.get_property_number("playlist-pos") + local reload_duration = mp.get_property_native("duration") + local time_pos = mp.get_property("time-pos") + + mp.set_property_number("playlist-pos", playlist_pos) + + -- Tries to determine live stream vs. pre-recorded VOD. VOD has non-zero + -- duration property. When reloading VOD, to keep the current time position + -- we should provide offset from the start. Stream doesn't have fixed start. + -- Decent choice would be to reload stream from it's current 'live' position. + -- That's the reason we don't pass the offset when reloading streams. + if reload_duration and reload_duration > 0 then + local function seeker() + mp.commandv("seek", time_pos, "absolute") + mp.unregister_event(seeker) + end + mp.register_event("file-loaded", seeker) + end +end + +local ytdl = { + path = opts.ytdl_ver, + searched = false, + blacklisted = {} +} + +local function process_json(json) + local function is_video(format) + -- "none" means it is not a video + -- nil means it is unknown + return (opts.include_unknown or format.vcodec) and format.vcodec ~= "none" + end + + local function is_audio(format) + return (opts.include_unknown or format.acodec) and format.acodec ~= "none" + end + + local vfmt = nil + local afmt = nil + local requested_formats = json["requested_formats"] or json["requested_downloads"] + for _, format in ipairs(requested_formats) do + if is_video(format) then + vfmt = format["format_id"] + elseif is_audio(format) then + afmt = format["format_id"] + end + end + + local video_formats = {} + local audio_formats = {} + local all_formats = {} + for i = #json.formats, 1, -1 do + local format = json.formats[i] + if is_video(format) then + video_formats[#video_formats+1] = format + all_formats[#all_formats+1] = format + elseif is_audio(format) then + audio_formats[#audio_formats+1] = format + all_formats[#all_formats+1] = format + end + end + + local function populate_special_fields(format) + format.size = format.filesize or format.filesize_approx + format.frame_rate = format.fps + format.bitrate_total = format.tbr + format.bitrate_video = format.vbr + format.bitrate_audio = format.abr + format.codec_video = format.vcodec + format.codec_audio = format.acodec + format.audio_sample_rate = format.asr + end + + for _,format in ipairs(all_formats) do + populate_special_fields(format) + end + + local function strip_minus(list) + local stripped_list = {} + local had_minus = {} + for i, val in ipairs(list) do + if string.sub(val, 1, 1) == "-" then + val = string.sub(val, 2) + had_minus[val] = true + end + stripped_list[i] = val + end + return stripped_list, had_minus + end + + local function string_split (inputstr, sep) + if sep == nil then + sep = "%s" + end + local t={} + for str in string.gmatch(inputstr, "([^"..sep.."]+)") do + table.insert(t, str) + end + return t + end + + local sort_video, reverse_video = strip_minus(string_split(opts.sort_video, ',')) + local sort_audio, reverse_audio = strip_minus(string_split(opts.sort_audio, ',')) + + local function comp(properties, reverse) + return function (a, b) + for _,prop in ipairs(properties) do + local a_val = a[prop] + local b_val = b[prop] + if a_val and b_val and type(a_val) ~= 'table' and a_val ~= b_val then + if reverse[prop] then + return a_val < b_val + else + return a_val > b_val + end + end + end + return false + end + end + + if #sort_video > 0 then + table.sort(video_formats, comp(sort_video, reverse_video)) + end + if #sort_audio > 0 then + table.sort(audio_formats, comp(sort_audio, reverse_audio)) + end + + local function scale_filesize(size) + if size == nil then + return "" + end + size = tonumber(size) + + local counter = 0 + while size > 1024 do + size = size / 1024 + counter = counter+1 + end + + if counter >= 3 then return string.format("%.1fGiB", size) + elseif counter >= 2 then return string.format("%.1fMiB", size) + elseif counter >= 1 then return string.format("%.1fKiB", size) + else return string.format("%.1fB ", size) + end + end + + local function scale_bitrate(br) + if br == nil then + return "" + end + br = tonumber(br) + + local counter = 0 + while br > 1000 do + br = br / 1000 + counter = counter+1 + end + + if counter >= 2 then return string.format("%.1fGbps", br) + elseif counter >= 1 then return string.format("%.1fMbps", br) + else return string.format("%.1fKbps", br) + end + end + + local function format_special_fields(format) + local size_prefix = not format.filesize and format.filesize_approx and "~" or "" + format.size = (size_prefix) .. scale_filesize(format.size) + format.frame_rate = format.fps and format.fps.."fps" or "" + format.bitrate_total = scale_bitrate(format.tbr) + format.bitrate_video = scale_bitrate(format.vbr) + format.bitrate_audio = scale_bitrate(format.abr) + format.codec_video = format.vcodec == nil and "unknown" or format.vcodec == "none" and "" or format.vcodec + format.codec_audio = format.acodec == nil and "unknown" or format.acodec == "none" and "" or format.acodec + format.audio_sample_rate = format.asr and tostring(format.asr) .. "Hz" or "" + end + + for _,format in ipairs(all_formats) do + format_special_fields(format) + end + + local function format_table(formats, columns) + local function calc_shown_columns() + local display_col = {} + local column_widths = {} + local column_values = {} + local columns, column_align_left = strip_minus(columns) + + for _,format in pairs(formats) do + for col, prop in ipairs(columns) do + local label = tostring(format[prop] or "") + format[prop] = label + + if not column_widths[col] or column_widths[col] < label:len() then + column_widths[col] = label:len() + end + + column_values[col] = column_values[col] or label + display_col[col] = display_col[col] or (column_values[col] ~= label) + end + end + + local show_columns={} + for i, width in ipairs(column_widths) do + if width > 0 and not opts.hide_identical_columns or display_col[i] then + local prop = columns[i] + show_columns[#show_columns+1] = { + prop=prop, + width=width, + align_left=column_align_left[prop] + } + end + end + return show_columns + end + + local show_columns = calc_shown_columns() + + local spacing = 2 + local res = {} + for _,f in ipairs(formats) do + local row = '' + for i,column in ipairs(show_columns) do + -- lua errors out with width > 99 ("invalid conversion specification") + local width = math.min(column.width * (column.align_left and -1 or 1), 99) + row = row .. (i > 1 and string.format('%' .. spacing .. 's', '') or '') + .. string.format('%' .. width .. 's', f[column.prop] or "") + end + res[#res+1] = {label=row, format=f.format_id} + end + return res + end + + local columns_video = string_split(opts.columns_video, ',') + local columns_audio = string_split(opts.columns_audio, ',') + local vres = format_table(video_formats, columns_video) + local ares = format_table(audio_formats, columns_audio) + return vres, ares , vfmt, afmt +end + +local function get_url() + local path = mp.get_property("path") + path = string.gsub(path, "ytdl://", "") -- Strip possible ytdl:// prefix. + + local function is_url(s) + -- adapted the regex from https://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url + return nil ~= string.match(path, "^[%w]-://[-a-zA-Z0-9@:%._\\+~#=]+%.[a-zA-Z0-9()][a-zA-Z0-9()]?[a-zA-Z0-9()]?[a-zA-Z0-9()]?[a-zA-Z0-9()]?[a-zA-Z0-9()]?[-a-zA-Z0-9()@:%_\\+.~#?&/=]*") + end + + return is_url(path) and path or nil +end + +local uosc = false +local url_data={} +local function process_json_string(url, json) + local json, err = utils.parse_json(json) + + if (json == nil) then + mp.osd_message("fetching formats failed...", 2) + msg.error("failed to parse JSON data: " .. err) + return + end + + if json.formats == nil then + return + end + + local vres, ares , vfmt, afmt = process_json(json) + url_data[url] = {voptions=vres, aoptions=ares, vfmt=vfmt, afmt=afmt} + if uosc and get_url() == url then + mp.commandv('script-message-to', 'uosc', 'set', 'vformats', #vres) + mp.commandv('script-message-to', 'uosc', 'set', 'aformats', #ares) + end + return vres, ares , vfmt, afmt +end + +local function download_formats(url) + + mp.osd_message("fetching available formats with youtube-dl...", 60) + + if not (ytdl.searched) then + local ytdl_mcd = mp.find_config_file(opts.ytdl_ver) + if not (ytdl_mcd == nil) then + msg.verbose("found youtube-dl at: " .. ytdl_mcd) + ytdl.path = ytdl_mcd + end + ytdl.searched = true + end + + local function exec(args) + local res, err = mp.command_native({name = "subprocess", args = args, capture_stdout = true, capture_stderr = true}) + return res.status, res.stdout, res.stderr + end + + local ytdl_format = mp.get_property("ytdl-format") + local command = nil + if (ytdl_format == nil or ytdl_format == "") then + command = {ytdl.path, "--no-warnings", "--no-playlist", "-J", url} + else + command = {ytdl.path, "--no-warnings", "--no-playlist", "-J", "-f", ytdl_format, url} + end + + msg.verbose("calling youtube-dl with command: " .. table.concat(command, " ")) + + local es, stdout, stderr = exec(command) + + if (es < 0) or (stdout == nil) or (stdout == "") then + mp.osd_message("fetching formats failed...", 2) + msg.error("failed to get format list: " .. es) + msg.error("stderr: " .. stderr) + return + end + + msg.verbose("youtube-dl succeeded!") + mp.osd_message("", 0) + + local vres, ares , vfmt, afmt = process_json_string(url, stdout) + return vres, ares , vfmt, afmt +end + +local function send_formats_to(type, url, script_name, options, format_id) + mp.commandv('script-message-to', script_name, type .. '_formats', url, utils.format_json(options or {}), format_id or '') +end + +local queue_callback_video = {} +local queue_callback_audio = {} +local function get_formats() + + local url = get_url() + if url == nil then + return + end + + if url_data[url] then + local data = url_data[url] + return data.voptions, data.aoptions, data.vfmt, data.afmt, url + end + + if opts.fetch_formats == false then + local vres = {} + for i,v in ipairs(opts.quality_strings) do + for k,v2 in pairs(v) do + vres[i] = {label = k, format=v2} + end + end + url_data[url] = {voptions=vres, aoptions={}, vfmt=nil, afmt=nil} + return vres, {}, nil, nil, url + end + + local vres, ares , vfmt, afmt = download_formats(url) + + for _, script_name in ipairs(queue_callback_video[url] or {}) do + send_formats_to('video', url, script_name, vres, vfmt) + end + for _, script_name in ipairs(queue_callback_audio[url] or {}) do + send_formats_to('audio', url, script_name, ares, afmt) + end + + queue_callback_video[url] = nil + queue_callback_audio[url] = nil + return vres, ares , vfmt, afmt, url +end + +local function format_string(vfmt, afmt) + if vfmt and afmt then + return vfmt.."+"..afmt + elseif vfmt then + return vfmt + elseif afmt then + return afmt + else + return "" + end +end + +local function set_format(url, vfmt, afmt) + if (url_data[url].vfmt ~= vfmt or url_data[url].afmt ~= afmt) then + url_data[url].afmt = afmt + url_data[url].vfmt = vfmt + if url == mp.get_property("path") then + mp.set_property("ytdl-format", format_string(vfmt, afmt)) + reload_resume() + end + end +end + +local destroyer = nil +local function show_menu(isvideo) + + if destroyer then + destroyer() + end + + local voptions, aoptions, vfmt, afmt, url = get_formats() + + local options + local fmt + if isvideo then + options = voptions + fmt = vfmt + else + options = aoptions + fmt = afmt + end + + if options == nil then + if uosc then + if isvideo then + mp.commandv('script-binding', 'uosc/video') + else + mp.commandv('script-binding', 'uosc/audio') + end + end + + return + end + + msg.verbose("current ytdl-format: "..format_string(vfmt, afmt)) + + local active = 0 + local selected = 1 + --set the cursor to the current format + if fmt then + for i,v in ipairs(options) do + if v.format == fmt then + active = i + selected = active + break + end + end + else + active = #options + 1 + selected = active + end + + if uosc then + local menu = { + title = isvideo and 'Video Formats' or 'Audio Formats', + items = {}, + type = (isvideo and 'video' or 'audio') .. '_formats', + } + for i, option in ipairs(options) do + menu.items[i] = { + title = option.label, + active = i == active, + value = { + 'script-message-to', + 'quality_menu', + (isvideo and 'video' or 'audio') .. '-format-set', + url, + option.format} + } + end + menu.items[#menu.items + 1] = { + title = 'None', + value = { + 'script-message-to', + 'quality_menu', + (isvideo and 'video' or 'audio') .. '-format-set', + url} + } + local json = utils.format_json(menu) + mp.commandv('script-message-to', 'uosc', 'open-menu', json) + return + end + + local function choose_prefix(i) + if i == selected and i == active then return opts.selected_and_active + elseif i == selected then return opts.selected_and_inactive end + + if i ~= selected and i == active then return opts.unselected_and_active + elseif i ~= selected then return opts.unselected_and_inactive end + return "> " --shouldn't get here. + end + + local function draw_menu() + local ass = assdraw.ass_new() + + ass:pos(opts.text_padding_x, opts.text_padding_y) + ass:append(opts.style_ass_tags) + + if #options > 0 then + for i,v in ipairs(options) do + ass:append(choose_prefix(i)..v.label.."\\N") + end + ass:append(choose_prefix(#options+1).."None") + else + ass:append("no formats found") + end + + local w, h = mp.get_osd_size() + if opts.scale_playlist_by_window then w,h = 0, 0 end + mp.set_osd_ass(w, h, ass.text) + end + + local num_options = #options + 1 + local timeout = nil + + local function selected_move(amt) + selected = selected + amt + if selected < 1 then selected = num_options + elseif selected > num_options then selected = 1 end + if timeout then + timeout:kill() + timeout:resume() + end + draw_menu() + end + + local function bind_keys(keys, name, func, opts) + if not keys then + mp.add_forced_key_binding(keys, name, func, opts) + return + end + local i = 1 + for key in keys:gmatch("[^%s]+") do + local prefix = i == 1 and '' or i + mp.add_forced_key_binding(key, name..prefix, func, opts) + i = i + 1 + end + end + + local function unbind_keys(keys, name) + if not keys then + mp.remove_key_binding(name) + return + end + local i = 1 + for key in keys:gmatch("[^%s]+") do + local prefix = i == 1 and '' or i + mp.remove_key_binding(name..prefix) + i = i + 1 + end + end + + local function destroy() + if timeout then + timeout:kill() + end + mp.set_osd_ass(0,0,"") + unbind_keys(opts.up_binding, "move_up") + unbind_keys(opts.down_binding, "move_down") + unbind_keys(opts.select_binding, "select") + unbind_keys(opts.close_menu_binding, "close") + destroyer = nil + end + + if opts.menu_timeout > 0 then + timeout = mp.add_periodic_timer(opts.menu_timeout, destroy) + end + destroyer = destroy + + bind_keys(opts.up_binding, "move_up", function() selected_move(-1) end, {repeatable=true}) + bind_keys(opts.down_binding, "move_down", function() selected_move(1) end, {repeatable=true}) + if #options > 0 then + bind_keys(opts.select_binding, "select", function() + destroy() + if selected == active then return end + + fmt = options[selected] and options[selected].format or nil + if isvideo then + vfmt = fmt + else + afmt = fmt + end + set_format(url, vfmt, afmt) + end) + end + bind_keys(opts.close_menu_binding, "close", destroy) --close menu using ESC + mp.osd_message("", 0) + draw_menu() +end + +local ui_callback = {} + +local function video_formats_toggle() + if #ui_callback > 0 then + for _, name in ipairs(ui_callback) do + mp.commandv('script-message-to', name, 'video-formats-menu') + end + else + show_menu(true) + end +end + +local function audio_formats_toggle() + if #ui_callback > 0 then + for _, name in ipairs(ui_callback) do + mp.commandv('script-message-to', name, 'audio-formats-menu') + end + else + show_menu(false) + end +end + +-- keybind to launch menu +mp.add_key_binding(nil, "video_formats_toggle", video_formats_toggle) +mp.add_key_binding(nil, "audio_formats_toggle", audio_formats_toggle) +mp.add_key_binding(nil, "reload", reload_resume) + +local original_format = mp.get_property("ytdl-format") +local path = nil +local function file_start() + local new_path = get_url() + if not new_path then return end + + local data = url_data[new_path] + + if uosc then + if data then + mp.commandv('script-message-to', 'uosc', 'set', 'vformats', #data.voptions) + mp.commandv('script-message-to', 'uosc', 'set', 'aformats', #data.aoptions) + else + mp.commandv('script-message-to', 'uosc', 'set', 'vformats', 0) + mp.commandv('script-message-to', 'uosc', 'set', 'aformats', 0) + end + end + + if opts.reset_format and path and new_path ~= path then + if data then + msg.verbose("setting previously set format") + mp.set_property("ytdl-format", format_string(data.vfmt, data.afmt)) + else + msg.verbose("setting original format") + mp.set_property("ytdl-format", original_format) + end + end + if opts.start_with_menu and new_path ~= path then + video_formats_toggle() + elseif opts.fetch_on_start and not data then + download_formats(new_path) + end + path = new_path +end +mp.register_event("start-file", file_start) + +mp.register_script_message('video-formats-get', function(url, script_name) + local data = url_data[url] + if data then + send_formats_to('video', url, script_name, data.voptions, data.vfmt) + else + local queue = queue_callback_video[url] or {} + queue[#queue + 1] = script_name + queue_callback_video[url] = queue + get_formats() + end +end) + +mp.register_script_message('audio-formats-get', function(url, script_name) + local data = url_data[url] + if data then + send_formats_to('audio', url, script_name, data.aoptions, data.afmt) + else + local queue = queue_callback_audio[url] or {} + queue[#queue + 1] = script_name + queue_callback_audio[url] = queue + get_formats() + end +end) + +mp.register_script_message('video-format-set', function(url, format_id) + set_format(url, format_id, url_data[url].afmt) +end) + +mp.register_script_message('audio-format-set', function(url, format_id) + set_format(url, url_data[url].vfmt, format_id) +end) + +mp.register_script_message('register-ui', function(script_name) + ui_callback[#ui_callback + 1] = script_name +end) + +-- check if uosc is running +mp.register_script_message('uosc-version', function(version) + version = tonumber((version:gsub('%.', ''))) +---@diagnostic disable-next-line: cast-local-type + uosc = version and version >= 400 +end) +mp.commandv('script-message-to', 'uosc', 'get-version', mp.get_script_name()) \ No newline at end of file diff --git a/mpv/scripts/youtube-download.lua b/mpv/scripts/youtube-download.lua new file mode 100644 index 0000000..3050b39 --- /dev/null +++ b/mpv/scripts/youtube-download.lua @@ -0,0 +1,758 @@ +-- youtube-download.lua +-- +-- Download video/audio from youtube via youtube-dl and ffmpeg/avconv +-- This is forked/based on https://github.com/jgreco/mpv-youtube-quality +-- +-- Video download bound to ctrl-d by default. +-- Audio download bound to ctrl-a by default. + +-- Requires youtube-dl in PATH for video download +-- Requires ffmpeg or avconv in PATH for audio download + +local mp = require 'mp' +local utils = require 'mp.utils' +local msg = require 'mp.msg' + +local opts = { + -- Key bindings + -- Set to empty string "" to disable + download_video_binding = "ctrl+d", + download_audio_binding = "ctrl+a", + download_subtitle_binding = "ctrl+s", + download_video_embed_subtitle_binding = "ctrl+i", + select_range_binding = "ctrl+r", + + -- Specify audio format: "best", "aac","flac", "mp3", "m4a", "opus", "vorbis", or "wav" + audio_format = "mp3", + + -- Specify ffmpeg/avconv audio quality + -- insert a value between 0 (better) and 9 (worse) for VBR or a specific bitrate like 128K + audio_quality = "0", + + -- Same as youtube-dl --format FORMAT + -- see https://github.com/ytdl-org/youtube-dl/blob/master/README.md#format-selection + -- set to "current" to download the same quality that is currently playing + video_format = "", + + -- Encode the video to another format if necessary: "mp4", "flv", "ogg", "webm", "mkv", "avi" + recode_video = "", + + -- Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames + restrict_filenames = true, + + -- Download the whole playlist (false) or only one video (true) + -- Same as youtube-dl --no-playlist + no_playlist = true, + + -- Use an archive file, see youtube-dl --download-archive + -- You have these options: + -- * Set to empty string "" to not use an archive file + -- * Set an absolute path to use one archive for all downloads e.g. download_archive="/home/user/archive.txt" + -- * Set a relative path/only a filename to use one archive per directory e.g. download_archive="archive.txt" + -- * Use $PLAYLIST to create one archive per playlist e.g. download_archive="/home/user/archives/$PLAYLIST.txt" + download_archive = "", + + -- Use a cookies file for youtube-dl + -- Same as youtube-dl --cookies + -- On Windows you need to use a double blackslash or a single fordwardslash + -- For example "C:\\Users\\Username\\cookies.txt" + -- Or "C:/Users/Username/cookies.txt" + cookies = "", + + -- Filename or full path + -- Same as youtube-dl -o FILETEMPLATE + -- see https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template + -- A relative path or a file name is relative to the path mpv was launched from + -- On Windows you need to use a double blackslash or a single fordwardslash + -- For example "C:\\Users\\Username\\Downloads\\%(title)s.%(ext)s" + -- Or "C:/Users/Username/Downloads/%(title)s.%(ext)s" + filename = "%(title)s.%(ext)s", + + -- Subtitle language + -- Same as youtube-dl --sub-lang en + sub_lang = "en", + + -- Subtitle format + -- Same as youtube-dl --sub-format best + sub_format = "best", + + -- Log file for download errors + log_file = "", + +} + +--Read configuration file +(require 'mp.options').read_options(opts, "youtube-download") + +--Read command line arguments +local ytdl_raw_options = mp.get_property("ytdl-raw-options") +if ytdl_raw_options ~= nil and ytdl_raw_options:find("cookies=") ~= nil then + local cookie_file = ytdl_raw_options:match("cookies=([^,]+)") + if cookie_file ~= nil then + opts.cookies = cookie_file + end +end + +local function exec(args, capture_stdout, capture_stderr) + local ret = mp.command_native({ + name = "subprocess", + playback_only = false, + capture_stdout = capture_stdout, + capture_stderr = capture_stderr, + args = args, + }) + return ret.status, ret.stdout, ret.stderr, ret +end + +local function trim(str) + return str:gsub("^%s+", ""):gsub("%s+$", "") +end + +local function not_empty(str) + if str == nil or str == "" then + return false + end + return trim(str) ~= "" +end + +local function path_separator() + return package.config:sub(1,1) +end + +local function path_join(...) + return table.concat({...}, path_separator()) +end + +local function get_current_format() + -- get the current youtube-dl format or the default value + local ytdl_format = mp.get_property("options/ytdl-format") + if not_empty(ytdl_format) then + return ytdl_format + end + ytdl_format = mp.get_property("ytdl-format") + if not_empty(ytdl_format) then + return ytdl_format + end + return "bestvideo+bestaudio/best" +end + +local DOWNLOAD = { + VIDEO=1, + AUDIO=2, + SUBTITLE=3, + VIDEO_EMBED_SUBTITLE=4 +} +local select_range_mode = 0 +local start_time_seconds = nil +local start_time_formated = nil +local end_time_seconds = nil +local end_time_formated = nil + +local is_downloading = false + +local function disable_select_range() + -- Disable range mode + select_range_mode = 0 + -- Remove the arrow key key bindings + mp.remove_key_binding("select-range-set-up") + mp.remove_key_binding("select-range-set-down") + mp.remove_key_binding("select-range-set-left") + mp.remove_key_binding("select-range-set-right") +end + + +local function download(download_type) + local start_time = os.date("%c") + if is_downloading then + return + end + is_downloading = true + + local ass0 = mp.get_property("osd-ass-cc/0") + local ass1 = mp.get_property("osd-ass-cc/1") + local url = mp.get_property("path") + + url = string.gsub(url, "ytdl://", "") -- Strip possible ytdl:// prefix. + + if string.find(url, "//youtu.be/") == nil + and string.find(url, "//ww.youtu.be/") == nil + and string.find(url, "//youtube.com/") == nil + and string.find(url, "//www.youtube.com/") == nil + then + mp.osd_message("Not a youtube URL: " .. tostring(url), 10) + is_downloading = false + return + end + + local list_match = url:match("list=(%w+)") + local download_archive = opts.download_archive + if list_match ~= nil and opts.download_archive ~= nil and opts.download_archive:find("$PLAYLIST", 1, true) then + download_archive = opts.download_archive:gsub("$PLAYLIST", list_match) + end + + if download_type == DOWNLOAD.AUDIO then + mp.osd_message("Audio download started", 2) + elseif download_type == DOWNLOAD.SUBTITLE then + mp.osd_message("Subtitle download started", 2) + elseif download_type == DOWNLOAD.VIDEO_EMBED_SUBTITLE then + mp.osd_message("Video w/ subtitle download started", 2) + else + mp.osd_message("Video download started", 2) + end + + -- Compose command line arguments + local command = {} + + local range_mode_file_name = nil + local range_mode_subtitle_file_name = nil + local start_time_offset = 0 + + if select_range_mode == 0 or (select_range_mode > 0 and (download_type == DOWNLOAD.AUDIO or download_type == DOWNLOAD.SUBTITLE)) then + table.insert(command, "youtube-dl") + table.insert(command, "--no-overwrites") + if opts.restrict_filenames then + table.insert(command, "--restrict-filenames") + end + if not_empty(opts.filename) then + table.insert(command, "-o") + table.insert(command, opts.filename) + end + if opts.no_playlist then + table.insert(command, "--no-playlist") + end + if not_empty(download_archive) then + table.insert(command, "--download-archive") + table.insert(command, download_archive) + end + + if download_type == DOWNLOAD.SUBTITLE then + table.insert(command, "--sub-lang") + table.insert(command, opts.sub_lang) + table.insert(command, "--write-sub") + table.insert(command, "--skip-download") + if not_empty(opts.sub_format) then + table.insert(command, "--sub-format") + table.insert(command, opts.sub_format) + end + if select_range_mode > 0 then + mp.osd_message("Range mode is not available for subtitle-only download", 10) + is_downloading = false + return + end + elseif download_type == DOWNLOAD.AUDIO then + table.insert(command, "--extract-audio") + if not_empty(opts.audio_format) then + table.insert(command, "--audio-format") + table.insert(command, opts.audio_format) + end + if not_empty(opts.audio_quality) then + table.insert(command, "--audio-quality") + table.insert(command, opts.audio_quality) + end + if select_range_mode > 0 then + local start_time_str = tostring(start_time_seconds) + local end_time_str = tostring(end_time_seconds) + table.insert(command, "--external-downloader") + table.insert(command, "ffmpeg") + table.insert(command, "--external-downloader-args") + table.insert(command, "-loglevel warning -nostats -hide_banner -ss ".. start_time_str .. " -to " .. end_time_str .. " -avoid_negative_ts make_zero") + end + else --DOWNLOAD.VIDEO or DOWNLOAD.VIDEO_EMBED_SUBTITLE + if download_type == DOWNLOAD.VIDEO_EMBED_SUBTITLE then + table.insert(command, "--all-subs") + table.insert(command, "--write-sub") + table.insert(command, "--embed-subs") + if not_empty(opts.sub_format) then + table.insert(command, "--sub-format") + table.insert(command, opts.sub_format) + end + end + if not_empty(opts.video_format) then + table.insert(command, "--format") + if opts.video_format == "current" then + table.insert(command, get_current_format()) + else + table.insert(command, opts.video_format) + end + end + if not_empty(opts.recode_video) then + table.insert(command, "--recode-video") + table.insert(command, opts.recode_video) + end + end + if not_empty(opts.cookies) then + table.insert(command, "--cookies") + table.insert(command, opts.cookies) + end + table.insert(command, url) + + elseif select_range_mode > 0 and + (download_type == DOWNLOAD.VIDEO or download_type == DOWNLOAD.VIDEO_EMBED_SUBTITLE) then + + -- Show download indicator + mp.set_osd_ass(0, 0, "{\\an9}{\\fs12}⌛🔗") + + start_time_seconds = math.floor(start_time_seconds) + end_time_seconds = math.ceil(end_time_seconds) + + local start_time_str = tostring(start_time_seconds) + local end_time_str = tostring(end_time_seconds) + + -- Add time to the file name of the video + local filename_format + -- Insert start time/end time + if not_empty(opts.filename) then + if opts.filename:find("%%%(start_time%)") ~= nil then + -- Found "start_time" -> replace it + filename_format = tostring(opts.filename: + gsub("%%%(start_time%)[^diouxXeEfFgGcrs]*[diouxXeEfFgGcrs]", start_time_str): + gsub("%%%(end_time%)[^diouxXeEfFgGcrs]*[diouxXeEfFgGcrs]", end_time_str)) + else + local ext_pattern = "%(ext)s" + if opts.filename:sub(-#ext_pattern) == ext_pattern then + -- Insert before ext + filename_format = opts.filename:sub(1, #(opts.filename) - #ext_pattern) .. + start_time_str .. "-" .. + end_time_str .. ".%(ext)s" + else + -- append at end + filename_format = opts.filename .. start_time_str .. "-" .. end_time_str + end + end + else + -- default youtube-dl filename pattern + filename_format = "%(title)s-%(id)s." .. start_time_str .. "-" .. end_time_str .. ".%(ext)s" + end + + -- Find a suitable format + local format = "bestvideo[ext*=mp4]+bestaudio/best[ext*=mp4]/best" + local requested_format = opts.video_format + if requested_format == "current" then + requested_format = get_current_format() + end + if requested_format == nil or requested_format == "" then + format = format + elseif requested_format == "best" then + -- "best" works, because its a single file stream + format = "best" + elseif requested_format:find("mp4") ~= nil then + -- probably a mp4 format, so use it + format = requested_format + else + -- custom format, no "mp4" found -> use default + msg.warn("Select range mode requires a .mp4 format or \"best\", found " .. + requested_format .. "\n(" .. opts.video_format .. ")" .. + "\nUsing default format instead: " .. format) + end + + -- Get the download url of the video file + -- e.g.: youtube-dl -g -f bestvideo[ext*=mp4]+bestaudio/best[ext*=mp4]/best -s --get-filename https://www.youtube.com/watch?v=abcdefg + command = {"youtube-dl"} + if opts.restrict_filenames then + table.insert(command, "--restrict-filenames") + end + if not_empty(opts.cookies) then + table.insert(command, "--cookies") + table.insert(command, opts.cookies) + end + table.insert(command, "-g") + table.insert(command, "--no-playlist") + table.insert(command, "-f") + table.insert(command, format) + table.insert(command, "-o") + table.insert(command, filename_format) + table.insert(command, "-s") + table.insert(command, "--get-filename") + table.insert(command, url) + + msg.debug("info exec: " .. table.concat(command, " ")) + local info_status, info_stdout, info_stderr = exec(command, true, true) + if info_status ~= 0 then + mp.set_osd_ass(0, 0, "") + mp.osd_message("Could not retieve download stream url: status=" .. tostring(info_status) .. "\n" .. + ass0 .. "{\\fs8} " .. info_stdout:gsub("\r", "") .."\n" .. info_stderr:gsub("\r", "") .. ass1, 20) + msg.debug("info_stdout:\n" .. info_stdout) + msg.debug("info_stderr:\n" .. info_stderr) + mp.set_osd_ass(0, 0, "") + is_downloading = false + return + end + + -- Split result into lines + local info_lines = {} + local last_index = 0 + local info_lines_N = 0 + while true do + local start_i, end_i = info_stdout:find("\n", last_index, true) + if start_i then + local line = tostring(trim(info_stdout:sub(last_index, start_i))) + if line ~= "" then + table.insert(info_lines, line) + info_lines_N = info_lines_N + 1 + end + else + break + end + last_index = end_i + 1 + end + + if info_lines_N < 2 then + mp.set_osd_ass(0, 0, "") + mp.osd_message("Could not extract download stream urls and filename from output\n" .. + ass0 .. "{\\fs8} " .. info_stdout:gsub("\r", "") .."\n" .. info_stderr:gsub("\r", "") .. ass1, 20) + msg.debug("info_stdout:\n" .. info_stdout) + msg.debug("info_stderr:\n" .. info_stderr) + mp.set_osd_ass(0, 0, "") + is_downloading = false + return + end + range_mode_file_name = info_lines[info_lines_N] + table.remove(info_lines) + + if download_type == DOWNLOAD.VIDEO_EMBED_SUBTITLE then + -- youtube-dl --write-sub --skip-download https://www.youtube.com/watch?v=abcdefg -o "temp.%(ext)s" + command = {"youtube-dl", "--write-sub", "--skip-download", "--sub-lang", opts.sub_lang} + if not_empty(opts.sub_format) then + table.insert(command, "--sub-format") + table.insert(command, opts.sub_format) + end + local randomName = "tmp_" .. tostring(math.random()) + table.insert(command, "-o") + table.insert(command, randomName .. ".%(ext)s") + table.insert(command, url) + + -- Start subtitle download + msg.debug("exec: " .. table.concat(command, " ")) + local subtitle_status, subtitle_stdout, subtitle_stderr = exec(command, true, true) + if subtitle_status == 0 and subtitle_stdout:find(randomName) then + local i, j = subtitle_stdout:find(randomName .. "[^\n]+") + range_mode_subtitle_file_name = trim(subtitle_stdout:sub(i, j)) + if range_mode_subtitle_file_name ~= "" then + if range_mode_file_name:sub(-4) ~= ".mkv" then + -- Only mkv supports all kinds of subtitle formats + range_mode_file_name = range_mode_file_name:sub(1,-4) .. "mkv" + end + end + else + mp.osd_message("Could not find a suitable subtitle") + msg.debug("subtitle_stdout:\n" .. subtitle_stdout) + msg.debug("subtitle_stderr:\n" .. subtitle_stderr) + end + + end + + -- Download earlier (cut off afterwards) + start_time_offset = math.min(15, start_time_seconds) + start_time_seconds = start_time_seconds - start_time_offset + + start_time_str = tostring(start_time_seconds) + end_time_str = tostring(end_time_seconds) + + command = {"ffmpeg", "-loglevel", "warning", "-nostats", "-hide_banner", "-y"} + for _, value in ipairs(info_lines) do + table.insert(command, "-ss") + table.insert(command, start_time_str) + table.insert(command, "-to") + table.insert(command, end_time_str) + table.insert(command, "-i") + table.insert(command, value) + end + if not_empty(range_mode_subtitle_file_name) then + table.insert(command, "-ss") + table.insert(command, start_time_str) + table.insert(command, "-i") + table.insert(command, range_mode_subtitle_file_name) + table.insert(command, "-to") -- To must be after input for subtitle + table.insert(command, end_time_str) + end + table.insert(command, "-c") + table.insert(command, "copy") + table.insert(command, range_mode_file_name) + + disable_select_range() + end + + -- Show download indicator + mp.set_osd_ass(0, 0, "{\\an9}{\\fs12}⌛💾") + + -- Start download + msg.debug("exec: " .. table.concat(command, " ")) + local status, stdout, stderr = exec(command, true, true) + + if status == 0 and range_mode_file_name ~= nil then + mp.set_osd_ass(0, 0, "{\\an9}{\\fs12}⌛🔨") + + -- Cut first few seconds to fix errors + local start_time_offset_str = tostring(start_time_offset) + if #start_time_offset_str == 1 then + start_time_offset_str = "0" .. start_time_offset_str + end + local max_length = end_time_seconds - start_time_seconds + start_time_offset + 12 + local tmp_file_name = range_mode_file_name .. ".tmp." .. range_mode_file_name:sub(-3) + command = {"ffmpeg", "-loglevel", "warning", "-nostats", "-hide_banner", "-y", + "-i", range_mode_file_name, "-ss", "00:00:" .. start_time_offset_str, + "-c", "copy", "-avoid_negative_ts", "make_zero", "-t", tostring(max_length), tmp_file_name} + msg.debug("mux exec: " .. table.concat(command, " ")) + local muxstatus, muxstdout, muxstderr = exec(command, true, true) + if muxstatus ~= 0 and not_empty(muxstderr) then + msg.warn("Remux log:" .. tostring(muxstdout)) + msg.warn("Remux errorlog:" .. tostring(muxstderr)) + end + if muxstatus == 0 then + os.remove(range_mode_file_name) + os.rename(tmp_file_name, range_mode_file_name) + if not_empty(range_mode_subtitle_file_name) then + os.remove(range_mode_subtitle_file_name) + end + end + + end + + + is_downloading = false + + -- Hide download indicator + mp.set_osd_ass(0, 0, "") + + local wrote_error_log = false + if stderr ~= nil and not_empty(opts.log_file) and not_empty(stderr) then + -- Write stderr to log file + local title = mp.get_property("media-title") + local file = io.open (opts.log_file , "a+") + file:write("\n[") + file:write(start_time) + file:write("] ") + file:write(url) + file:write("\n[\"") + file:write(title) + file:write("\"]\n") + file:write(stderr) + file:close() + wrote_error_log = true + end + + if (status ~= 0) then + mp.osd_message("download failed:\n" .. tostring(stderr), 10) + msg.error("URL: " .. tostring(url)) + msg.error("Return status code: " .. tostring(status)) + msg.debug(tostring(stderr)) + msg.debug(tostring(stdout)) + return + end + + if string.find(stdout, "has already been recorded in archive") ~=nil then + mp.osd_message("Has already been recorded in archive", 5) + return + end + + -- Retrieve the file name + local filename = nil + if range_mode_file_name == nil and stdout then + local i, j, last_i, start_index = 0 + while i ~= nil do + last_i, start_index = i, j + i, j = stdout:find ("Destination: ",j, true) + end + + if last_i ~= nil then + local end_index = stdout:find ("\n", start_index, true) + if end_index ~= nil and start_index ~= nil then + filename = trim(stdout:sub(start_index, end_index)) + end + end + elseif not_empty(range_mode_file_name) then + filename = range_mode_file_name + end + + local osd_text = "Download succeeded\n" + local osd_time = 5 + -- Find filename or directory + if filename then + local filepath + local basepath + if filename:find("/") == nil and filename:find("\\") == nil then + basepath = utils.getcwd() + filepath = path_join(utils.getcwd(), filename) + else + basepath = "" + filepath = filename + end + + if filepath:len() < 100 then + osd_text = osd_text .. ass0 .. "{\\fs12} " .. filepath .. " {\\fs20}" .. ass1 + elseif basepath == "" then + osd_text = osd_text .. ass0 .. "{\\fs8} " .. filepath .. " {\\fs20}" .. ass1 + else + osd_text = osd_text .. ass0 .. "{\\fs11} " .. basepath .. "\n" .. filename .. " {\\fs20}" .. ass1 + end + if wrote_error_log then + -- Write filename and end time to log file + local file = io.open (opts.log_file , "a+") + file:write("[" .. filepath .. "]\n") + file:write(os.date("[end %c]\n")) + file:close() + end + else + if wrote_error_log then + -- Write directory and end time to log file + local file = io.open (opts.log_file , "a+") + file:write("[" .. utils.getcwd() .. "]\n") + file:write(os.date("[end %c]\n")) + file:close() + end + osd_text = osd_text .. utils.getcwd() + end + + -- Show warnings + if not_empty(stderr) then + msg.warn("Errorlog:" .. tostring(stderr)) + if stderr:find("incompatible for merge") == nil then + local i = stderr:find("Input #") + if i ~= nil then + stderr = stderr:sub(i) + end + osd_text = osd_text .. "\n" .. ass0 .. "{\\fs8} " .. stderr:gsub("\r", "") .. ass1 + osd_time = osd_time + 5 + end + end + + mp.osd_message(osd_text, osd_time) +end + +local function select_range_show() + local status + if select_range_mode > 0 then + if select_range_mode == 2 then + status = "Download range: Fine tune\n← → start time\n↓ ↑ end time\n" .. + tostring(opts.select_range_binding) .. " next mode" + elseif select_range_mode == 1 then + status = "Download range: Select interval\n← start here\n→ end here\n↓from beginning\n↑til end\n" .. + tostring(opts.select_range_binding) .. " next mode" + end + mp.osd_message("Start: " .. start_time_formated .. "\nEnd: " .. end_time_formated .. "\n" .. status, 30) + else + status = "Download range: Disabled (download full length)" + mp.osd_message(status, 3) + end +end + +local function select_range_set_left() + if select_range_mode == 2 then + start_time_seconds = math.max(0, start_time_seconds - 1) + if start_time_seconds < 86400 then + start_time_formated = os.date("!%H:%M:%S", start_time_seconds) + else + start_time_formated = tostring(start_time_seconds) .. "s" + end + elseif select_range_mode == 1 then + start_time_seconds = mp.get_property_number("time-pos") + start_time_formated = mp.command_native({"expand-text","${time-pos}"}) + end + select_range_show() +end + +local function select_range_set_start() + if select_range_mode == 2 then + end_time_seconds = math.max(1, end_time_seconds - 1) + if end_time_seconds < 86400 then + end_time_formated = os.date("!%H:%M:%S", end_time_seconds) + else + end_time_formated = tostring(end_time_seconds) .. "s" + end + elseif select_range_mode == 1 then + start_time_seconds = 0 + start_time_formated = "00:00:00" + end + select_range_show() +end + +local function select_range_set_end() + if select_range_mode == 2 then + end_time_seconds = math.min(mp.get_property_number("duration"), end_time_seconds + 1) + if end_time_seconds < 86400 then + end_time_formated = os.date("!%H:%M:%S", end_time_seconds) + else + end_time_formated = tostring(end_time_seconds) .. "s" + end + elseif select_range_mode == 1 then + end_time_seconds = mp.get_property_number("duration") + end_time_formated = mp.command_native({"expand-text","${duration}"}) + end + select_range_show() +end + +local function select_range_set_right() + if select_range_mode == 2 then + start_time_seconds = math.min(mp.get_property_number("duration") - 1, start_time_seconds + 1) + if start_time_seconds < 86400 then + start_time_formated = os.date("!%H:%M:%S", start_time_seconds) + else + start_time_formated = tostring(start_time_seconds) .. "s" + end + elseif select_range_mode == 1 then + end_time_seconds = mp.get_property_number("time-pos") + end_time_formated = mp.command_native({"expand-text","${time-pos}"}) + end + select_range_show() +end + + +local function select_range() + -- Cycle through modes + if select_range_mode == 2 then + -- Disable range mode + disable_select_range() + elseif select_range_mode == 1 then + -- Switch to "fine tune" mode + select_range_mode = 2 + else + select_range_mode = 1 + -- Add keybinds for arrow keys + mp.add_key_binding("up", "select-range-set-up", select_range_set_end) + mp.add_key_binding("down", "select-range-set-down", select_range_set_start) + mp.add_key_binding("left", "select-range-set-left", select_range_set_left) + mp.add_key_binding("right", "select-range-set-right", select_range_set_right) + + -- Defaults + if start_time_seconds == nil then + start_time_seconds = mp.get_property_number("time-pos") + start_time_formated = mp.command_native({"expand-text","${time-pos}"}) + end_time_seconds = mp.get_property_number("duration") + end_time_formated = mp.command_native({"expand-text","${duration}"}) + end + end + select_range_show() +end + +local function download_video() + return download(DOWNLOAD.VIDEO) +end + +local function download_audio() + return download(DOWNLOAD.AUDIO) +end + +local function download_subtitle() + return download(DOWNLOAD.SUBTITLE) +end + +local function download_embed_subtitle() + return download(DOWNLOAD.VIDEO_EMBED_SUBTITLE) +end + +-- keybind +if not_empty(opts.download_video_binding) then + mp.add_key_binding(opts.download_video_binding, "download-video", download_video) +end +if not_empty(opts.download_audio_binding) then + mp.add_key_binding(opts.download_audio_binding, "download-audio", download_audio) +end +if not_empty(opts.download_subtitle_binding) then + mp.add_key_binding(opts.download_subtitle_binding, "download-subtitle", download_subtitle) +end +if not_empty(opts.download_video_embed_subtitle_binding) then + mp.add_key_binding(opts.download_video_embed_subtitle_binding, "download-embed-subtitle", download_embed_subtitle) +end +if not_empty(opts.select_range_binding) then + mp.add_key_binding(opts.select_range_binding, "select-range-start", select_range) +end diff --git a/ncmpcpp/bindings b/ncmpcpp/bindings new file mode 100644 index 0000000..9b8f4da --- /dev/null +++ b/ncmpcpp/bindings @@ -0,0 +1,543 @@ +############################################################## +## This is the example bindings file. Copy it to ## +## ~/.ncmpcpp/bindings or $XDG_CONFIG_HOME/ncmpcpp/bindings ## +## and set up your preferences ## +############################################################## +## +##### General rules ##### +## +## 1) Because each action has runtime checks whether it's +## ok to run it, a few actions can be bound to one key. +## Actions will be bound in order given in configuration +## file. When a key is pressed, first action in order +## will test itself whether it's possible to run it. If +## test succeeds, action is executed and other actions +## bound to this key are ignored. If it doesn't, next +## action in order tests itself etc. +## +## 2) It's possible to bind more that one action at once +## to a key. It can be done using the following syntax: +## +## def_key "key" +## action1 +## action2 +## ... +## +## This creates a chain of actions. When such chain is +## executed, each action in chain is run until the end of +## chain is reached or one of its actions fails to execute +## due to its requirements not being met. If multiple actions +## and/or chains are bound to the same key, they will be +## consecutively run until one of them gets fully executed. +## +## 3) When ncmpcpp starts, bindings configuration file is +## parsed and then ncmpcpp provides "missing pieces" +## of default keybindings. If you want to disable some +## bindings, there is a special action called 'dummy' +## for that purpose. Eg. if you want to disable ability +## to crop playlists, you need to put the following +## into configuration file: +## +## def_key "C" +## dummy +## +## After that ncmpcpp will not bind any default action +## to this key. +## +## 4) To let you write simple macros, the following special +## actions are provided: +## +## - push_character "character" - pushes given special +## character into input queue, so it will be immediately +## picked by ncmpcpp upon next call to readKey function. +## Accepted values: mouse, up, down, page_up, page_down, +## home, end, space, enter, insert, delete, left, right, +## tab, ctrl-a, ctrl-b, ..., ctrl-z, ctrl-[, ctrl-\\, +## ctrl-], ctrl-^, ctrl-_, f1, f2, ..., f12, backspace. +## In addition, most of these names can be prefixed with +## alt-/ctrl-/shift- to be recognized with the appropriate +## modifier key(s). +## +## - push_characters "string" - pushes given string into +## input queue. +## +## - require_runnable "action" - checks whether given action +## is runnable and fails if it isn't. This is especially +## useful when mixed with previous two functions. Consider +## the following macro definition: +## +## def_key "key" +## push_characters "custom_filter" +## apply_filter +## +## If apply_filter can't be currently run, we end up with +## sequence of characters in input queue which will be +## treated just as we typed them. This may lead to unexpected +## results (in this case 'c' will most likely clear current +## playlist, 'u' will trigger database update, 's' will stop +## playback etc.). To prevent such thing from happening, we +## need to change above definition to this one: +## +## def_key "key" +## require_runnable "apply_filter" +## push_characters "custom_filter" +## apply_filter +## +## Here, first we test whether apply_filter can be actually run +## before we stuff characters into input queue, so if condition +## is not met, whole chain is aborted and we're fine. +## +## - require_screen "screen" - checks whether given screen is +## currently active. accepted values: browser, clock, help, +## media_library, outputs, playlist, playlist_editor, +## search_engine, tag_editor, visualizer, last_fm, lyrics, +## selected_items_adder, server_info, song_info, +## sort_playlist_dialog, tiny_tag_editor. +## +## - run_external_command "command" - runs given command using +## system() function. +## +## 5) In addition to binding to a key, you can also bind actions +## or chains of actions to a command. If it comes to commands, +## syntax is very similar to defining keys. Here goes example +## definition of a command: +## +## def_command "quit" [deferred] +## stop +## quit +## +## If you execute the above command (which can be done by +## invoking action execute_command, typing 'quit' and pressing +## enter), ncmpcpp will stop the player and then quit. Note the +## presence of word 'deferred' enclosed in square brackets. It +## tells ncmpcpp to wait for confirmation (ie. pressing enter) +## after you typed quit. Instead of 'deferred', 'immediate' +## could be used. Then ncmpcpp will not wait for confirmation +## (enter) and will execute the command the moment it sees it. +## +## Note: while command chains are executed, internal environment +## update (which includes current window refresh and mpd status +## update) is not performed for performance reasons. However, it +## may be desirable to do so in some situration. Therefore it's +## possible to invoke by hand by performing 'update enviroment' +## action. +## +## Note: There is a difference between: +## +## def_key "key" +## action1 +## +## def_key "key" +## action2 +## +## and +## +## def_key "key" +## action1 +## action2 +## +## First one binds two single actions to the same key whilst +## second one defines a chain of actions. The behavior of +## these two is different and is described in (1) and (2). +## +## Note: Function def_key accepts non-ascii characters. +## +##### List of unbound actions ##### +## +## The following actions are not bound to any key/command: +## +## - set_volume +## +# +#def_key "mouse" +# mouse_event +# +def_key "k" + scroll_up + +def_key "K" + select_item + scroll_up + +def_key "j" + scroll_down + +def_key "J" + select_item + scroll_down + +def_key "[" + scroll_up_album + +def_key "]" + scroll_down_album + +def_key "{" + scroll_up_artist + +def_key "}" + scroll_down_artist + +#def_key "page_up" +# page_up +# +#def_key "page_down" +# page_down +# +#def_key "home" +# move_home +# +#def_key "end" +# move_end +# +#def_key "insert" +# select_item +# +#def_key "enter" +# enter_directory +# +#def_key "enter" +# toggle_output +# +#def_key "enter" +# run_action +# +#def_key "enter" +# play_item +# +#def_key "space" +# add_item_to_playlist +# +#def_key "space" +# toggle_lyrics_update_on_song_change +# +#def_key "space" +# toggle_visualization_type +# +#def_key "delete" +# delete_playlist_items +# +#def_key "delete" +# delete_browser_items +# +#def_key "delete" +# delete_stored_playlist + +def_key "l" + next_column + +def_key "l" + slave_screen + +#def_key "right" +# volume_up +# +#def_key "+" +# volume_up + +def_key "h" + previous_column + +def_key "h" + master_screen + +#def_key "left" +# volume_down +# +#def_key "-" +# volume_down +# +#def_key ":" +# execute_command +# +#def_key "tab" +# next_screen +# +#def_key "shift-tab" +# previous_screen +# +#def_key "f1" +# show_help +# +#def_key "1" +# show_playlist +# +#def_key "2" +# show_browser +# +#def_key "2" +# change_browse_mode +# +#def_key "3" +# show_search_engine +# +#def_key "3" +# reset_search_engine +# +#def_key "4" +# show_media_library +# +#def_key "4" +# toggle_media_library_columns_mode +# +#def_key "5" +# show_playlist_editor +# +#def_key "6" +# show_tag_editor +# +#def_key "7" +# show_outputs +# +#def_key "8" +# show_visualizer +# +#def_key "=" +# show_clock +# +#def_key "@" +# show_server_info +# +#def_key "s" +# stop +# +#def_key "p" +# pause +# +#def_key ">" +# next +# +#def_key "<" +# previous +# +#def_key "ctrl-h" +# jump_to_parent_directory +# +#def_key "ctrl-h" +# replay_song +# +#def_key "backspace" +# jump_to_parent_directory +# +#def_key "backspace" +# replay_song +# +#def_key "f" +# seek_forward +# +#def_key "b" +# seek_backward +# +#def_key "r" +# toggle_repeat +# +#def_key "z" +# toggle_random +# +#def_key "y" +# save_tag_changes +# +#def_key "y" +# start_searching +# +#def_key "y" +# toggle_single +# +#def_key "R" +# toggle_consume +# +#def_key "Y" +# toggle_replay_gain_mode +# +#def_key "T" +# toggle_add_mode +# +#def_key "|" +# toggle_mouse +# +#def_key "#" +# toggle_bitrate_visibility +# +#def_key "Z" +# shuffle +# +#def_key "x" +# toggle_crossfade +# +#def_key "X" +# set_crossfade +# +#def_key "u" +# update_database +# +#def_key "ctrl-s" +# sort_playlist +# +#def_key "ctrl-s" +# toggle_browser_sort_mode +# +#def_key "ctrl-s" +# toggle_media_library_sort_mode +# +#def_key "ctrl-r" +# reverse_playlist +# +#def_key "ctrl-f" +# apply_filter +# +#def_key "ctrl-_" +# select_found_items +# +#def_key "/" +# find +# +#def_key "/" +# find_item_forward +# +#def_key "?" +# find +# +#def_key "?" +# find_item_backward +# +#def_key "." +# next_found_item +# +#def_key "," +# previous_found_item +# +#def_key "w" +# toggle_find_mode +# +#def_key "e" +# edit_song +# +#def_key "e" +# edit_library_tag +# +#def_key "e" +# edit_library_album +# +#def_key "e" +# edit_directory_name +# +#def_key "e" +# edit_playlist_name +# +#def_key "e" +# edit_lyrics +# +#def_key "i" +# show_song_info +# +#def_key "I" +# show_artist_info +# +#def_key "g" +# jump_to_position_in_song +# +#def_key "l" +# show_lyrics +# +#def_key "ctrl-v" +# select_range +# +#def_key "v" +# reverse_selection +# +#def_key "V" +# remove_selection +# +#def_key "B" +# select_album +# +#def_key "a" +# add_selected_items +# +#def_key "c" +# clear_playlist +# +#def_key "c" +# clear_main_playlist +# +#def_key "C" +# crop_playlist +# +#def_key "C" +# crop_main_playlist +# +#def_key "m" +# move_sort_order_up +# +#def_key "m" +# move_selected_items_up +# +#def_key "n" +# move_sort_order_down +# +#def_key "n" +# move_selected_items_down +# +#def_key "M" +# move_selected_items_to +# +#def_key "A" +# add +# +#def_key "S" +# save_playlist +# +#def_key "o" +# jump_to_playing_song +# +#def_key "G" +# jump_to_browser +# +#def_key "G" +# jump_to_playlist_editor +# +#def_key "~" +# jump_to_media_library +# +#def_key "E" +# jump_to_tag_editor +# +#def_key "U" +# toggle_playing_song_centering +# +#def_key "P" +# toggle_display_mode +# +#def_key "\\" +# toggle_interface +# +#def_key "!" +# toggle_separators_between_albums +# +#def_key "L" +# toggle_lyrics_fetcher +# +#def_key "F" +# fetch_lyrics_in_background +# +#def_key "alt-l" +# toggle_fetching_lyrics_in_background +# +#def_key "ctrl-l" +# toggle_screen_lock +# +#def_key "`" +# toggle_library_tag_type +# +#def_key "`" +# refetch_lyrics +# +#def_key "`" +# add_random_items +# +#def_key "ctrl-p" +# set_selected_items_priority +# +#def_key "q" +# quit +# diff --git a/ncmpcpp/config b/ncmpcpp/config new file mode 100644 index 0000000..2b4b68f --- /dev/null +++ b/ncmpcpp/config @@ -0,0 +1,544 @@ +############################################################################## +## This is the example configuration file. Copy it to $HOME/.ncmpcpp/config ## +## or $XDG_CONFIG_HOME/ncmpcpp/config and set up your preferences. ## +############################################################################## +# +##### directories ###### +## +## Directory for storing ncmpcpp related files. Changing it is useful if you +## want to store everything somewhere else and provide command line setting for +## alternative location to config file which defines that while launching +## ncmpcpp. +## +# +ncmpcpp_directory = ~/.config/ncmpcpp +# +## +## Directory for storing downloaded lyrics. It defaults to ~/.lyrics since other +## MPD clients (eg. ncmpc) also use that location. +## +# +lyrics_directory = ~/.config/ncmpcpp/lyrics +# +##### connection settings ##### +# +mpd_host = ~/.config/mpd/socket +# +#mpd_port = 6600 +# +#mpd_connection_timeout = 5 +# +## Needed for tag editor and file operations to work. +## +#mpd_music_dir = ~/music +# +#mpd_crossfade_time = 5 +# +##### music visualizer ##### +## +## Note: In order to make music visualizer work you'll need to use mpd fifo +## output, whose format parameter has to be set to 44100:16:1 for mono +## visualization or 44100:16:2 for stereo visualization. Example configuration +## (it has to be put into mpd.conf): +## +audio_output { + type "fifo" + name "Visualizer feed" + path "/tmp/mpd.fifo" + format "44100:16:2" +} +## +# +visualizer_data_source = /tmp/mpd.fifo +# +## +## Note: Below parameter is needed for ncmpcpp to determine which output +## provides data for visualizer and thus allow syncing between visualization and +## sound as currently there are some problems with it. +## +# +visualizer_output_name = my_fifo +# +## +## If you set format to 44100:16:2, make it 'yes'. +## +#visualizer_in_stereo = yes +# +## +## Note: Below parameter defines how often ncmpcpp has to "synchronize" +## visualizer and audio outputs. 30 seconds is optimal value, but if you +## experience synchronization problems, set it to lower value. Keep in mind +## that sane values start with >=10. +## +# +#visualizer_sync_interval = 30 +# +## +## Note: To enable spectrum frequency visualization you need to compile ncmpcpp +## with fftw3 support. +## +# +## Available values: spectrum, wave, wave_filled, ellipse. +## +visualizer_type = spectrum +# +visualizer_look = ●▮ +# +#visualizer_color = blue, cyan, green, yellow, magenta, red +# +## Alternative subset of 256 colors for terminals that support it. +## +#visualizer_color = 41, 83, 119, 155, 185, 215, 209, 203, 197, 161 +# +##### system encoding ##### +## +## ncmpcpp should detect your charset encoding but if it failed to do so, you +## can specify charset encoding you are using here. +## +## Note: You can see whether your ncmpcpp build supports charset detection by +## checking output of `ncmpcpp --version`. +## +## Note: Since MPD uses UTF-8 by default, setting this option makes sense only +## if your encoding is different. +## +# +#system_encoding = "" +# +##### delays ##### +# +## Time of inactivity (in seconds) after playlist highlighting will be disabled +## (0 = always on). +## +#playlist_disable_highlight_delay = 5 +# +## Defines how long messages are supposed to be visible. +## +#message_delay_time = 5 +# +##### song format ##### +## +## For a song format you can use: +## +## %l - length +## %f - filename +## %D - directory +## %a - artist +## %A - album artist +## %t - title +## %b - album +## %y - date +## %n - track number (01/12 -> 01) +## %N - full track info (01/12 -> 01/12) +## %g - genre +## %c - composer +## %p - performer +## %d - disc +## %C - comment +## %P - priority +## $R - begin right alignment +## +## If you want to make sure that a part of the format is displayed only when +## certain tags are present, you can archieve it by grouping them with brackets, +## e.g. '{%a - %t}' will be evaluated to 'ARTIST - TITLE' if both tags are +## present or '' otherwise. It is also possible to define a list of +## alternatives by providing several groups and separating them with '|', +## e.g. '{%t}|{%f}' will be evaluated to 'TITLE' or 'FILENAME' if the former is +## not present. +## +## Note: If you want to set limit on maximal length of a tag, just put the +## appropriate number between % and character that defines tag type, e.g. to +## make album take max. 20 terminal cells, use '%20b'. +## +## In addition, formats support markers used for text attributes. They are +## followed by character '$'. After that you can put: +## +## - 0 - default window color (discards all other colors) +## - 1 - black +## - 2 - red +## - 3 - green +## - 4 - yellow +## - 5 - blue +## - 6 - magenta +## - 7 - cyan +## - 8 - white +## - 9 - end of current color +## - b - bold text +## - u - underline text +## - r - reverse colors +## - a - use alternative character set +## +## If you don't want to use a non-color attribute anymore, just put it again, +## but this time insert character '/' between '$' and attribute character, +## e.g. {$b%t$/b}|{$r%f$/r} will display bolded title tag or filename with +## reversed colors. +## +## If you want to use 256 colors and/or background colors in formats (the naming +## scheme is described below in section about color definitions), it can be done +## with the syntax $(COLOR), e.g. to set the artist tag to one of the +## non-standard colors and make it have yellow background, you need to write +## $(197_yellow)%a$(end). Note that for standard colors this is interchangable +## with attributes listed above. +## +## Note: colors can be nested. +## +# +#song_list_format = {%a - }{%t}|{$8%f$9}$R{$3(%l)$9} +# +#song_status_format = {{%a{ "%b"{ (%y)}} - }{%t}}|{%f} +# +#song_library_format = {%n - }{%t}|{%f} +# +#alternative_header_first_line_format = $b$1$aqqu$/a$9 {%t}|{%f} $1$atqq$/a$9$/b +# +#alternative_header_second_line_format = {{$4$b%a$/b$9}{ - $7%b$9}{ ($4%y$9)}}|{%D} +# +#current_item_prefix = $(yellow)$r +# +#current_item_suffix = $/r$(end) +# +#current_item_inactive_column_prefix = $(white)$r +# +#current_item_inactive_column_suffix = $/r$(end) +# +#now_playing_prefix = $b +# +#now_playing_suffix = $/b +# +#browser_playlist_prefix = "$2playlist$9 " +# +#selected_item_prefix = $6 +# +#selected_item_suffix = $9 +# +#modified_item_prefix = $3> $9 +# +## +## Note: attributes are not supported for the following variables. +## +#song_window_title_format = {%a - }{%t}|{%f} +## +## Note: Below variables are used for sorting songs in browser. The sort mode +## determines how songs are sorted, and can be used in combination with a sort +## format to specify a custom sorting format. Available values for +## browser_sort_mode are "name", "mtime", "format" and "noop". +## +# +#browser_sort_mode = name +# +#browser_sort_format = {%a - }{%t}|{%f} {(%l)} +# +##### columns settings ##### +## +## syntax of song columns list format is "column column etc." +## +## - syntax for each column is: +## +## (width of the column)[color of the column]{displayed tag} +## +## Note: Width is by default in %, if you want a column to have fixed size, add +## 'f' after the value, e.g. (10)[white]{a} will be the column that take 10% of +## screen (so the real width will depend on actual screen size), whereas +## (10f)[white]{a} will take 10 terminal cells, no matter how wide the screen +## is. +## +## - color is optional (if you want the default one, leave the field empty). +## +## Note: You can give a column additional attributes by putting appropriate +## character after displayed tag character. Available attributes are: +## +## - r - column will be right aligned +## - E - if tag is empty, empty tag marker won't be displayed +## +## You can also: +## +## - give a column custom name by putting it after attributes, separated with +## character ':', e.g. {lr:Length} gives you right aligned column of lengths +## named "Length". +## +## - define sequence of tags, that have to be displayed in case predecessor is +## empty in a way similar to the one in classic song format, i.e. using '|' +## character, e.g. {a|c|p:Owner} creates column named "Owner" that tries to +## display artist tag and then composer and performer if previous ones are not +## available. +## +# +#song_columns_list_format = (20)[]{a} (6f)[green]{NE} (50)[white]{t|f:Title} (20)[cyan]{b} (7f)[magenta]{l} +# +##### various settings ##### +# +## +## Note: Custom command that will be executed each time song changes. Useful for +## notifications etc. +## +#execute_on_song_change = "" +# +## +## Note: Custom command that will be executed each time player state +## changes. The environment variable MPD_PLAYER_STATE is set to the current +## state (either unknown, play, pause, or stop) for its duration. +## +# +#execute_on_player_state_change = "" +# +#playlist_show_mpd_host = no +# +#playlist_show_remaining_time = no +# +#playlist_shorten_total_times = no +# +#playlist_separate_albums = no +# +## +## Note: Possible display modes: classic, columns. +## +#playlist_display_mode = columns +# +#browser_display_mode = classic +# +#search_engine_display_mode = classic +# +#playlist_editor_display_mode = classic +# +#discard_colors_if_item_is_selected = yes +# +#show_duplicate_tags = yes +# +#incremental_seeking = yes +# +#seek_time = 1 +# +#volume_change_step = 2 +# +#autocenter_mode = no +# +#centered_cursor = no +# +## +## Note: You can specify third character which will be used to build 'empty' +## part of progressbar. +## +#progressbar_look = => +# +## Available values: database, playlist. +## +#default_place_to_search_in = database +# +## Available values: classic, alternative. +## +#user_interface = classic +# +#data_fetching_delay = yes +# +## Available values: artist, album_artist, date, genre, composer, performer. +## +#media_library_primary_tag = artist +# +#media_library_albums_split_by_date = yes +# +## Available values: wrapped, normal. +## +#default_find_mode = wrapped +# +#default_tag_editor_pattern = %n - %t +# +#header_visibility = yes +# +#statusbar_visibility = yes +# +#titles_visibility = yes +# +#header_text_scrolling = yes +# +#cyclic_scrolling = no +# +#lines_scrolled = 2 +# +#lyrics_fetchers = lyricwiki, azlyrics, genius, sing365, lyricsmania, metrolyrics, justsomelyrics, jahlyrics, plyrics, tekstowo, internet +# +#follow_now_playing_lyrics = no +# +#fetch_lyrics_for_current_song_in_background = no +# +#store_lyrics_in_song_dir = no +# +#generate_win32_compatible_filenames = yes +# +#allow_for_physical_item_deletion = no +# +## +## Note: If you set this variable, ncmpcpp will try to get info from last.fm in +## language you set and if it fails, it will fall back to english. Otherwise it +## will use english the first time. +## +## Note: Language has to be expressed as an ISO 639 alpha-2 code. +## +#lastfm_preferred_language = en +# +#space_add_mode = add_remove +# +#show_hidden_files_in_local_browser = no +# +## +## How shall screen switcher work? +## +## - "previous" - switch between the current and previous screen. +## - "screen1,...,screenN" - switch between given sequence of screens. +## +## Screens available for use: help, playlist, browser, search_engine, +## media_library, playlist_editor, tag_editor, outputs, visualizer, clock, +## lyrics, last_fm. +## +#screen_switcher_mode = playlist, browser +# +## +## Note: You can define startup screen by choosing screen from the list above. +## +#startup_screen = playlist +# +## +## Note: You can define startup slave screen by choosing screen from the list +## above or an empty value for no slave screen. +## +#startup_slave_screen = "" +# +#startup_slave_screen_focus = no +# +## +## Default width of locked screen (in %). Acceptable values are from 20 to 80. +## +# +#locked_screen_width_part = 50 +# +#ask_for_locked_screen_width_part = yes +# +#jump_to_now_playing_song_at_start = yes +# +#ask_before_clearing_playlists = yes +# +#clock_display_seconds = no +# +#display_volume_level = yes +# +#display_bitrate = no +# +#display_remaining_time = no +# +## Available values: none, basic, extended, perl. +## +#regular_expressions = perl +# +## +## Note: if below is enabled, ncmpcpp will ignore leading "The" word while +## sorting items in browser, tags in media library, etc. +## +#ignore_leading_the = no +# +## +## Note: if below is enabled, ncmpcpp will ignore diacritics while searching and +## filtering lists. This takes an effect only if boost was compiled with ICU +## support. +## +#ignore_diacritics = no +# +#block_search_constraints_change_if_items_found = yes +# +#mouse_support = yes +# +#mouse_list_scroll_whole_page = yes +# +#empty_tag_marker = +# +#tags_separator = " | " +# +#tag_editor_extended_numeration = no +# +#media_library_sort_by_mtime = no +# +#enable_window_title = yes +# +## +## Note: You can choose default search mode for search engine. Available modes +## are: +## +## - 1 - use mpd built-in searching (no regexes, pattern matching) +## +## - 2 - use ncmpcpp searching (pattern matching with support for regexes, but +## if your mpd is on a remote machine, downloading big database to process +## it can take a while +## +## - 3 - match only exact values (this mode uses mpd function for searching in +## database and local one for searching in current playlist) +## +# +#search_engine_default_search_mode = 1 +# +#external_editor = nano +# +## Note: set to yes if external editor is a console application. +## +#use_console_editor = yes +# +##### colors definitions ##### +## +## It is possible to set a background color by setting a color value +## "_", e.g. red_black will set foregound color to red +## and background color to black. +## +## In addition, for terminals that support 256 colors it is possible to set one +## of them by using a number in range [1, 256] instead of color name, +## e.g. numerical value corresponding to red_black is 2_1. To find out if the +## terminal supports 256 colors, run ncmpcpp and check out the bottom of the +## help screen for list of available colors and their numerical values. +## +## What is more, there are two special values for the background color: +## "transparent" and "current". The first one explicitly sets the background to +## be transparent, while the second one allows you to preserve current +## background color and change only the foreground one. It's used implicitly +## when background color is not specified. +## +## Moreover, it is possible to attach format information to selected color +## variables by appending to their end a colon followed by one or more format +## flags, e.g. black:b or red:ur. The following variables support this syntax: +## visualizer_color, color1, color2, empty_tag_color, volume_color, +## state_line_color, state_flags_color, progressbar_color, +## progressbar_elapsed_color, player_state_color, statusbar_time_color, +## alternative_ui_separator_color. +## +## Note: due to technical limitations of older ncurses version, if 256 colors +## are used there is a possibility that you'll be able to use only colors with +## transparent background. +# +#colors_enabled = yes +# +#empty_tag_color = cyan +# +#header_window_color = default +# +#volume_color = default +# +#state_line_color = default +# +#state_flags_color = default:b +# +#main_window_color = yellow +# +#color1 = white +# +#color2 = green +# +#progressbar_color = black:b +# +#progressbar_elapsed_color = green:b +# +#statusbar_color = default +# +#statusbar_time_color = default:b +# +#player_state_color = default:b +# +#alternative_ui_separator_color = black:b +# +#window_border_color = green +# +#active_window_border = red +# diff --git a/ncmpcpp/patterns.list b/ncmpcpp/patterns.list new file mode 100644 index 0000000..e69de29 diff --git a/newsboat/config b/newsboat/config new file mode 100644 index 0000000..b9b8b26 --- /dev/null +++ b/newsboat/config @@ -0,0 +1,55 @@ +#show-read-feeds no +auto-reload yes + +external-url-viewer "urlscan -dc -r 'browser {}'" + +bind-key j down +bind-key k up +bind-key j next articlelist +bind-key k prev articlelist +bind-key J next-feed articlelist +bind-key K prev-feed articlelist +bind-key G end +bind-key g home +bind-key d pagedown +bind-key u pageup +bind-key l open +bind-key h quit +bind-key a toggle-article-read +bind-key n next-unread +bind-key N prev-unread +bind-key D pb-download +bind-key U show-urls +bind-key x pb-delete + +color listnormal cyan default +color listfocus black yellow standout bold +color listnormal_unread blue default +color listfocus_unread yellow default bold +color info red black bold +color article white default bold + +browser browser +macro , open-in-browser +macro t set browser "qndl" ; open-in-browser ; set browser browser +macro a set browser "tsp youtube-dl --add-metadata -xic -f bestaudio/best" ; open-in-browser ; set browser browser +macro v set browser "setsid -f mpv" ; open-in-browser ; set browser browser +macro w set browser "lynx" ; open-in-browser ; set browser browser +macro d set browser "dmenuhandler" ; open-in-browser ; set browser browser +macro c set browser "echo %u | xclip -r -sel c" ; open-in-browser ; set browser browser +macro C set browser "youtube-viewer --comments=%u" ; open-in-browser ; set browser browser +macro p set browser "peertubetorrent %u 480" ; open-in-browser ; set browser browser +macro P set browser "peertubetorrent %u 1080" ; open-in-browser ; set browser browser + +highlight all "---.*---" yellow +highlight feedlist ".*(0/0))" black +highlight article "(^Feed:.*|^Title:.*|^Author:.*)" cyan default bold +highlight article "(^Link:.*|^Date:.*)" default default +highlight article "https?://[^ ]+" green default +highlight article "^(Title):.*$" blue default +highlight article "\\[[0-9][0-9]*\\]" magenta default bold +highlight article "\\[image\\ [0-9]+\\]" green default bold +highlight article "\\[embedded flash: [0-9][0-9]*\\]" green default bold +highlight article ":.*\\(link\\)$" cyan default +highlight article ":.*\\(image\\)$" blue default +highlight article ":.*\\(embedded flash\\)$" magenta default diff --git a/nvim/init.vim b/nvim/init.vim new file mode 100644 index 0000000..b5831c2 --- /dev/null +++ b/nvim/init.vim @@ -0,0 +1,267 @@ +" vimplugs {{{ +call plug#begin('~/.config/nvim/plugged') +" colorschemes {{{ +Plug 'tomasiser/vim-code-dark' " codedark color scheme +Plug 'flazz/vim-colorschemes' " meta-color scheme package +" }}} +" language support {{{ +Plug 'axvr/org.vim' " basic org markup language implementation +Plug 'ziglang/zig.vim' " zig programming language +Plug 'jdonaldson/vaxe' " haxe programming language +Plug 'xuhdev/vim-latex-live-preview', { 'for': 'tex' } " latex live preview support +Plug 'waycrate/swhkd-vim' " swhkd syntax highlighting +Plug 'HiPhish/guile.vim' " guile syntax highlighting +" }}} +" utility {{{ +Plug 'preservim/nerdtree' " directory tree interface +Plug 'Xuyuanp/nerdtree-git-plugin' " git status indicator for nerdtree +Plug 'PhilRunninger/nerdtree-visual-selection' " allows visual selection mode in nerdtree +Plug 'tpope/vim-fugitive' " git command interface +Plug 'junegunn/goyo.vim' " simplify the user interface (distraction-free) [BROKEN] +Plug 'junegunn/limelight.vim' " focus on single paragraph of text at a time +Plug 'vim-airline/vim-airline' " powerline the vim bottom bar +Plug 'nathanaelkane/vim-indent-guides' " indent guides for vim +Plug 'mhinz/vim-signify' " use signs to show diffs +Plug 'tpope/vim-endwise' " auto end functions/if statements +Plug 'tpope/vim-surround' " auto close stuff +Plug 'mattn/emmet-vim' " html css easy formating +Plug 'godlygeek/tabular' " Needed for vim-markdown +Plug 'plasticboy/vim-markdown' " Better markdown support +Plug 'ryanoasis/vim-devicons' " dev icons for nerdtree +" }}} +call plug#end() + +" }}} +" nvim options {{{ + +"" nvimrc: +"" General + +set showmatch " Highlight matching brace + +set number +set relativenumber + +colorscheme BlackSea + +set hlsearch " Highlight all search results +set smartcase " Enable smart-case search +set incsearch " Searches for strings incrementally + +set expandtab " Use spaces instead of tabs +set shiftwidth=2 " Number of auto-indent spaces +set smartindent " Enable smart-indent +set smarttab " Enable smart-tabs +set softtabstop=2 " Number of spaces per Tab + +"" Advanced +set ruler " Show row and column ruler information +set undolevels=1000 " Number of undo levels +set backspace=indent,eol,start " Backspace behaviour +filetype plugin indent on + +"" GUI Config +set guifont=mononoki\ Nerd\ Font\ Mono:h12 + +hi Normal guibg=NONE ctermbg=NONE +hi NonText guibg=NONE ctermbg=NONE +set background=dark + +set foldmethod=marker + +set conceallevel=2 + +" set leader key + +let mapleader="'" + +" emmet {{{ +let g:user_emmet_leader_key=';' +" }}} + +" zig config {{{ +let g:zig_fmt_autosave = 1 +" }}} + +" latex live preview {{{ +let g:livepreview_previewer = 'zathura' +let g:livepreview_use_biber = 1 +let g:livepreview_cursorhold_recompile = 0 +" }}} + +" vim-markdown {{{ +let g:vim_markdown_folding_disabled = 1 +let g:vim_markdown_folding_level = 3 +let g:vim_markdown_toc_autofit = 1 +let g:vim_markdown_emphasis_multiline = 0 +let g:tex_conceal = "" +let g:vim_markdown_math = 1 +let g:vim_markdown_conceal_code_blocks = 1 +let g:vim_markdown_fenced_languages = ['c++=cpp', 'viml=vim', 'bash=sh', 'ini=dosini'] +let g:vim_markdown_follow_anchor = 1 +let g:vim_markdown_math = 1 +let g:vim_markdown_frontmatter = 1 +let g:vim_markdown_toml_frontmatter = 1 +let g:vim_markdown_strikethrough = 1 +let g:vim_markdown_no_extensions_in_markdown = 1 +let g:vim_markdown_autowrite = 1 +let g:vim_markdown_auto_insert_bullets = 0 +let g:vim_markdown_new_list_item_indent = 0 +let g:vim_markdown_edit_url_in = 'tab' +" }}} + +" NERDTree config {{{ +let g:NERDTreeGitStatusUseNerdFonts = 1 " use nerd fonts +let g:NERDTreeGitStatusShowClean = 1 " default: 0 +let g:NERDTreeDirArrowExpandable = '>' +let g:NERDTreeDirArrowCollapsible = '<' +let g:NERDTreeMapToggleHidden = 'z' +" }}} + +" Goyo config {{{ +let g:goyo_width = '90%' +let g:goyo_height = '100%' +" }}} + +" limelight config {{{ +let g:limelight_conceal_ctermfg = 'gray' +let g:limelight_conceal_guifg = 'gray' +" }}} + +" devicon config {{{ +let g:airline_powerline_fonts = 1 +let g:webdevicons_enable_nerdtree = 1 +" }}} + +" vim-indent-guides config {{{ +let g:indent_guides_enable_on_vim_startup = 0 +" }}} + +" vim-signify config {{{ +set updatetime=100 +" }}} + +" }}} +" Functions {{{ +" Goyo functions {{{ +function! s:goyo_enter() + if executable('tmux') && strlen($TMUX) + silent !tmux set status off + silent !tmux list-panes -F '\#F' | grep -q Z || tmux resize-pane -Z + endif + set noshowmode + set noshowcmd + set scrolloff=999 + Limelight + NERDTreeClose +endfunction +function! s:goyo_leave() + if executable('tmux') && strlen('$TMUX') + silent !tmux set status on + silent !tmux list-panes -F '\#F' | grep -q Z && tmux resize-pane -Z + endif + set showmode + set showcmd + set scrolloff=5 + Limelight! + NERDTree +endfunction +" }}} +" }}} +" Autocommands {{{ +" Goyo autocommands {{{ +autocmd! User GoyoEnter nested call goyo_enter() +autocmd! User GoyoLeave nested call goyo_leave() +" }}} +" NERDTree autocmds {{{ +autocmd StdinReadPre * let s:std_in=1 +autocmd VimEnter * if argc() == 0 && !exists('s:std_in') | NERDTree | wincmd p | endif +autocmd VimEnter * if argc() == 1 && isdirectory(argv()[0]) && !exists('s:std_in') | + \ execute 'NERDTree' argv()[0] | wincmd p | enew | execute 'cd '.argv()[0] | endif +autocmd BufEnter * if tabpagenr('$') == 1 && winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() | quit | endif +autocmd BufEnter * if winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() | quit | endif +"autocmd BufEnter * if bufname('#') =~ 'NERD_tree_\d\+' && bufname('%') !~ 'NERD_tree_\d\+' && winnr('$') > 1 | + "\ let buf=bufnr() | buffer# | execute "normal! \w" | execute 'buffer;.buf | endif +autocmd BufWinEnter * if getcmdwintype() == '' | silent NERDTreeMirror | endif +" }}} +" custom augroup {{{ +augroup custom + autocmd! + au BufEnter *.tex :LLPStartPreview + au BufEnter *.md :set textwidth=80 + au BufWritePost init.vim :source % + au BufWritePost *.tex :make + au BufWritePost *sxhkdrc* :!pkill -USR1 -x sxhkd + au BufWritePost .Xresources :!xrdb ~/.Xresources + au BufWritePost .gitignore :!git add .gitignore +augroup end +" }}} +" }}} +" keybindings {{{ + +inoremap gj +inoremap gk +inoremap g +inoremap g +vnoremap gj +vnoremap gk +vnoremap g +vnoremap g +noremap gj +noremap gk + +" toggles +noremap tn :set number! +noremap tr :set relativenumber! +noremap tt :NERDTreeToggle + +" tabs +noremap th :tabprevious +noremap tl :tabnext +noremap tk :tabnew +noremap tj :tabclose + +" splits +noremap wh :vertical resize -1 +noremap wj :resize -1 +noremap wk :resize +1 +noremap wl :vertical resize +1 + +" config +noremap en :e ~/.config/nvim/init.vim +noremap ec :source % + +" write as root +noremap ZW :w !pkexec tee % >/dev/null + +" Goyo +noremap G :Goyo + +" windows +nnoremap h +nnoremap j +nnoremap k +nnoremap l +vnoremap h +vnoremap j +vnoremap k +vnoremap l +noremap xx :q +noremap x! :q! +noremap xw :wq +noremap w :w + +" escape for term windows +tnoremap + +" vim-plug +noremap pi :PlugInstall +noremap pu :PlugUpdate +noremap pU :PlugUpgrade +noremap pc :PlugClean + +" fugitive +noremap gp :G pull +noremap gd :G diff % + +" }}} diff --git a/nyxt/auto-config.lisp b/nyxt/auto-config.lisp new file mode 100644 index 0000000..88335fa --- /dev/null +++ b/nyxt/auto-config.lisp @@ -0,0 +1,4 @@ +(DEFINE-CONFIGURATION BUFFER + ((DEFAULT-MODES (APPEND '(NYXT::VI-NORMAL-MODE) %SLOT-DEFAULT%)))) +(DEFINE-CONFIGURATION PROMPT-BUFFER + ((DEFAULT-MODES (APPEND '(NYXT::VI-INSERT-MODE) %SLOT-DEFAULT%)))) diff --git a/open/openrc b/open/openrc new file mode 100644 index 0000000..2c5ebd0 --- /dev/null +++ b/open/openrc @@ -0,0 +1,15 @@ +[full] +browser: ^https?://, www\., \.com, \.co\.uk, \.net +#in_terminal yplay.pl: ^(http://)?(www\.)?youtube\.com/watch\?v= +in_terminal $VISUAL: \.[^/]*rc$ + +[suffix] +soffice: odp, pptx?, docx? +neovide: txt, c, cpp, nfo, pl, py, s, conf, md, yaml, toml, lua, h, lisp +st -e less: log +mpv: mp3, wav, mp4, wmv +zathura: pdf, epub, ps +browser: html? +soffice: odt + +#xterm -e wget: http://.*.(tar|gz|bz2) - not called due to hash ordering diff --git a/paru/paru.conf b/paru/paru.conf new file mode 100644 index 0000000..8932c55 --- /dev/null +++ b/paru/paru.conf @@ -0,0 +1,37 @@ +# +# $PARU_CONF +# /etc/paru.conf +# ~/.config/paru/paru.conf +# +# See the paru.conf(5) manpage for options + +# +# GENERAL OPTIONS +# +[options] +PgpFetch +Devel +Provides +DevelSuffixes = -git -cvs -svn -bzr -darcs -always +#AurOnly +BottomUp +#RemoveMake +#SudoLoop +UseAsk +#CombinedUpgrade +CleanAfter +#UpgradeMenu +NewsOnUpgrade + +#LocalRepo +#Chroot +#Sign +#SignDb + +# +# Binary OPTIONS +# +[bin] +FileManager = lf +#MFlags = --skippgpcheck +Sudo = doas diff --git a/picom.conf b/picom.conf new file mode 100644 index 0000000..a98405c --- /dev/null +++ b/picom.conf @@ -0,0 +1,93 @@ +# Shadow +shadow = true; +shadow-radius = 7; +shadow-offset-x = -7; +shadow-offset-y = -7; +# shadow-opacity = 0.7; +# shadow-red = 0.0; +# shadow-green = 0.0; +# shadow-blue = 0.0; +shadow-exclude = [ "name = 'Notification'", "class_g = 'Conky'", "class_g ?= 'Notify-osd'", "class_g = 'Cairo-clock'" ]; +# shadow-exclude = "n:e:Notification"; +shadow-ignore-shaped = false; +inactive-opacity = 1.0; +active-opacity = 1.0; +frame-opacity = 1.0; +inactive-opacity-override = false; +# inactive-dim = 0.2; +# inactive-dim-fixed = true; +blur-background = false; +# blur-background-frame = true; +blur-kern = "3x3box" +# blur-kern = "5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1" +# blur-background-fixed = true; +blur-background-exclude = [ "window_type = 'dock'", "window_type = 'desktop'" ]; +# opacity-rule = [ "80:class_g = 'URxvt'" ]; + +# Fading +fading = false; +# fade-delta = 30; +fade-in-step = 0.03; +fade-out-step = 0.03; +# no-fading-openclose = true; +fade-exclude = [ ]; + +# Other +backend = "xrender" +mark-wmwin-focused = true; +mark-ovredir-focused = true; +# use-ewmh-active-win = true; +detect-rounded-corners = true; +detect-client-opacity = true; +refresh-rate = 0; +vsync = true; +dbe = false; +# sw-opti = true; +# unredir-if-possible = true; +# unredir-if-possible-delay = 5000; +# unredir-if-possible-exclude = [ ]; +focus-exclude = [ "class_g = 'Cairo-clock'" ]; +detect-transient = true; +detect-client-leader = true; +invert-color-include = [ ]; +# resize-damage = 1; + +# GLX backend +# glx-no-stencil = true; +glx-copy-from-front = "false"; +# glx-use-copysubbuffermesa = true; +# glx-no-rebind-pixmap = true; +use-damage = "true"; +# glx-use-gpushader4 = true; + +opacity-rule = [ "99:name *?= 'Screenshot'", +"99:class_g = 'Firefox'", +"99:name *?= 'Pale Moon'", +"99:name *?= 'QupZilla'", +"99:class_g = 'Midori'", +"99:class_g = 'Lazpaint'", +"99:class_g = 'Pinta'", +"99:class_g = 'Viewnior'", +"99:class_g = 'GIMP'", +"99:class_g = 'Darktable'", +"99:name *?= 'VLC'", +"99:name *?= 'Event'", +"99:name *?= 'Call'", +"99:name *?= 'Minitube'", +"99:name *?= 'Write'", +"99:name *?= 'VirtualBox'", +"99:name *?= 'Conky'", +"90:name *?= 'Panel'", +"90:name *?= 'Restart'", +"90:name *?= 'Page Info'", +"99:name *?= 'Image'", +"75:class_g = 'kwrite'", +"75:name *?= 'mousepad'"]; + +# Window type settings +wintypes: +{ + tooltip = { fade = true; shadow = false; opacity = 0.75; focus = true; }; + dock = { opacity = 1; shadow = false; }; +}; + diff --git a/pipewire/pipewire.conf b/pipewire/pipewire.conf new file mode 100644 index 0000000..ac5f9c6 --- /dev/null +++ b/pipewire/pipewire.conf @@ -0,0 +1,246 @@ +# Daemon config file for PipeWire version "0.3.34" # +# +# Copy and edit this file in /etc/pipewire for systemwide changes +# or in ~/.config/pipewire for local changes. + +context.properties = { + ## Configure properties in the system. + #library.name.system = support/libspa-support + #context.data-loop.library.name.system = support/libspa-support + #support.dbus = true + #link.max-buffers = 64 + link.max-buffers = 16 # version < 3 clients can't handle more + #mem.warn-mlock = false + #mem.allow-mlock = true + #mem.mlock-all = false + #clock.power-of-two-quantum = true + #log.level = 2 + + core.daemon = true # listening for socket connections + core.name = pipewire-0 # core name and socket name + + ## Properties for the DSP configuration. + #default.clock.rate = 48000 + #default.clock.allowed-rates = [ 48000 ] + #default.clock.quantum = 1024 + #default.clock.min-quantum = 32 + #default.clock.max-quantum = 8192 + #default.video.width = 640 + #default.video.height = 480 + #default.video.rate.num = 25 + #default.video.rate.denom = 1 + # + # These overrides are only applied when running in a vm. + vm.overrides = { + default.clock.min-quantum = 1024 + } +} + +context.spa-libs = { + # = + # + # Used to find spa factory names. It maps an spa factory name + # regular expression to a library name that should contain + # that factory. + # + audio.convert.* = audioconvert/libspa-audioconvert + api.alsa.* = alsa/libspa-alsa + api.v4l2.* = v4l2/libspa-v4l2 + api.libcamera.* = libcamera/libspa-libcamera + api.bluez5.* = bluez5/libspa-bluez5 + api.vulkan.* = vulkan/libspa-vulkan + api.jack.* = jack/libspa-jack + support.* = support/libspa-support + #videotestsrc = videotestsrc/libspa-videotestsrc + #audiotestsrc = audiotestsrc/libspa-audiotestsrc +} + +context.modules = [ + #{ name = + # [ args = { = ... } ] + # [ flags = [ [ ifexists ] [ nofail ] ] + #} + # + # Loads a module with the given parameters. + # If ifexists is given, the module is ignored when it is not found. + # If nofail is given, module initialization failures are ignored. + # + + # Uses RTKit to boost the data thread priority. + { name = libpipewire-module-rtkit + args = { + #nice.level = -11 + #rt.prio = 88 + #rt.time.soft = 2000000 + #rt.time.hard = 2000000 + } + flags = [ ifexists nofail ] + } + + # Set thread priorities without using RTKit. + #{ name = libpipewire-module-rt + # args = { + # nice.level = -11 + # rt.prio = 88 + # rt.time.soft = 2000000 + # rt.time.hard = 2000000 + # } + # flags = [ ifexists nofail ] + #} + + # The native communication protocol. + { name = libpipewire-module-protocol-native } + + # The profile module. Allows application to access profiler + # and performance data. It provides an interface that is used + # by pw-top and pw-profiler. + { name = libpipewire-module-profiler } + + # Allows applications to create metadata objects. It creates + # a factory for Metadata objects. + { name = libpipewire-module-metadata } + + # Creates a factory for making devices that run in the + # context of the PipeWire server. + { name = libpipewire-module-spa-device-factory } + + # Creates a factory for making nodes that run in the + # context of the PipeWire server. + { name = libpipewire-module-spa-node-factory } + + # Allows creating nodes that run in the context of the + # client. Is used by all clients that want to provide + # data to PipeWire. + { name = libpipewire-module-client-node } + + # Allows creating devices that run in the context of the + # client. Is used by the session manager. + { name = libpipewire-module-client-device } + + # The portal module monitors the PID of the portal process + # and tags connections with the same PID as portal + # connections. + { name = libpipewire-module-portal + flags = [ ifexists nofail ] + } + + # The access module can perform access checks and block + # new clients. + { name = libpipewire-module-access + args = { + # access.allowed to list an array of paths of allowed + # apps. + #access.allowed = [ + # /usr/bin/pipewire-media-session + #] + + # An array of rejected paths. + #access.rejected = [ ] + + # An array of paths with restricted access. + #access.restricted = [ ] + + # Anything not in the above lists gets assigned the + # access.force permission. + #access.force = flatpak + } + } + + # Makes a factory for wrapping nodes in an adapter with a + # converter and resampler. + { name = libpipewire-module-adapter } + + # Makes a factory for creating links between ports. + { name = libpipewire-module-link-factory } + + # Provides factories to make session manager objects. + { name = libpipewire-module-session-manager } +] + +context.objects = [ + #{ factory = + # [ args = { = ... } ] + # [ flags = [ [ nofail ] ] + #} + # + # Creates an object from a PipeWire factory with the given parameters. + # If nofail is given, errors are ignored (and no object is created). + # + #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } } + #{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = [ nofail ] } + #{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } } + #{ factory = spa-node-factory args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } } + #{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test } } + #{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } } + + # A default dummy driver. This handles nodes marked with the "node.always-driver" + # property when no other driver is currently active. JACK clients need this. + { factory = spa-node-factory + args = { + factory.name = support.node.driver + node.name = Dummy-Driver + node.group = pipewire.dummy + priority.driver = 20000 + } + } + { factory = spa-node-factory + args = { + factory.name = support.node.driver + node.name = Freewheel-Driver + priority.driver = 19000 + node.group = pipewire.freewheel + node.freewheel = true + } + } + # This creates a new Source node. It will have input ports + # that you can link, to provide audio for this source. + #{ factory = adapter + # args = { + # factory.name = support.null-audio-sink + # node.name = "my-mic" + # node.description = "Microphone" + # media.class = "Audio/Source/Virtual" + # audio.position = "FL,FR" + # } + #} + + # This creates a single PCM source device for the given + # alsa device path hw:0. You can change source to sink + # to make a sink in the same way. + #{ factory = adapter + # args = { + # factory.name = api.alsa.pcm.source + # node.name = "alsa-source" + # node.description = "PCM Source" + # media.class = "Audio/Source" + # api.alsa.path = "hw:0" + # #api.alsa.period-size = 1024 + # #api.alsa.headroom = 0 + # #api.alsa.disable-mmap = false + # #api.alsa.disable-batch = false + # #audio.format = "S16LE" + # #audio.rate = 48000 + # #audio.channels = 2 + # #audio.position = "FL,FR" + # } + #} +] + +context.exec = [ + #{ path = [ args = "" ] } + # + # Execute the given program with arguments. + # + # You can optionally start the session manager here, + # but it is better to start it as a systemd service. + # Run the session manager with -h for options. + # + { path = "/usr/bin/wireplumber" args = "-c wireplumber.conf" } + # + # You can optionally start the pulseaudio-server here as well + # but it is better to start it as a systemd service. + # It can be interesting to start another daemon here that listens + # on another address with the -a option (eg. -a tcp:4713). + # + { path = "/usr/bin/pipewire" args = "-c pipewire-pulse.conf" } +] diff --git a/pipewire/wireplumber.conf b/pipewire/wireplumber.conf new file mode 100644 index 0000000..3595858 --- /dev/null +++ b/pipewire/wireplumber.conf @@ -0,0 +1,90 @@ +# WirePlumber daemon context configuration # + +context.properties = { + ## Properties to configure the PipeWire context and some modules + + #application.name = WirePlumber + log.level = 2 + wireplumber.script-engine = lua-scripting + #wireplumber.export-core = true + + #mem.mlock-all = false + #support.dbus = true +} + +context.spa-libs = { + # = + # + # Used to find spa factory names. It maps an spa factory name + # regular expression to a library name that should contain + # that factory. + # + api.alsa.* = alsa/libspa-alsa + api.bluez5.* = bluez5/libspa-bluez5 + api.v4l2.* = v4l2/libspa-v4l2 + api.libcamera.* = libcamera/libspa-libcamera + audio.convert.* = audioconvert/libspa-audioconvert + support.* = support/libspa-support +} + +context.modules = [ + #{ name = + # [ args = { = ... } ] + # [ flags = [ [ ifexists ] [ nofail ] ] + #} + # + # PipeWire modules to load. + # If ifexists is given, the module is ignored when it is not found. + # If nofail is given, module initialization failures are ignored. + # + + # Uses RTKit to boost the data thread priority. + { name = libpipewire-module-rt + args = { + nice.level = -11 + #rt.prio = 88 + #rt.time.soft = -1 + #rt.time.hard = -1 + } + flags = [ ifexists nofail ] + } + + # The native communication protocol. + { name = libpipewire-module-protocol-native } + + # Allows creating nodes that run in the context of the + # client. Is used by all clients that want to provide + # data to PipeWire. + { name = libpipewire-module-client-node } + + # Allows creating devices that run in the context of the + # client. Is used by the session manager. + { name = libpipewire-module-client-device } + + # Makes a factory for wrapping nodes in an adapter with a + # converter and resampler. + { name = libpipewire-module-adapter } + + # Allows applications to create metadata objects. It creates + # a factory for Metadata objects. + { name = libpipewire-module-metadata } + + # Provides factories to make session manager objects. + { name = libpipewire-module-session-manager } +] + +wireplumber.components = [ + #{ name = , type = } + # + # WirePlumber components to load + # + + # The lua scripting engine + { name = libwireplumber-module-lua-scripting, type = module } + + # The lua configuration file(s) + # Other components are loaded from there + { name = main.lua, type = config/lua } + { name = policy.lua, type = config/lua } + { name = bluetooth.lua, type = config/lua } +] diff --git a/polybar/config b/polybar/config new file mode 100644 index 0000000..f7b924d --- /dev/null +++ b/polybar/config @@ -0,0 +1,615 @@ +;========================================================== +; +; +; ██████╗ ██████╗ ██╗ ██╗ ██╗██████╗ █████╗ ██████╗ +; ██╔══██╗██╔═══██╗██║ ╚██╗ ██╔╝██╔══██╗██╔══██╗██╔══██╗ +; ██████╔╝██║ ██║██║ ╚████╔╝ ██████╔╝███████║██████╔╝ +; ██╔═══╝ ██║ ██║██║ ╚██╔╝ ██╔══██╗██╔══██║██╔══██╗ +; ██║ ╚██████╔╝███████╗██║ ██████╔╝██║ ██║██║ ██║ +; ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ +; +; +; To learn more about how to configure Polybar +; go to https://github.com/jaagr/polybar +; +; The README contains alot of information +; +;========================================================== + +[colors] +;background = ${xrdb:color0:#222} +background = #000 +background-alt = #222 +;foreground = ${xrdb:color7:#222} +foreground = #fff +foreground-alt = #ddd +primary = #ffb52a +secondary = #9f9 +alert = #bd2c40 + +[bar/xmonad] +monitor = ${env:MONITOR:} +width = 100% +height = 24 +;offset-x = 1% +;offset-y = 1% +radius = 0.0 +fixed-center = false + +background = ${colors.background} +foreground = ${colors.foreground} + +line-size = 3 +line-color = #f00 + +border-size = 0 +border-color = #00000000 + +padding-left = 0 +padding-right = 0 + +module-margin-left = 1 +module-margin-right = 2 +font-0 = mononoki Nerd Font:pixelsize=10;1 +font-1 = JoyPixels:pixelsize=10;1 + +modules-left = ewmh +;i3 +modules-center = +modules-right = mpd packages pulse battery memory cpu wlan eth filesystem date powermenu +;xbacklight temperature +tray-position = right +tray-padding = 2 +;tray-background = #0063ff + +;wm-restack = bspwm +;wm-restack = i3 + +;override-redirect = true + +;scroll-up = bspwm-desknext +;scroll-down = bspwm-deskprev + +;scroll-up = i3wm-wsnext +;scroll-down = i3wm-wsprev + +cursor-click = pointer +cursor-scroll = ns-resize + +[bar/herbstluft] +monitor = ${env:MONITOR:} +width = 100% +height = 20 +;offset-x = 1% +;offset-y = 1% +radius = 0.0 +fixed-center = false +enable-ipc = true + +background = ${colors.background} +foreground = ${colors.foreground} + +line-size = 3 +line-color = #f00 + +border-size = 0 +border-color = #00000000 + +padding-left = 0 +padding-right = 0 + +module-margin-left = 1 +module-margin-right = 2 + +font-0 = mononoki Nerd Font:pixelsize=10;1 +font-1 = JoyPixels:pixelsize=10;1 + +modules-left = ewmh title +modules-center = +modules-right = packages mail filesystem pulseaudio xkeyboard mem cpu wlan eth battery date powermenu +;xbacklight temperature +tray-position = right +tray-padding = 2 +;tray-background = #0063ff + +;wm-restack = bspwm +;wm-restack = i3 + +;override-redirect = true + +;scroll-up = bspwm-desknext +;scroll-down = bspwm-deskprev + +;scroll-up = i3wm-wsnext +;scroll-down = i3wm-wsprev + +cursor-click = pointer +cursor-scroll = ns-resize + +[bar/bspwm] +monitor = ${env:MONITOR:} +width = 100% +height = 20 +;offset-x = 1% +;offset-y = 1% +radius = 0.0 +fixed-center = false + +background = ${colors.background} +foreground = ${colors.foreground} + +line-size = 3 +line-color = #f00 + +border-size = 0 +border-color = #00000000 + +padding-left = 0 +padding-right = 0 + +module-margin-left = 1 +module-margin-right = 2 + +font-0 = mononoki Nerd Font:pixelsize=10;1 +font-1 = JoyPixels:pixelsize=10;1 + +modules-left = bspwm +;i3 +modules-center = +modules-right = mail mpd filesystem pulseaudio alsa xkeyboard memory cpu wlan eth battery date powermenu +;xbacklight temperature +tray-position = right +tray-padding = 2 +;tray-background = #0063ff + +wm-restack = bspwm +;wm-restack = i3 + +;override-redirect = true + +scroll-up = bspwm-desknext +scroll-down = bspwm-deskprev + +;scroll-up = i3wm-wsnext +;scroll-down = i3wm-wsprev + +cursor-click = pointer +cursor-scroll = ns-resize + +[module/title] +type = internal/xwindow +label = %title% +label-maxlen = 45 + +[module/ewmh] +type = internal/xworkspaces + +; Only show workspaces defined on the same output as the bar +; +; Useful if you want to show monitor specific workspaces +; on different bars +; +; Default: false +pin-workspaces = false + +; Create click handler used to focus desktop +; Default: true +enable-click = true + +; Create scroll handlers used to cycle desktops +; Default: true +enable-scroll = false + +label-active = %name% +label-active-foreground = #ffffff +label-active-background = #222222 +label-active-padding = 2 + +label-occupied = %name% +label-occupied-foreground = #ffffff +label-occupied-background = #000000 +label-occupied-padding = 2 + +label-urgent = %name% +label-urgent-foreground = #ff0000 +label-urgent-background = #000000 +label-urgent-padding = 2 + +label-empty = %name% +label-empty-foreground = #7b7b7b +label-empty-backgorund = #000000 +label-empty-padding = 2 + +[module/packages] +type = custom/ipc +format-underline = #3399bb +hook-0 = pacpackages +initial = 1 + +[module/herbstluftwm] +type = custom/ipc +hook-0 = herbsttags +initial = 1 + +[module/mail] +type = custom/script +exec = mail +format-underline = #020 +interval = 10 + +[module/mem] +type = custom/script +exec = free -h | awk '/Mem/ {print $3}' +format-underline = #ff6c6b +interval = 5 + +[module/workspaces-xmonad] +type = custom/script +exec = tail -F /tmp/.xmonad-workspace-log +exec-if = [ -p /tmp/.xmonad-workspace-log ] +tail = true + +[module/title-xmonad] +type = custom/script +exec = tail -F /tmp/.xmonad-title-log +exec-if = [ -p /tmp/.xmonad-title-log ] +tail = true + +[module/xwindow] +type = internal/xwindow +label = %title:0:30:...% + +[module/xkeyboard] +type = internal/xkeyboard +blacklist-0 = num lock + +format-prefix = +format-prefix-foreground = ${colors.foreground-alt} +format-prefix-underline = ${colors.secondary} + +label-layout = %layout% +label-layout-underline = ${colors.secondary} + +label-indicator-padding = 2 +label-indicator-margin = 1 +label-indicator-background = ${colors.secondary} +label-indicator-underline = ${colors.secondary} + +[module/filesystem] +type = internal/fs +interval = 25 + +mount-0 = / + +label-mounted = %{F#0a81f5}%mountpoint%%{F-}: %percentage_used%% +label-unmounted = %mountpoint% not mounted +label-unmounted-foreground = ${colors.foreground-alt} + +format-underline = #51afef + +[module/bspwm] +type = internal/bspwm + +label-focused = %index% +label-focused-background = ${colors.background-alt} +label-focused-underline= ${colors.primary} +label-focused-padding = 2 + +label-occupied = %index% +label-occupied-padding = 2 + +label-urgent = %index%! +label-urgent-background = ${colors.alert} +label-urgent-padding = 2 + +label-empty = %index% +label-empty-foreground = ${colors.foreground-alt} +label-empty-padding = 2 + +; Separator in between workspaces +; label-separator = | + +[module/i3] +type = internal/i3 +format = +index-sort = true +wrapping-scroll = false + +; Only show workspaces on the same output as the bar +;pin-workspaces = true + +label-mode-padding = 2 +label-mode-foreground = #000 +label-mode-background = ${colors.primary} + +; focused = Active workspace on focused monitor +label-focused = %index% +label-focused-background = ${module/bspwm.label-focused-background} +label-focused-underline = ${module/bspwm.label-focused-underline} +label-focused-padding = ${module/bspwm.label-focused-padding} + +; unfocused = Inactive workspace on any monitor +label-unfocused = %index% +label-unfocused-padding = ${module/bspwm.label-occupied-padding} + +; visible = Active workspace on unfocused monitor +label-visible = %index% +label-visible-background = ${self.label-focused-background} +label-visible-underline = ${self.label-focused-underline} +label-visible-padding = ${self.label-focused-padding} + +; urgent = Workspace with urgency hint set +label-urgent = %index% +label-urgent-background = ${module/bspwm.label-urgent-background} +label-urgent-padding = ${module/bspwm.label-urgent-padding} + +; Separator in between workspaces +; label-separator = | + + +[module/mpd] +type = internal/mpd +format-online = + +icon-prev = < +icon-stop = s +icon-play = p +icon-pause = a +icon-next = > + +label-song-maxlen = 25 +label-song-ellipsis = true + +[module/xbacklight] +type = internal/xbacklight + +format =