Compare commits

..

46 Commits

Author SHA1 Message Date
33b541dbd8 update 2025-12-07 21:45:34 -08:00
a93761b042 update 2025-12-04 22:42:27 -08:00
a1ec1a54ba update 2025-12-03 22:49:24 -08:00
kyasuda
7b7fae9b91 update 2025-12-03 14:12:00 -08:00
d8a0e95bb5 bump versions 2025-12-02 18:49:10 -08:00
154f9e3ea6 update 2025-12-02 18:48:58 -08:00
4983623860 update mpv config 2025-12-02 18:48:51 -08:00
3628e70b72 update 2025-12-01 18:40:58 -08:00
31cfb8dd1c fux docs script 2025-12-01 18:09:32 -08:00
3fc0b32a9d update 2025-11-30 22:58:47 -08:00
4005e4650e move float center window rule down 2025-11-30 22:58:39 -08:00
3b87c06731 update rofi scripts 2025-11-30 22:57:56 -08:00
099d5e8ba6 update 2025-11-30 12:25:38 -08:00
21d6320cc1 update to new monitor 2025-11-30 12:25:25 -08:00
kyasuda
cb3641a9d9 send input directly to codecompanion inline command 2025-11-25 09:32:26 -08:00
b2cda94362 update window rules to new format 2025-11-20 12:26:07 -08:00
36d458c378 set sub-pos 2025-11-18 23:48:27 -08:00
5ec72352b8 update 2025-11-18 22:36:38 -08:00
7378fe9826 disable vrr on monitors 2025-11-16 20:54:53 -08:00
2006748e1d update keybindings 2025-11-14 10:24:20 -08:00
db9b3b65f1 update mpv config and remove osc.conf 2025-11-13 22:07:31 -08:00
a26255e83a update opacity rules and add keybind toggle 2025-11-12 11:30:48 -08:00
edec0e1b80 update 2025-11-12 11:27:51 -08:00
5e8bbf7f82 update 2025-10-24 23:21:58 -07:00
3f622c3298 update 2025-10-23 21:08:24 -07:00
918b5ccaec update keybindings 2025-10-23 21:08:07 -07:00
c36740a494 add codex 2025-10-22 22:34:09 -07:00
2688e2c488 add rofi-docs 2025-10-21 23:46:16 -07:00
db54fee30b fix stuff 2025-10-21 23:45:55 -07:00
c61bd04919 fix style 2025-10-21 23:08:39 -07:00
e5934fc174 fix border 2025-10-21 22:55:08 -07:00
cd370f70e6 add rmpv script 2025-10-20 18:23:44 -07:00
3bb7a5b0c7 remove lazy lock 2025-10-20 18:20:01 -07:00
kyasuda
2fc1896d89 update nvim 2025-10-20 09:36:39 -07:00
036e1b01dd remove cava 2025-10-16 22:21:12 -07:00
89732e90c5 update mpd config 2025-10-16 22:21:05 -07:00
7a1b814187 add center keybiding 2025-10-11 00:27:32 -07:00
9933e7a7f2 fix waybar 2025-10-11 00:27:21 -07:00
d8f8d4425b fix notification spacing when no notifications 2025-10-10 00:57:56 -07:00
7f963a9a6c fix waybar config and some other stuff 2025-10-09 23:56:49 -07:00
4c99d38f05 udpate 2025-10-03 14:52:42 -07:00
cebca89c32 udpate 2025-09-20 00:09:25 -07:00
kyasuda
356aac91db fix ruff config and linting 2025-09-19 11:42:29 -07:00
4589fc08b5 fix snacks indent 2025-09-14 01:29:17 -07:00
2c9749fa3d enable memory 2025-09-13 17:49:16 -07:00
102dc49fd0 update input.conf 2025-09-13 17:16:07 -07:00
39 changed files with 1261 additions and 771 deletions

View File

@@ -14,12 +14,34 @@
################ ################
# See https://wiki.hyprland.org/Configuring/Monitors/ # See https://wiki.hyprland.org/Configuring/Monitors/
monitor=DP-1,2560x1440@144,0x0,1, vrr, 1 # monitor=DP-1,2560x1440@144,0x0,1
monitor=DP-3,2560x1440@144,2560x0,1, vrr, 1 # monitor=DP-3,2560x1440@144,2560x0,1
# vrr 2 enables vrr if application is fullscreen
# vrr 3 enables vrr if application is fullscreen and video or game content
# monitor = DP-1, 3440x1440@240,0x0,1,vrr,3
monitorv2 {
output = DP-1
mode = 3440x1440@240
position = 0x0
scale = 1
vrr = 2
cm = srgb
# Optional HDR settings
# cm = hdr
# bitdepth = 10
# sdr_min_luminance = 0.005
# sdr_max_luminance = 200
# min_luminance = 0
# max_luminance = 1000
# max_avg_luminance = 200
# sdrbrightness = 1.2
# sdrsaturation = 0.98
}
source = ~/.config/hypr/keybindings.conf source = ~/.config/hypr/keybindings.conf
source = ~/.config/hypr/windowrules.conf
source = ~/.config/hypr/macchiato.conf source = ~/.config/hypr/macchiato.conf
# source = ~/.config/hypr/env.conf
# unscale XWayland # unscale XWayland
xwayland { xwayland {
force_zero_scaling = true force_zero_scaling = true
@@ -46,8 +68,8 @@ $notification_daemon = uwsm app -- swaync -c ~/.config/swaync/config.json
# Autostart necessary processes (like notifications daemons, status bars, etc.) # Autostart necessary processes (like notifications daemons, status bars, etc.)
# Or execute your favorite apps at launch like this: # Or execute your favorite apps at launch like this:
exec-once = uwsm app -sb -- hyprpm update -nn exec-once = uwsm app -sb -- hyprpm update -n
exec-once = uwsm app -sb -- hyprpm reload -nn exec-once = uwsm app -sb -- hyprpm reload -n
exec-once = $notification_daemon exec-once = $notification_daemon
exec-once = $terminal exec-once = $terminal
exec-once = uwsm app -sb -S both -t scope -- hyprpm update -nn exec-once = uwsm app -sb -S both -t scope -- hyprpm update -nn
@@ -55,7 +77,7 @@ exec-once = uwsm app -sb -S both -t scope -- hyprpm reload -nn
exec-once = uwsm app -sb -t service -- nm-applet exec-once = uwsm app -sb -t service -- nm-applet
exec-once = uwsm app -sb -t service -- waybar -c ~/.config/waybar/catppuccin-macchiato/config.jsonc -s ~/.config/waybar/catppuccin-macchiato/style.css exec-once = uwsm app -sb -t service -- waybar -c ~/.config/waybar/catppuccin-macchiato/config.jsonc -s ~/.config/waybar/catppuccin-macchiato/style.css
exec-once = uwsm app -sb -t service -- hyprsunset exec-once = uwsm app -sb -t service -- hyprsunset
exec-once = uwsm app -sb -t service -- polkit-kde-authentication-agent-1.desktop exec-once = uwsm app -sb -t service -- /usr/lib/polkit-kde-authentication-agent-1
exec-once = uwsm app -sb -t service -- variety exec-once = uwsm app -sb -t service -- variety
exec-once = ~/.local/bin/aria exec-once = ~/.local/bin/aria
# exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP # exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP
@@ -105,10 +127,10 @@ decoration {
rounding_power = 2 rounding_power = 2
# Change transparency of focused and unfocused windows # Change transparency of focused and unfocused windows
# active_opacity = 0.88 active_opacity = 0.88
active_opacity = 1.0 # active_opacity = 1.0
# inactive_opacity = 0.88 inactive_opacity = 0.88
inactive_opacity = 1.0 # inactive_opacity = 1.0
shadow { shadow {
enabled = true enabled = true
@@ -166,10 +188,6 @@ animations {
# uncomment all if you wish to use that. # uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0 # workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0 # workspace = f[1], gapsout:0, gapsin:0
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
@@ -212,7 +230,7 @@ input {
# https://wiki.hyprland.org/Configuring/Variables/#gestures # https://wiki.hyprland.org/Configuring/Variables/#gestures
gestures { gestures {
workspace_swipe = false # workspace_swipe = false
} }
# Example per-device config # Example per-device config
@@ -230,7 +248,8 @@ misc {
font_family = JetBrainsMono Nerd Font font_family = JetBrainsMono Nerd Font
} }
# {{{ WORKSPACES # {{{ WORKSPACES - HANDLED IN WAYBAR CONFIG
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# workspace = name:,monitor:DP-1 # workspace = name:,monitor:DP-1
# workspace = 2,monitor:DP-1,defaultName: # workspace = 2,monitor:DP-1,defaultName:
# workspace = 2,monitor:DP-1,persistent:false # workspace = 2,monitor:DP-1,persistent:false
@@ -244,65 +263,9 @@ misc {
# workspace = 10,monitor:DP-3,persistent:false # workspace = 10,monitor:DP-3,persistent:false
# }}} # }}}
# windowrule = match:class my-window, border_size 10
############################## debug {
### WINDOWS AND WORKSPACES ### disable_logs = true
############################## enable_stdout_logs = false
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
# Example windowrule v1
# windowrulev2 = float, class:com.mitchellh.ghostty
windowrule = float, class:discord
windowrule = float, class:mpv
windowrule = float, class:steam
windowrule = workspace 10 silent, class:discord
windowrule = workspace 9 silent, class:steam
# windowruv2 = opacity 0.88, class:.* fullscreen:0
windowrule = opacity 0.88, class:.* fullscreen:0
# windowruv2 = opacity 1, class:.* fullscreen:0
windowrule = opacity 1, class:mpv fullscreen:0
windowrule = opacity 1, class:anki fullscreen:0
windowrule = opacity 1, class:Thorium-browser title:(.*)asbplayer
windowrule = tile, class:Thorium-browser title:(.*)asbplayer
windowrule = opacity 1, class:^(remote-viewer)$
windowrule = opacity 1, class:com.obsproject.Studio
windowrule = opacity 1, title:(.*)(- YouTube(.*))
windowrule = opacity 1, class:zen, title:(.*)YouTube TV(.*)
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this.
windowrule = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland
windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
# https://github.com/hyprwm/Hyprland/issues/3835#issuecomment-2004448245
windowrule = suppressevent maximize, class:^(zen)$
exec-once = $HOME/.local/bin/bitwarden-nofloat.sh
# ENABLE_HDR_WSI=1 mpv --vo=gpu-next --target-colorspace-hint --gpu-api=vulkan --gpu-context=waylandvk "filename"
# {{{ Screen sharing workaround: https://wiki.hyprland.org/Useful-Utilities/Screen-Sharing/#xwayland
windowrule = opacity 0.0 override, class:^(xwaylandvideobridge)$
windowrule = noanim, class:^(xwaylandvideobridge)$
windowrule = noinitialfocus, class:^(xwaylandvideobridge)$
windowrule = maxsize 1 1, class:^(xwaylandvideobridge)$
windowrule = noblur, class:^(xwaylandvideobridge)$
windowrule = nofocus, class:^(xwaylandvideobridge)$
# }}}
plugin {
split-monitor-workspaces {
count = 5
keep_focused = 1
enable_notifications = 1
enable_persistent_workspaces = 1
} }
}

View File

@@ -20,7 +20,7 @@ bind = $mainMod, d, exec, $menu
bind = $mainMod, P, pseudo, # dwindle bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod, t, togglesplit, # dwindle bind = $mainMod, t, togglesplit, # dwindle
bind = $mainMod, f, fullscreen, bind = $mainMod, f, fullscreen,
bind = $mainMod, i, swapactiveworkspaces, DP-1 DP-3 bind = $mainMod, i, swapnext
# Move focus with mainMod + arrow keys # Move focus with mainMod + arrow keys
bind = $mainMod, h, movefocus, l bind = $mainMod, h, movefocus, l
@@ -32,6 +32,7 @@ bind = $mainMod SHIFT, j, movewindow, d
bind = $mainMod SHIFT, k, movewindow, u bind = $mainMod SHIFT, k, movewindow, u
bind = $mainMod SHIFT, h, movewindow, l bind = $mainMod SHIFT, h, movewindow, l
bind = $mainMod SHIFT, l, movewindow, r bind = $mainMod SHIFT, l, movewindow, r
bind = CTRL+SHIFT, c, centerwindow
# Move focus to next monitor # Move focus to next monitor
@@ -39,28 +40,28 @@ bind = CTRL+ALT, j, focusmonitor, r
bind = CTRL+ALT, k, focusmonitor, l bind = CTRL+ALT, k, focusmonitor, l
# Switch workspaces with mainMod + [0-9] # Switch workspaces with mainMod + [0-9]
bind = $mainMod, 1, split-workspace, 1 bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, split-workspace, 2 bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, split-workspace, 3 bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, split-workspace, 4 bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, split-workspace, 5 bind = $mainMod, 5, workspace, 5
bind = $mainMod, 6, split-workspace, 6 bind = $mainMod, 6, workspace, 6
bind = $mainMod, 7, split-workspace, 7 bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, split-workspace, 8 bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, split-workspace, 9 bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, split-workspace, 10 bind = $mainMod, 0, workspace, 10
# Move active window to a workspace with mainMod + SHIFT + [0-9] # Move active window to a workspace with mainMod + SHIFT + [0-9]
bind = $mainMod SHIFT, 1, split-movetoworkspacesilent, 1 bind = $mainMod SHIFT, 1, movetoworkspacesilent, 1
bind = $mainMod SHIFT, 2, split-movetoworkspacesilent, 2 bind = $mainMod SHIFT, 2, movetoworkspacesilent, 2
bind = $mainMod SHIFT, 3, split-movetoworkspacesilent, 3 bind = $mainMod SHIFT, 3, movetoworkspacesilent, 3
bind = $mainMod SHIFT, 4, split-movetoworkspacesilent, 4 bind = $mainMod SHIFT, 4, movetoworkspacesilent, 4
bind = $mainMod SHIFT, 5, split-movetoworkspacesilent, 5 bind = $mainMod SHIFT, 5, movetoworkspacesilent, 5
bind = $mainMod SHIFT, 6, split-movetoworkspacesilent, 6 bind = $mainMod SHIFT, 6, movetoworkspacesilent, 6
bind = $mainMod SHIFT, 7, split-movetoworkspacesilent, 7 bind = $mainMod SHIFT, 7, movetoworkspacesilent, 7
bind = $mainMod SHIFT, 8, split-movetoworkspacesilent, 8 bind = $mainMod SHIFT, 8, movetoworkspacesilent, 8
bind = $mainMod SHIFT, 9, split-movetoworkspacesilent, 9 bind = $mainMod SHIFT, 9, movetoworkspacesilent, 9
bind = $mainMod SHIFT, 0, split-movetoworkspacesilent, 10 bind = $mainMod SHIFT, 0, movetoworkspacesilent, 10
# Example special workspace (scratchpad) # Example special workspace (scratchpad)
bind = SUPER, S, togglespecialworkspace, magic bind = SUPER, S, togglespecialworkspace, magic
@@ -93,6 +94,7 @@ bindl = , XF86AudioPrev, exec, mpc prev
bind = $mainMod SHIFT, v, exec, uwsm app -sb -- rofi-rbw bind = $mainMod SHIFT, v, exec, uwsm app -sb -- rofi-rbw
bind = $mainMod, w, exec, rofi -show window -theme $HOME/.config/rofi/launchers/type-2/style-2.rasi -dpi 96 -theme-str 'window {width: 35%;}' bind = $mainMod, w, exec, rofi -show window -theme $HOME/.config/rofi/launchers/type-2/style-2.rasi -dpi 96 -theme-str 'window {width: 35%;}'
bind = $mainMod SHIFT, w, exec, $HOME/.config/rofi/scripts/rofi-wallpaper.sh bind = $mainMod SHIFT, w, exec, $HOME/.config/rofi/scripts/rofi-wallpaper.sh
bind = $mainMod SHIFT, d, exec, $HOME/.config/rofi/scripts/rofi-docs.sh
# ncmcppp # ncmcppp
bind = $mainMod, n, exec, uwsm app -sb -- ghostty --command=/usr/bin/ncmpcpp bind = $mainMod, n, exec, uwsm app -sb -- ghostty --command=/usr/bin/ncmpcpp
@@ -126,3 +128,16 @@ bind = $mainMod, z, exec, uwsm app -sb -- zen-browser
bind = $mainMod SHIFT, s, exec , rofi -show ssh -theme "$HOME/.config/rofi/launchers/type-2/style-2.rasi" -terminal -theme-str 'window{width: 25%;} listview {columns: 1; lines: 10;}' ghostty -ssh-command "ghostty --initial-command='TERM=kitty ssh {host}'" bind = $mainMod SHIFT, s, exec , rofi -show ssh -theme "$HOME/.config/rofi/launchers/type-2/style-2.rasi" -terminal -theme-str 'window{width: 25%;} listview {columns: 1; lines: 10;}' ghostty -ssh-command "ghostty --initial-command='TERM=kitty ssh {host}'"
# reload monitors
bind = $mainMod SHIFT, R, exec, hyprctl dispatch dpms off && sleep 1 && hyprctl dispatch dpms on
# Disable keybinds with one master keybind
# https://wiki.hypr.land/0.49.0/Configuring/Uncommon-tips--tricks/#disabling-keybinds-with-one-master-keybind
bind = $mainMod, code:117, submap, clean
submap = clean
bind = $mainMod, code:112, submap, reset
submap = reset
bind = SUPER, l, exec, hyprlock
bind = $mainMod SHIFT, a, exec, ~/.config/rofi/scripts/rofi-anki-script.sh

View File

@@ -7,7 +7,7 @@ pid_file "~/.config/mpd/pid"
state_file "~/.config/mpd/mpdstate" state_file "~/.config/mpd/mpdstate"
playlist_directory "~/.config/mpd/playlists" playlist_directory "~/.config/mpd/playlists"
# music_directory "~/Music" # music_directory "~/Music"
music_directory "/jellyfin/music" music_directory "/truenas/jellyfin/music"
# music_directory "nfs://102.168.5.77:/nandury/jellyfin/music" # music_directory "nfs://102.168.5.77:/nandury/jellyfin/music"
database { database {
plugin "simple" plugin "simple"

View File

@@ -241,9 +241,9 @@ ctrl+K script-binding mpvacious-secondary-sid-prev
ctrl+J script-binding mpvacious-secondary-sid-next ctrl+J script-binding mpvacious-secondary-sid-next
# }}} # }}}
# {{ animecards # {{{ animecards
ctrl+v script-binding animecards/update-anki-card ctrl+v script-binding animecards/update-anki-card
# }} # }}}
# {{{ mpv-youtube-queue # {{{ mpv-youtube-queue
ctrl+a script-binding mpv_youtube_queue/add_to_queue ctrl+a script-binding mpv_youtube_queue/add_to_queue
@@ -279,3 +279,7 @@ g-t script-binding select/select-track
g-v script-binding select/select-vid g-v script-binding select/select-vid
g-w script-binding select/select-watch-later g-w script-binding select/select-watch-later
# }}} # }}}
# {{{ IMMERSION TRACKER
ctrl+t script-binding immersion_tracker/immersion_tracking
# }}}

View File

@@ -1,124 +1,143 @@
profile=high-quality
user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36" user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"
cache=yes glsl-shaders="" # Disable heavy shaders for regular content
demuxer-max-bytes=500M # glsl-shaders="~~/shaders/ArtCNN_C4F32_DS.glsl"
demuxer-max-back-bytes=100M # glsl-shaders="~~/shaders/ArtCNN_C4F32.glsl"
cache-pause=no scale=spline36 # Faster than ewa_lanczos for high-res video when shaders are off
dither=fruit # Lighter dithering aimed at 8-bit or FRC panels
# --- Window & interface ---
ontop=yes ontop=yes
border=no
no-border
autofit=50% # Start at half of the screen to avoid oversized windows on UHD displays
osc=no
blend-subtitles=video # Keeps subtitles composited into the video plane
opengl-early-flush=no # Delay buffer flushes to reduce micro-stutter on some GPUs
# --- Subtitle defaults ---
sub-font="JetBrainsMono Nerd Font" sub-font="JetBrainsMono Nerd Font"
sub-font-size=45 sub-font-size=45
# osd-font="Fluent System Icons" sub-auto=fuzzy
border=no slang=en,eng
# geometry=50% subs-with-matching-audio=no
autofit=50% sub-fix-timing=yes
sub-ass-override=scale
sub-gauss=1.0
sub-gray=yes
sub-pos=100
# --- Audio chain ---
volume=75 volume=75
ao=pipewire,pulse
audio-spdif=ac3,dts-hd,truehd audio-spdif=ac3,dts-hd,truehd
# glsl-shaders="~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_VL.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_VL.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl" audio-stream-silence=yes # Keep the device primed to avoid startup pops
# glsl-shaders="~~/shaders/FSRCNNX.glsl:~~/shaders/FSR.glsl:~~/shaders/NVScaler.glsl:~~/shaders/CAS-scaled.glsl" audio-wait-open=0.1 # Shorten audio device warm-up for snappier playback
# glsl-shaders="~~/shaders/ArtCNN_C4F32_DS.glsl"
glsl-shaders="~~/shaders/ArtCNN_C4F32.glsl"
# Can fix stuttering in some cases, in other cases probably causes it. Try it if you experience stuttering.
opengl-early-flush=no
video-sync=display-resample
osc=no
no-border
# --- Networking & remote sources ---
ytdl-format=bestvideo+bestaudio/best ytdl-format=bestvideo+bestaudio/best
ytdl-raw-options=sub-langs=en.*,write-auto-subs= ytdl-raw-options=sub-langs=en.*,write-auto-subs=
ytdl-raw-options-append=sponsorblock-mark=all ytdl-raw-options-append=sponsorblock-mark=all
ytdl-raw-options-append=sponsorblock-remove=sponsor,selfpromo,interaction ytdl-raw-options-append=sponsorblock-remove=sponsor,selfpromo,interaction
# get subtitles for videos automatically # --- Video output & decoding ---
sub-auto=fuzzy
slang=en,eng
# profile=svp
profile=high-quality
blend-subtitles=video
# GPU OPTIONS
vo=gpu-next vo=gpu-next
hwdec=nvdec hwdec=nvdec
hwdec-codecs=all
gpu-api=vulkan gpu-api=vulkan
gpu-context=waylandvk
vulkan-queue-count=2
vulkan-async-compute=yes # Use independent compute queues for tone mapping/shaders
vulkan-async-transfer=yes # Parallelize frame uploads to free the graphics queue
vd-lavc-dr=yes # Direct rendering keeps frames resident on the GPU longer
vd-lavc-threads=0 # Let ffmpeg auto-pick the optimal thread count
video-sync=display-resample # Smoothly match video speed to the display refresh
# --- Scaling, interpolation, and dithering ---
scale=ewa_lanczossharp scale=ewa_lanczossharp
dscale=catmull_rom dscale=catmull_rom
cscale=ewa_lanczos cscale=ewa_lanczos
tscale=oversample tscale=oversample
interpolation=yes interpolation=yes
interpolation-preserve=no interpolation-preserve=no
interpolation-threshold=0.5 interpolation-threshold=0.5 # Only blend nearby frames to reduce SOE artifacts
sigmoid-upscaling=yes sigmoid-upscaling=yes # Protect highlights when upscaling SDR video
temporal-dither=yes temporal-dither=yes # Prefer temporal noise over spatial patterns on SDR panels
# Dithering presets reference:
# fruit: 8-Bit/8-Bit+FRC display # fruit -> 8-bit / 8-bit + FRC displays
# ordered: true 10-Bit/12-Bit display # ordered -> True 10-bit / 12-bit displays
# error-diffusion: high-end GPUs # error-diffusion -> High-end GPUs
dither=error-diffusion dither=error-diffusion
dither-depth=auto dither-depth=auto
error-diffusion=sierra-lite # uncomment if not 'error-diffusion' error-diffusion=sierra-lite # Balanced diffusion kernel for 8-bit panels
###### Antiring # --- Antiring controls ---
scale-antiring=0.5 scale-antiring=0.5
dscale-antiring=0.5 dscale-antiring=0.5
cscale-antiring=0.5 cscale-antiring=0.5
# laptop # --- Post-processing ---
# vo=gpu
# gpu-api=opengl
# gpu-context=wayland
# profile=opengl-hq
gpu-context=waylandvk
gpu-api=vulkan
vulkan-swap-mode=mailbox
swapchain-depth=2
vulkan-async-compute=no
vd-lavc-threads=0
opengl-pbo=yes
vd-lavc-film-grain=gpu
input-ipc-server=/tmp/mpvsocket
# ao=pule,pipewire
ao=pipewire,pulse
deband=yes deband=yes
deband-iterations=2 deband-iterations=2
deband-threshold=24 deband-threshold=24
deband-range=16 deband-range=16
deband-grain=4 deband-grain=4
subs-with-matching-audio=no # --- IPC & automation ---
sub-fix-timing=yes input-ipc-server=/tmp/mpvsocket # Allows external tools (e.g., SVP) to control mpv
sub-ass-override=scale
#Some settings fixing VOB/PGS subtitles (creating blur & changing yellow subs to gray)
sub-gauss=1.0
sub-gray=yes
###### High-quality screenshots # --- Screenshot workflow ---
screenshot-format=webp screenshot-format=webp
screenshot-webp-lossless=yes screenshot-webp-lossless=yes
screenshot-high-bit-depth=yes screenshot-high-bit-depth=yes
screenshot-sw=no screenshot-sw=no # Force GPU path so tone mapping stays consistent
screenshot-directory="/truenas/sudacode/pictures/mpv" screenshot-directory="/truenas/sudacode/pictures/mpv"
screenshot-template="%f-%wH.%wM.%wS.%wT-#%#00n" screenshot-template="%f-%wH.%wM.%wS.%wT-#%#00n"
# --- Session persistence ---
save-position-on-quit save-position-on-quit
watch-later-dir="~~/.watch-later" watch-later-dir="~~/.watch-later"
resume-playback=yes resume-playback=yes
save-watch-history save-watch-history
watch-history-path="~~/state/watch_history.jsonl" watch-history-path="~~/state/watch_history.jsonl"
# --- HDR/SDR hints ---
target-colorspace-hint=yes target-colorspace-hint=yes
# --- Caching & buffers ---
cache=yes
demuxer-max-bytes=1GiB # Buffer up to 1 GiB for high-bitrate remuxes
demuxer-max-back-bytes=200MiB # Keep recent data handy for quick reverse seeks
cache-secs=30
demuxer-readahead-secs=30
[anime]
profile-desc="Anime upscaling with ArtCNN"
glsl-shaders="~~/shaders/ArtCNN_C4F32.glsl"
scale=ewa_lanczossharp
dither=error-diffusion
deband=yes # Crucial for anime gradients
[movies]
profile-desc="Movies and TV shows"
profile-cond=width >= 1920 and filename:match("mkv$|mp4$")
glsl-shaders=""
scale=ewa_lanczos
target-peak=800
[hdr] [hdr]
target-colorspace-hint=yes target-colorspace-hint=yes
gpu-api=vulkan tone-mapping-param=0.5
gpu-context=waylandvk tone-mapping-max-boost=2.0
allow-delayed-peak-detect=yes
# For SDR content on HDR display (or vice versa)
icc-profile-auto=yes
[svp] [svp]
interpolation=no interpolation=no
input-ipc-server=/tmp/mpvsocket # Receives input from SVP input-ipc-server=/tmp/mpvsocket
hr-seek-framedrop=no # Fixes audio desync hr-seek-framedrop=no
resume-playback=no # Not compatible with SVP resume-playback=no
[Idle] [Idle]
profile-cond=p["idle-active"] profile-cond=p["idle-active"]
@@ -134,12 +153,22 @@ ytdl-raw-options-append=cookies=/truenas/sudacode/japanese/cookies.Japanese.txt
ytdl-raw-options-append=sponsorblock-mark=all ytdl-raw-options-append=sponsorblock-mark=all
ytdl-raw-options-append=sponsorblock-remove=sponsor,selfpromo,interaction ytdl-raw-options-append=sponsorblock-remove=sponsor,selfpromo,interaction
ytdl-format=bestvideo+bestaudio/best ytdl-format=bestvideo+bestaudio/best
# get subtitles for videos automatically
sub-auto=fuzzy sub-auto=fuzzy
slang=ja,jpn,ja.hi,ja.* alang=ja,jp,jpn,japanese,en,eng,english,English,enUS,en-US
alang=ja,jpn slang=ja,jp,jpn,japanese,en,eng,english,English,enUS,en-US
vlang=ja,jpn vlang=ja,jpn
sub-font="Noto Sans CJK JP" subs-with-matching-audio=yes
sub-border-size=1 sub-font="Noto Sans CJK JP Regular"
sub-shadow-color=0.0/0.0/0.0/0.50 glsl-shaders="~~/shaders/ArtCNN_C4F32.glsl"
sub-shadow-offset=2 scale=ewa_lanczossharp
dither=error-diffusion
deband=yes # Crucial for anime gradients
[anime-subs]
profile-cond=p["slang"] == "ja" or p["slang"] == "ja.hi"
sub-font="Noto Sans CJK JP Regular"
sub-font-size=42
sub-border-size=1.2
sub-shadow-color=0.0/0.0/0.0/0.6
sub-shadow-offset=3
sub-hinting=light

View File

@@ -1,233 +1,182 @@
# user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"
# Example mpv configuration file
#
# Warning:
#
# The commented example options usually do _not_ set the default values. Call
# mpv with --list-options to see the default values for most options. There is
# no builtin or example mpv.conf with all the defaults.
#
#
# Configuration files are read system-wide from /usr/local/etc/mpv.conf
# and per-user from ~~/mpv.conf, where per-user settings override
# system-wide settings, all of which are overridden by the command line.
#
# Configuration file settings and the command line options use the same
# underlying mechanisms. Most options can be put into the configuration file
# by dropping the preceding '--'. See the man page for a complete list of
# options.
#
# Lines starting with '#' are comments and are ignored.
#
# See the CONFIGURATION FILES section in the man page
# for a detailed description of the syntax.
#
# Profiles should be placed at the bottom of the configuration file to ensure
# that settings wanted as defaults are not restricted to specific profiles.
################## glsl-shaders=""
# video settings # scale=spline36 # Fast, high-quality fallback
################## dither=fruit # Lightweight dithering
# Start in fullscreen mode by default. # Window & interface
#fs=yes ontop=yes
border=no
no-border
autofit=50% # Reasonable default size
# force starting with centered window # Audio (macOS-specific)
# geometry=50%:50% volume=75
ao=coreaudio # Native macOS audio
# don't allow a new window to have a size larger than 90% of the screen size audio-stream-silence=no # FIXED: Prevents player behavior issues
#autofit-larger=90%x90% audio-wait-open=0.1 # Faster audio startup
# Do not close the window on exit.
#keep-open=yes
# Do not wait with showing the video window until it has loaded. (This will
# resize the window once video is loaded. Also always shows a window with
# audio.)
#force-window=immediate
# Disable the On Screen Controller (OSC).
# osc=no
# Keep the player window on top of all other windows.
# window=scale=1.0
# Specify high quality video rendering preset (for --vo=gpu only)
# Can cause performance problems with some drivers and GPUs.
# profile=gpu-hq
# Force video to lock on the display's refresh rate, and change video and audio
# speed to some degree to ensure synchronous playback - can cause problems
# with some drivers and desktop environments.
#video-sync=display-resample
# Enable hardware decoding if available. Often, this does not work with all
# video outputs, but should work well with default settings on most systems.
# If performance or energy usage is an issue, forcing the vdpau or vaapi VOs
# may or may not help.
# discourged by mpv devs and not likely to make significant difference
# hwdec=auto-copy
# hwdec-codecs=all
##################
# audio settings #
##################
# Specify default audio device. You can list devices with: --audio-device=help
# The option takes the device string (the stuff between the '...').
#audio-device=alsa/default
# Do not filter audio to keep pitch when changing playback speed.
#audio-pitch-correction=no
# Output 5.1 audio natively, and upmix/downmix audio with a different format.
#audio-channels=5.1
# Disable any automatic remix, _if_ the audio output accepts the audio format.
# of the currently played file. See caveats mentioned in the manpage.
# (The default is "auto-safe", see manpage.)
#audio-channels=auto
##################
# other settings #
##################
# Pretend to be a web browser. Might fix playback with some streaming sites,
# but also will break with shoutcast streams.
# user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"
user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"
# user-agent="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36"
# user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/37.0.2062.94 Chrome/37.0.2062.94 Safari/537.36"
# user-agent="Chromium/37.0.2062.94 Chrome/37.0.2062.94 Safari/537.36"
# cache settings
#
# Use a large seekable RAM cache even for local input.
cache=yes
#
# Use extra large RAM cache (needs cache=yes to make it useful).
demuxer-max-bytes=500M
demuxer-max-back-bytes=100M
#
# Disable the behavior that the player will pause if the cache goes below a
# certain fill size.
cache-pause=no
#
# Store cache payload on the hard disk instead of in RAM. (This may negatively
# impact performance unless used for slow input such as network.)
#cache-dir=~/.cache/
#cache-on-disk=yes
# Display English subtitles if available.
#slang=en
# Play Finnish audio if available, fall back to English otherwise.
#alang=fi,en
# Change subtitle encoding. For Arabic subtitles use 'cp1256'.
# If the file seems to be valid UTF-8, prefer UTF-8.
# (You can add '+' in front of the codepage to force it.)
#sub-codepage=cp1256
# You can also include other configuration files.
#include=/path/to/the/file/you/want/to/include
############
# Profiles #
############
# The options declared as part of profiles override global default settings,
# but only take effect when the profile is active.
# The following profile can be enabled on the command line with: --profile=eye-cancer
#[eye-cancer]
#sharpen=5
# Subtitle defaults
sub-font="JetBrainsMono Nerd Font" sub-font="JetBrainsMono Nerd Font"
sub-font-size=45 sub-font-size=45
# osd-font="Fluent System Icons"
border=no
geometry=50%
volume=50
# speed-step=0.05
# audio-spdif=ac3,eac3,dts-hd,truehd
# glsl-shaders="~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_VL.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_VL.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"
glsl-shaders="~~/shaders/ArtCNN_C4F16.glsl"
# glsl-shaders="~~/shaders/FSR.glsl"
# Can fix stuttering in some cases, in other cases probably causes it. Try it if you experience stuttering.
opengl-early-flush=no
video-sync=display-resample
osc=no
no-border
ytdl-raw-options=sub-langs=en.*,write-auto-subs=
ytdl-format=bestvideo+bestaudio/best
# get subtitles for videos automatically
sub-auto=fuzzy sub-auto=fuzzy
slang=en,eng slang=en,eng
subs-with-matching-audio=no
sub-fix-timing=yes
sub-ass-override=scale
sub-gauss=1.0
sub-gray=yes
sub-pos=90
# CATPPUCCIN MACHIATTO # Networking & streaming
# Main mpv options ytdl-format=bestvideo+bestaudio/best
ytdl-raw-options=sub-langs=en.*,write-auto-subs=
ytdl-raw-options-append=sponsorblock-mark=all
ytdl-raw-options-append=sponsorblock-remove=sponsor,selfpromo,interaction
# Stats & UI colors (Catppuccin Macchiato)
background-color='#24273a' background-color='#24273a'
osd-back-color='#181926' osd-back-color='#181926'
osd-border-color='#181926' osd-border-color='#181926'
osd-color='#cad3f5' osd-color='#cad3f5'
osd-shadow-color='#24273a' osd-shadow-color='#24273a'
# Stats script options
# Options are on separate lines for clarity
# Colors are in #BBGGRR format
script-opts-append=stats-border_color=30201e script-opts-append=stats-border_color=30201e
script-opts-append=stats-font_color=f5d3ca script-opts-append=stats-font_color=f5d3ca
script-opts-append=stats-plot_bg_border_color=f8bdb7 script-opts-append=stats-plot_bg_border_color=f8bdb7
script-opts-append=stats-plot_bg_color=30201e script-opts-append=stats-plot_bg_color=30201e
script-opts-append=stats-plot_color=f8bdb7 script-opts-append=stats-plot_color=f8bdb7
# profile=svp ##################
profile=gpu-hq # Video/Graphics #
# GPU OPTIONS ##################
vo=gpu-next vo=gpu-next
# hwdec=nvdec-copy hwdec=videotoolbox # macOS hardware decoding
hwdec=videotoolbox hwdec-codecs=all
scale=bicubic gpu-api=vulkan
dscale=bicubic gpu-context=macvk # macOS-specific Vulkan context
cscale=bicubic
# Vulkan optimizations (prevents crashes and memory leaks)
vulkan-queue-count=1 # FIXED: Prevents buffer overflow
vulkan-async-compute=no # FIXED: Improves stability
vulkan-async-transfer=no # FIXED: Reduces memory pressure
vulkan-swap-mode=fifo # Most compatible presentation mode
fbo-format=rgba8 # FIXED: Memory-safe format
# Video filtering & quality
vd-lavc-film-grain=cpu # FIXED: GPU grain not supported on macOS
vd-lavc-threads=0
vd-lavc-dr=yes # Keep frames on GPU
video-sync=display-resample # Smooth playback
# Scaling & interpolation
scale=ewa_lanczossharp
dscale=catmull_rom
cscale=ewa_lanczos
tscale=oversample tscale=oversample
interpolation=yes interpolation=yes
interpolation-preserve=no interpolation-threshold=0.5
sigmoid-upscaling=yes
temporal-dither=yes
input-ipc-server=/tmp/mpvsocket # High-quality dithering
# ao=pule,pipewire dither=error-diffusion
# ao=pipewire,pulse dither-depth=auto
ontop=yes error-diffusion=sierra-lite
# Antiring
scale-antiring=0.5
dscale-antiring=0.5
cscale-antiring=0.5
# Post-processing
deband=yes
deband-iterations=2
deband-threshold=24
deband-range=16
deband-grain=4
##################
# Screenshot #
##################
screenshot-format=webp
screenshot-webp-lossless=yes
screenshot-high-bit-depth=yes
screenshot-sw=no
screenshot-directory="/Volumes/sudacode/pictures/mpv"
screenshot-template="%f-%wH.%wM.%wS.%wT-#%#00n"
##################
# Session #
##################
ao=coreaudio
save-position-on-quit save-position-on-quit
watch-later-dir="~~.watch-later" watch-later-dir="~~/.watch-later"
resume-playback=yes resume-playback=yes
save-watch-history save-watch-history
watch-history-path="~~state/watch_history.jsonl" watch-history-path="~~/state/watch_history.jsonl"
vd-lavc-threads=0 input-ipc-server=/tmp/mpvsocket
gpu-api=vulkan
gpu-context=macvk
opengl-pbo=yes
##################
# Caching #
##################
cache=yes
demuxer-max-bytes=1GiB
demuxer-max-back-bytes=200MiB
cache-pause=no
cache-secs=30
demuxer-readahead-secs=30
############
# Profiles #
############
# Base high-quality preset (inherits above settings)
[base]
profile=gpu-hq
# Anime profile (ArtCNN is memory-heavy, use cautiously)
[anime]
profile-desc="Anime upscaling with ArtCNN"
profile-cond=filename:match("mkv$") and height <= 1080
glsl-shaders="~~/shaders/ArtCNN_C4F16.glsl" # Use F16 variant (lighter)
scale=ewa_lanczossharp
deband=yes
# Movies profile (no shaders, HDR support)
[movies]
profile-desc="Movies and TV shows"
profile-cond=width >= 1920 and filename:match("mkv$|mp4$")
glsl-shaders=""
scale=ewa_lanczos
target-peak=800
hdr-tone-mapping=bt.2390
# HDR profile
[hdr]
target-colorspace-hint=yes
tone-mapping-param=0.5
tone-mapping-max-boost=2.0
allow-delayed-peak-detect=yes
icc-profile-auto=yes
# SVP compatibility profile
[svp] [svp]
input-ipc-server=/tmp/mpvsocket # Receives input from SVP interpolation=no
hr-seek-framedrop=no # Fixes audio desync input-ipc-server=/tmp/mpvsocket
resume-playback=no # Not compatible with SVP hr-seek-framedrop=no
resume-playback=no
# Idle profile
[Idle] [Idle]
profile-cond=p["idle-active"] profile-cond=p["idle-active"]
profile-restore=copy-equal profile-restore=copy-equal
title=' ' title=' '
keepaspect=no keepaspect=no
# Japanese immersion profile
[immersion] [immersion]
cookies=yes cookies=yes
cookies-file=/Volumes/sudacode/japanese/cookies.Japanese.txt cookies-file=/Volumes/sudacode/japanese/cookies.Japanese.txt
@@ -236,8 +185,22 @@ ytdl-raw-options-append=cookies=/Volumes/sudacode/japanese/cookies.Japanese.txt
ytdl-raw-options-append=sponsorblock-mark=all ytdl-raw-options-append=sponsorblock-mark=all
ytdl-raw-options-append=sponsorblock-remove=sponsor ytdl-raw-options-append=sponsorblock-remove=sponsor
ytdl-format=bestvideo+bestaudio/best ytdl-format=bestvideo+bestaudio/best
# get subtitles for videos automatically
sub-auto=fuzzy sub-auto=fuzzy
slang=ja,jpn alang=ja,jp,jpn,japanese,en,eng,english,English,enUS,en-US
alang=ja,jpn slang=ja,jp,jpn,japanese,en,eng,english,English,enUS,en-US
vlang=ja,jpn vlang=ja,jpn
subs-with-matching-audio=yes
sub-font="Noto Sans CJK JP Regular"
glsl-shaders="~~/shaders/ArtCNN_C4F32.glsl"
scale=ewa_lanczossharp
dither=error-diffusion
deband=yes # Crucial for anime gradients
# Anime subtitles profile
[anime-subs]
profile-cond=p["slang"] == "ja" or p["slang"] == "ja.hi"
sub-font="Noto Sans CJK JP"
sub-font-size=42
sub-border-size=1.2
sub-shadow-color=0.0/0.0/0.0/0.6
sub-shadow-offset=3

View File

@@ -1,19 +0,0 @@
showwindowed=yes
showfullscreen=yes
scalewindowed=1
scalefullscreen=1
scaleforcedwindow=2
vidscale=yes
hidetimeout=1000
fadeduration=500
minmousemove=3
iamaprogrammer=yes
font='mpv-osd-symbols'
seekrangealpha=128
title='${media-title}'
showtitle=yes
visibility=auto
windowcontrols=auto
volumecontrol=yes
processvolume=yes
language=eng

View File

@@ -129,7 +129,7 @@ disable_gui_browse=no
# Play audio clip automatically in background # Play audio clip automatically in background
# after note creation (or note update) to ensure that the audio is correctly cut. # after note creation (or note update) to ensure that the audio is correctly cut.
preview_audio=yes preview_audio=no
# When selecting subtitle lines, print them on the screen. # When selecting subtitle lines, print them on the screen.
show_selected_text=yes show_selected_text=yes

View File

@@ -36,7 +36,7 @@ mpd_connection_timeout = 5
## Needed for tag editor and file operations to work. ## Needed for tag editor and file operations to work.
## ##
# mpd_music_dir = "~/Music" # mpd_music_dir = "~/Music"
mpd_music_dir = "/jellyfin/music" mpd_music_dir = "/truenas/jellyfin/music"
# #
#mpd_crossfade_time = 5 #mpd_crossfade_time = 5

View File

@@ -9,8 +9,3 @@ require("utils.telescope_extra").setup()
require("utils.functions.git_paste").setup({ telescope_key = "<leader>pg" }) require("utils.functions.git_paste").setup({ telescope_key = "<leader>pg" })
require("utils.treesitter.parsers.hyprlang") require("utils.treesitter.parsers.hyprlang")
require("utils.hyprland.lsp") require("utils.hyprland.lsp")
-- vim.notify = function(msg, level, opts)
-- print("Notification debug:", msg, level, vim.inspect(opts))
-- -- Call original notify
-- require("notify")(msg, level, opts)
-- end

View File

@@ -1,13 +1,12 @@
local map = vim.keymap.set local map = vim.keymap.set
local term = require("utils.terminal")
local map_from_table = require("utils.keymaps.converters.from_table").set_keybindings local map_from_table = require("utils.keymaps.converters.from_table").set_keybindings
local add_to_whichkey = require("utils.keymaps.converters.whichkey").addToWhichKey local add_to_whichkey = require("utils.keymaps.converters.whichkey").addToWhichKey
local telescope_paste_img = require("utils.telescope_extra").find_and_paste_image local telescope_paste_img = require("utils.telescope_extra").find_and_paste_image
local mkdir_under_cursor = require("utils.functions.mkdir_under_cursor").setup() local mkdir_under_cursor = require("utils.functions.mkdir_under_cursor").setup()
local term = require("utils.terminal")
local term_factory = term.term_factory local term_factory = term.term_factory
local term_toggle = term.term_toggle local term_toggle = term.term_toggle
local opts = { silent = true, noremap = true }
local nosilent = { silent = false, noremap = true } local nosilent = { silent = false, noremap = true }
-- Leader key -- Leader key
@@ -19,7 +18,7 @@ vim.g.maplocalleader = ","
--- @param command string The command to execute --- @param command string The command to execute
--- @param description string Description of the command --- @param description string Description of the command
--- @return nil --- @return nil
function create_custom_command(trigger, command, description) local create_custom_command = function(trigger, command, description)
vim.api.nvim_create_user_command(trigger, command, { desc = description }) vim.api.nvim_create_user_command(trigger, command, { desc = description })
end end
-- Custom commands -- Custom commands
@@ -164,7 +163,7 @@ local lsp_mappings = {
{ mode = "n", key = "<leader>gb", cmd = ":Gitsigns blame<CR>", group = "Git Blame" }, { mode = "n", key = "<leader>gb", cmd = ":Gitsigns blame<CR>", group = "Git Blame" },
{ mode = "n", key = "gi", cmd = ":Telescope lsp_implementations<CR>", group = "Telescope Implementations" }, { mode = "n", key = "gi", cmd = ":Telescope lsp_implementations<CR>", group = "Telescope Implementations" },
{ mode = "n", key = "gj", cmd = ":Telescope jumplist<CR>", group = "Telescope Jumplist" }, { mode = "n", key = "gj", cmd = ":Telescope jumplist<CR>", group = "Telescope Jumplist" },
{ mode = "n", key = "gr", cmd = ":Telescope lsp_references<CR>", goup = "LSP References" }, { mode = "n", key = "gr", cmd = ":Telescope lsp_references<CR>", group = "LSP References" },
{ mode = "n", key = "gs", cmd = vim.lsp.buf.signature_help }, { mode = "n", key = "gs", cmd = vim.lsp.buf.signature_help },
-- { mode = "n", key = "K", cmd = vim.lsp.buf.hover }, -- { mode = "n", key = "K", cmd = vim.lsp.buf.hover },
{ mode = "n", key = "<leader>ca", cmd = vim.lsp.buf.code_action, group = "Code" }, { mode = "n", key = "<leader>ca", cmd = vim.lsp.buf.code_action, group = "Code" },
@@ -198,7 +197,7 @@ local lsp_mappings = {
{ {
mode = "n", mode = "n",
key = "<leader>cDp", key = "<leader>cDp",
cmd = ":lua vim.diagnostic.goto_prev()<CR<CR>", cmd = ":lua vim.diagnostic.goto_prev()<CR>",
group = "Goto Previous Preview", group = "Goto Previous Preview",
}, },
{ mode = "n", key = "<leader>cl", cmd = ":lua vim.diagnostic.setloclist()<CR>", group = "Set Loclist" }, { mode = "n", key = "<leader>cl", cmd = ":lua vim.diagnostic.setloclist()<CR>", group = "Set Loclist" },
@@ -217,22 +216,44 @@ local lsp_mappings = {
-- {{{ Code Companion Mappings -- {{{ Code Companion Mappings
local code_companion_mappings = { local code_companion_mappings = {
{ mode = "n", key = "<leader>cp", cmd = ":vert Copilot panel<CR>", group = "Copilot Panel" }, { mode = "n", key = "<leader>cp", cmd = ":vert Copilot panel<CR>", group = "Copilot Panel" },
{ mode = "n", key = "<leader>oc", cmd = ":CodeCompanionChat Toggle<CR>", group = "Toggle Codecompanion" }, {
mode = "n",
key = "<leader>Cf",
cmd = function()
local chat = require("codecompanion").chat
chat({ window_opts = { height = 1.0, layout = "buffer" } })
end,
group = "Codecompanion Fullscreen",
},
{
mode = "n",
key = "<leader>Ch",
cmd = function()
local chat = require("codecompanion").chat
chat({ window_opts = { height = 0.24, layout = "horizontal", position = "bottom" } })
end,
group = "Codecompanion Horizontal Split",
},
{ mode = "n", key = "<leader>Cc", cmd = ":CodeCompanionChat Toggle<CR>", group = "Toggle Codecompanion" }, { mode = "n", key = "<leader>Cc", cmd = ":CodeCompanionChat Toggle<CR>", group = "Toggle Codecompanion" },
{ mode = "n", key = "<leader>oc", cmd = ":CodeCompanionChat Toggle<CR>", group = "Toggle Codecompanion" },
{ {
mode = "n", mode = "n",
key = "<leader>Ci", key = "<leader>Ci",
cmd = ":CodeCompanion #{buffer} ", cmd = function()
vim.api.nvim_feedkeys(":CodeCompanion #{buffer} ", "n", false)
end,
group = "Inline CodeCompanion", group = "Inline CodeCompanion",
opts = nosilent, opts = nosilent,
}, },
{ mode = "n", key = "<leader>CT", cmd = ":CodeCompanionChat Toggle<CR>", group = "CodeCompanion Toggle" }, { mode = "n", key = "<leader>Ct", cmd = ":CodeCompanionChat Toggle<CR>", group = "CodeCompanion Toggle" },
{ mode = "n", key = "<leader>Ca", cmd = ":CodeCompanionActions<CR>", group = "CodeCompanion Actions" }, { mode = "n", key = "<leader>CA", cmd = ":CodeCompanionActions<CR>", group = "CodeCompanion Actions" },
{ mode = "v", key = "<leader>Cc", cmd = ":CodeCompanionChat Add<CR>", group = "CodeCompanion Add" }, { mode = "v", key = "<leader>Ca", cmd = ":CodeCompanionChat Add<CR>", group = "CodeCompanion Add" },
{ {
mode = "v", mode = "v",
key = "<leader>Ci", key = "<leader>Ci",
cmd = ":CodeCompanion #{buffer} ", cmd = function()
vim.api.nvim_feedkeys(":CodeCompanion #{buffer} ", "n", false)
end,
group = "CodeCompanion Inline", group = "CodeCompanion Inline",
opts = nosilent, opts = nosilent,
}, },
@@ -249,7 +270,7 @@ local telescope_mappings = {
mode = "n", mode = "n",
key = "//", key = "//",
cmd = ":Telescope current_buffer_fuzzy_find previewer=false<CR>", cmd = ":Telescope current_buffer_fuzzy_find previewer=false<CR>",
"Current buffer fuzzy find", desc = "Current buffer fuzzy find",
}, },
{ {
mode = "n", mode = "n",
@@ -396,16 +417,16 @@ local telescope_mappings = {
-- {{{ File Explorer Mappings (i guess) -- {{{ File Explorer Mappings (i guess)
local file_explorer_mappings = { local file_explorer_mappings = {
{ mode = "n", key = "<leader>nt", cmd = ":NvimTreeToggle<CR>" }, { mode = "n", key = "<leader>nt", cmd = ":NvimTreeToggle<CR>" },
{ mode = "n", key = "<leader>nc", cmd = ":lua require('notify').dismiss()<CR>" }, { mode = "n", key = "<leader>nc", cmd = ":lua Snacks.notifier.hide()<CR>" },
{ mode = "n", key = "<leader>D", cmd = ":Dotenv .env<CR>", group = "Dotenv" }, { mode = "n", key = "<leader>nh", cmd = ":lua Snacks.notifier.show_history()<CR>" },
} }
-- }}} -- }}}
-- {{{ Misc Utilities Mappings -- {{{ Misc Utilities Mappings
local misc_utilities_mappings = { local misc_utilities_mappings = {
{ mode = "n", key = "<leader>x", cmd = "<cmd>!chmod +x %<CR>", group = "Make Executable" }, { mode = "n", key = "<leader>x", cmd = "<cmd>!chmod +x %<CR>", group = "Make Executable" },
{ mode = "n", key = "<leader>y", cmd = '"+', group = "System Yank" }, { mode = "n", key = "<leader>y", cmd = '"+y', group = "System Yank" },
{ mode = "v", key = "<leader>y", cmd = '"+', group = "System Yank" }, { mode = "v", key = "<leader>y", cmd = '"+y', group = "System Yank" },
{ mode = "n", key = "<leader>sc", cmd = ":nohls<CR>", group = "Search" }, { mode = "n", key = "<leader>sc", cmd = ":nohls<CR>", group = "Search" },
{ {
mode = "n", mode = "n",
@@ -415,6 +436,14 @@ local misc_utilities_mappings = {
end, end,
group = "mkdir under cursor", group = "mkdir under cursor",
}, },
{
mode = "v",
key = "<leader>m",
cmd = function()
mkdir_under_cursor()
end,
group = "mkdir selection",
},
} }
-- }}} -- }}}
@@ -521,12 +550,17 @@ local diffview_mappings = {
desc = "Refresh diffview", desc = "Refresh diffview",
group = "Git", group = "Git",
}, },
{
mode = "n",
key = "<leader>gg",
cmd = ":lua Snacks.lazygit()<CR>",
desc = "Open Lazygit",
},
} }
-- }}} -- }}}
--{{{ Custom Terminals --{{{ Custom Terminals
local programs_map = { local programs_map = {
gg = { cmd = "lazygit", display_name = "lazygit", direction = "tab", hidden = true },
op = { cmd = "ipython", display_name = "ipython", direction = "vertical", hidden = true }, op = { cmd = "ipython", display_name = "ipython", direction = "vertical", hidden = true },
oP = { oP = {
cmd = "ipython", cmd = "ipython",

View File

@@ -1,6 +1,6 @@
return { return {
"sontungexpt/better-diagnostic-virtual-text", "sontungexpt/better-diagnostic-virtual-text",
event = "LspAttach", -- event = "LspAttach",
enabled = true, enabled = true,
config = function() config = function()
local diagnostic = require("better-diagnostic-virtual-text") local diagnostic = require("better-diagnostic-virtual-text")
@@ -130,7 +130,7 @@ return {
down_arrow = "", down_arrow = "",
above = false, -- the virtual text will be displayed above the line above = false, -- the virtual text will be displayed above the line
}, },
priority = 2003, -- the priority of virtual text priority = 10000, -- the priority of virtual text
inline = true, inline = true,
}) })
end, end,

View File

@@ -28,7 +28,7 @@ return {
-- default = "claude-3.7-sonnet-thought", -- default = "claude-3.7-sonnet-thought",
-- default = "o3-mini", -- default = "o3-mini",
-- default = "gemini-2.0-flash-001", -- default = "gemini-2.0-flash-001",
default = "gpt-4.1", default = "claude-haiku-4.5",
-- default = "gpt-4o", -- default = "gpt-4o",
-- default = "o3-mini-2025-01-31", -- default = "o3-mini-2025-01-31",
-- choices = { -- choices = {
@@ -121,6 +121,13 @@ return {
}, },
}) })
end, end,
codex = function()
return require("codecompanion.adapters").extend("codex", {
defaults = {
auth_method = "chatgpt", -- "openai-api-key"|"codex-api-key"|"chatgpt"
},
})
end,
}, },
-- }}} -- }}}
}, },
@@ -221,6 +228,55 @@ return {
diff = { diff = {
enabled = true, enabled = true,
provider = "mini_diff", provider = "mini_diff",
provider_opts = {
-- Options for inline diff provider
inline = {
layout = "buffer", -- float|buffer - Where to display the diff
diff_signs = {
signs = {
text = "", -- Sign text for normal changes
reject = "", -- Sign text for rejected changes in super_diff
highlight_groups = {
addition = "DiagnosticOk",
deletion = "DiagnosticError",
modification = "DiagnosticWarn",
},
},
-- Super Diff options
icons = {
accepted = "",
rejected = "",
},
colors = {
accepted = "DiagnosticOk",
rejected = "DiagnosticError",
},
},
opts = {
context_lines = 3, -- Number of context lines in hunks
dim = 25, -- Background dim level for floating diff (0-100, [100 full transparent], only applies when layout = "float")
full_width_removed = true, -- Make removed lines span full width
show_keymap_hints = true, -- Show "gda: accept | gdr: reject" hints above diff
show_removed = true, -- Show removed lines as virtual text
},
},
-- Options for the split provider
split = {
close_chat_at = 240, -- Close an open chat buffer if the total columns of your display are less than...
layout = "vertical", -- vertical|horizontal split
opts = {
"internal",
"filler",
"closeoff",
"algorithm:histogram", -- https://adamj.eu/tech/2024/01/18/git-improve-diff-histogram/
"indent-heuristic", -- https://blog.k-nut.eu/better-git-diffs
"followwrap",
"linematch:120",
},
},
},
}, },
---Customize how tokens are displayed ---Customize how tokens are displayed
---@param tokens number ---@param tokens number
@@ -244,6 +300,13 @@ return {
}, },
}, },
}, },
memory = {
opts = {
chat = {
enabled = true,
},
},
},
}, },
init = function() init = function()
require("utils.codecompanion.fidget-spinner"):init() require("utils.codecompanion.fidget-spinner"):init()

View File

@@ -69,7 +69,6 @@ return {
end end
end, end,
}) })
vim.lsp.enable(lsp)
elseif lsp == "basedpyright" then elseif lsp == "basedpyright" then
vim.lsp.config(lsp, { vim.lsp.config(lsp, {
capabilities = capabilities, capabilities = capabilities,
@@ -97,7 +96,6 @@ return {
}, },
}, },
}) })
vim.lsp.enable(lsp)
elseif lsp == "ruff" then elseif lsp == "ruff" then
vim.api.nvim_create_autocmd("LspAttach", { vim.api.nvim_create_autocmd("LspAttach", {
group = vim.api.nvim_create_augroup("lsp_attach_disable_ruff_hover", { clear = true }), group = vim.api.nvim_create_augroup("lsp_attach_disable_ruff_hover", { clear = true }),
@@ -114,15 +112,12 @@ return {
desc = "LSP: Disable hover capability from Ruff", desc = "LSP: Disable hover capability from Ruff",
}) })
vim.lsp.config(lsp, { vim.lsp.config(lsp, {
capabilities = capabilities,
init_options = {
settings = { settings = {
configuration = vim.fn.stdpath("config") .. "lua/utils/ruff.toml", configuration = vim.fn.stdpath("config") .. "/lua/utils/ruff.toml",
}, logLevel = "info",
}, },
}) })
end end
vim.lsp.config(lsp, { capabilities = capabilities })
vim.lsp.enable(lsp) vim.lsp.enable(lsp)
end end
end, end,

View File

@@ -25,22 +25,13 @@ return {
local orig_try_lint = lint.try_lint local orig_try_lint = lint.try_lint
lint.try_lint = function(...) lint.try_lint = function(...)
local bufnr = vim.api.nvim_get_current_buf() local opts = select(2, ...)
local buftype = vim.api.nvim_get_option_value("buftype", { buf = bufnr }) local bufnr = (type(opts) == "table" and opts.bufnr) or vim.api.nvim_get_current_buf()
if vim.api.nvim_get_option_value("buftype", { buf = bufnr }) ~= "" then
-- Skip linting for non-file buffers (like hover docs)
if buftype ~= "" then
return return
end end
return orig_try_lint(...) return orig_try_lint(...)
end end
vim.api.nvim_create_autocmd({ "BufEnter", "BufWritePost", "InsertLeave" }, {
callback = function()
lint.try_lint()
end,
})
end, end,
event = { "BufReadPre", "BufNewFile" }, event = { "BufReadPre", "BufNewFile" },
} }

View File

@@ -10,11 +10,12 @@ return {
bigfile = { enabled = true }, bigfile = { enabled = true },
dashboard = { enabled = true }, dashboard = { enabled = true },
explorer = { enabled = true }, explorer = { enabled = true },
indent = {
indent = { indent = {
priority = 1, priority = 1,
enabled = true, -- enable indent guides enabled = true, -- enable indent guides
char = "", char = "",
only_scope = false, -- only show indent guides of the scope only_scope = true, -- only show indent guides of the scope
only_current = false, -- only show indent guides in the current window only_current = false, -- only show indent guides in the current window
-- hl = "SnacksIndent", ---@type string|string[] hl groups for indent guides -- hl = "SnacksIndent", ---@type string|string[] hl groups for indent guides
-- can be a list of hl groups to cycle through -- can be a list of hl groups to cycle through
@@ -28,6 +29,7 @@ return {
"SnacksIndent7", "SnacksIndent7",
"SnacksIndent8", "SnacksIndent8",
}, },
},
animate = { animate = {
-- enabled = vim.fn.has("nvim-0.10") == 1, -- enabled = vim.fn.has("nvim-0.10") == 1,
enabled = false, enabled = false,
@@ -49,41 +51,6 @@ return {
icon_pos = "left", icon_pos = "left",
prompt_pos = "title", prompt_pos = "title",
win = { style = "input" }, win = { style = "input" },
expand = true,
backdrop = true,
position = "float",
border = "rounded",
title_pos = "center",
height = 1,
width = 60,
relative = "editor",
noautocmd = true,
row = 2,
-- relative = "cursor",
-- row = -3,
-- col = 0,
wo = {
winhighlight = "NormalFloat:SnacksInputNormal,FloatBorder:SnacksInputBorder,FloatTitle:SnacksInputTitle",
cursorline = false,
},
bo = {
filetype = "snacks_input",
buftype = "prompt",
},
--- buffer local variables
b = {
completion = false, -- disable blink completions in input
},
keys = {
n_esc = { "<esc>", { "cmp_close", "cancel" }, mode = "n", expr = true },
i_esc = { "<esc>", { "cmp_close", "stopinsert" }, mode = "i", expr = true },
i_cr = { "<cr>", { "cmp_accept", "confirm" }, mode = { "i", "n" }, expr = true },
i_tab = { "<tab>", { "cmp_select_next", "cmp" }, mode = "i", expr = true },
i_ctrl_w = { "<c-w>", "<c-s-w>", mode = "i", expr = true },
i_up = { "<up>", { "hist_up" }, mode = { "i", "n" } },
i_down = { "<down>", { "hist_down" }, mode = { "i", "n" } },
q = "cancel",
},
}, },
lazygit = { enabled = true }, lazygit = { enabled = true },
picker = { enabled = true }, picker = { enabled = true },
@@ -163,5 +130,43 @@ return {
}, },
}, },
win = { enabled = true }, win = { enabled = true },
styles = {
input = {
backdrop = false,
position = "float",
border = "rounded",
title_pos = "center",
height = 1,
width = 60,
relative = "editor",
noautocmd = true,
row = 2,
-- relative = "cursor",
-- row = -3,
-- col = 0,
wo = {
winhighlight = "NormalFloat:SnacksInputNormal,FloatBorder:SnacksInputBorder,FloatTitle:SnacksInputTitle",
cursorline = false,
},
bo = {
filetype = "snacks_input",
buftype = "prompt",
},
--- buffer local variables
b = {
completion = false, -- disable blink completions in input
},
keys = {
n_esc = { "<esc>", { "cmp_close", "cancel" }, mode = "n", expr = true },
i_esc = { "<esc>", { "cmp_close", "stopinsert" }, mode = "i", expr = true },
i_cr = { "<cr>", { "cmp_accept", "confirm" }, mode = { "i", "n" }, expr = true },
i_tab = { "<tab>", { "cmp_select_next", "cmp" }, mode = "i", expr = true },
i_ctrl_w = { "<c-w>", "<c-s-w>", mode = "i", expr = true },
i_up = { "<up>", { "hist_up" }, mode = { "i", "n" } },
i_down = { "<down>", { "hist_down" }, mode = { "i", "n" } },
q = "cancel",
},
},
},
}, },
} }

View File

@@ -36,15 +36,14 @@ return {
dynamic_preview_title = true, dynamic_preview_title = true,
treesitter = true, treesitter = true,
}, },
mappings = { -- mappings = {
i = { -- i = {
-- map actions.which_key to <C-h> (default: <C-/>) -- -- map actions.which_key to <C-h> (default: <C-/>)
-- actions.which_key shows the mappings for your picker, -- -- actions.which_key shows the mappings for your picker,
-- e.g. git_{create, delete, ...}_branch for the git_branches picker -- -- e.g. git_{create, delete, ...}_branch for the git_branches picker
["<C-h>"] = "which_key", -- ["<C-/>"] = "which_key",
["<C-u"] = false, -- },
}, -- },
},
file_ignore_patterns = { "^node_modules/", "^env/", "^__pycache__/" }, file_ignore_patterns = { "^node_modules/", "^env/", "^__pycache__/" },
}, },
pickers = { pickers = {

View File

@@ -2,8 +2,20 @@ local M = {}
vim.notify = require("notify") vim.notify = require("notify")
function M.mkdir_under_cursor() function M.mkdir_under_cursor()
-- Get the word under the cursor local word
local word = vim.fn.expand("<cWORD>")
-- Check if in visual mode
if vim.fn.mode():match("[vV]") then
-- Get visual selection
local start_pos = vim.fn.getpos("'<")
local end_pos = vim.fn.getpos("'>")
local line = vim.fn.getline(start_pos[2])
word = line:sub(start_pos[3], end_pos[3])
else
-- Get word under cursor
word = vim.fn.expand("<cWORD>")
end
-- Remove quotes if present -- Remove quotes if present
word = word:gsub("^[\"']", ""):gsub("[\"']$", "") word = word:gsub("^[\"']", ""):gsub("[\"']$", "")
-- Check if directory exists -- Check if directory exists

View File

@@ -35,6 +35,8 @@ indent-width = 4
# Assume Python 3.9 # Assume Python 3.9
target-version = "py39" target-version = "py39"
respect-gitignore = true
[lint] [lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. # Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or # Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
@@ -57,7 +59,7 @@ convention = "numpy" # Accepts: "google", "numpy", or "pep257".
quote-style = "double" quote-style = "double"
# Like Black, indent with spaces, rather than tabs. # Like Black, indent with spaces, rather than tabs.
indent-style = "spaces" indent-style = "space"
# Like Black, respect magic trailing commas. # Like Black, respect magic trailing commas.
skip-magic-trailing-comma = false skip-magic-trailing-comma = false
@@ -78,5 +80,3 @@ docstring-code-format = true
# This only has an effect when the `docstring-code-format` setting is # This only has an effect when the `docstring-code-format` setting is
# enabled. # enabled.
docstring-code-line-length = "dynamic" docstring-code-line-length = "dynamic"
respect-gitignore = true

View File

@@ -1,5 +1,6 @@
local telescope = require("telescope") local telescope = require("telescope")
local telescopeConfig = require("telescope.config") local telescopeConfig = require("telescope.config")
local actions = require("telescope.actions")
local M = {} local M = {}
@@ -36,56 +37,13 @@ function M.setup()
-- I don't want to search in the `.git` directory. -- I don't want to search in the `.git` directory.
table.insert(vimgrep_arguments, "--glob") table.insert(vimgrep_arguments, "--glob")
table.insert(vimgrep_arguments, "!**/.git/*") table.insert(vimgrep_arguments, "!**/.git/*")
telescope.setup({ vim.tbl_deep_extend("force", telescopeConfig.values, {
defaults = {
-- `hidden = true` is not supported in text grep commands.
vimgrep_arguments = vimgrep_arguments,
},
pickers = {
find_files = {
-- `hidden = true` will still show the inside of `.git/` as it's not `.gitignore`d.
find_command = { "rg", "--files", "--hidden", "--glob", "!**/.git/*" },
mappings = { mappings = {
n = { i = {
["cd"] = function(prompt_bufnr) ["<C-h>"] = actions.results_scrolling_left,
local selection = require("telescope.actions.state").get_selected_entry() ["<C-l>"] = actions.results_scrolling_right,
local dir = vim.fn.fnamemodify(selection.path, ":p:h")
require("telescope.actions").close(prompt_bufnr)
-- Depending on what you want put `cd`, `lcd`, `tcd`
vim.cmd(string.format("silent lcd %s", dir))
end,
}, },
}, },
},
},
preview = {
-- show images in telescope using kitty
mime_hook = function(filepath, bufnr, opts)
local is_image = function(filepath)
local image_extensions = { "png", "jpg" } -- Supported image formats
local split_path = vim.split(filepath:lower(), ".", { plain = true })
local extension = split_path[#split_path]
return vim.tbl_contains(image_extensions, extension)
end
if is_image(filepath) then
local term = vim.api.nvim_open_term(bufnr, {})
local function send_output(_, data, _)
for _, d in ipairs(data) do
vim.api.nvim_chan_send(term, d .. "\r\n")
end
end
vim.fn.jobstart({
"kitty +icat " .. filepath, -- Terminal image viewer command
}, { on_stdout = send_output, stdout_buffered = true, pty = true })
else
require("telescope.previewers.utils").set_preview_message(
bufnr,
opts.winid,
"Binary cannot be previewed"
)
end
end,
},
}) })
end end

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "https://opencode.ai/config.json", "$schema": "https://opencode.ai/config.json",
"theme": "catppuccin", "theme": "catppuccin",
"model": "github-copilot/gpt-4.1", "model": "github-copilot/gpt-5.1",
"provider": { "provider": {
"openai": { "openai": {
"models": { "models": {
@@ -19,7 +19,7 @@
"agent": { "agent": {
"build": { "build": {
"mode": "primary", "mode": "primary",
"model": "github-copilot/gpt-4.1", "model": "github-copilot/gpt-5.1",
"tools": { "tools": {
"write": true, "write": true,
"edit": true, "edit": true,
@@ -28,7 +28,7 @@
}, },
"plan": { "plan": {
"mode": "primary", "mode": "primary",
"model": "github-copilot/gpt-4.1", "model": "github-copilot/gpt-5.1-codex",
"tools": { "tools": {
"write": false, "write": false,
"edit": false, "edit": false,
@@ -38,7 +38,7 @@
"code-reviewer": { "code-reviewer": {
"description": "Reviews code for best practices and potential issues", "description": "Reviews code for best practices and potential issues",
"mode": "subagent", "mode": "subagent",
"model": "github-copilot/gpt-4.1", "model": "github-copilot/gpt-5.1",
"prompt": "You are a code reviewer. Focus on security, performance, and maintainability.", "prompt": "You are a code reviewer. Focus on security, performance, and maintainability.",
"tools": { "tools": {
"write": false, "write": false,

View File

@@ -10,8 +10,10 @@
"Cloudflare - https://dash.cloudflare.com/", "Cloudflare - https://dash.cloudflare.com/",
"CoinMarketCap - https://coinmarketcap.com/", "CoinMarketCap - https://coinmarketcap.com/",
"Deemix - http://pve-main:3358", "Deemix - http://pve-main:3358",
"Ephemera - https://ephemera.suda.codes",
"F1TV - https://f1tv.suda.codes", "F1TV - https://f1tv.suda.codes",
"Fidelity - https://login.fidelity.com/", "Fidelity - https://login.fidelity.com/",
"Ghstats - http://oracle-vm:3340",
"Gitea - https://gitea.suda.codes", "Gitea - https://gitea.suda.codes",
"Github - https://github.com", "Github - https://github.com",
"Ghostfolio - http://pve-main:3334", "Ghostfolio - http://pve-main:3334",
@@ -23,7 +25,7 @@
"Jellyfin (Vue) - http://pve-main:8098", "Jellyfin (Vue) - http://pve-main:8098",
"Karakeep - https://karakeep.suda.codes", "Karakeep - https://karakeep.suda.codes",
"Komodo - https://komodo.suda.codes", "Komodo - https://komodo.suda.codes",
"Komga - http://oracle-vm:3332", "Komga - http://pve-main:3332",
"Lidarr - http://pve-main:3357", "Lidarr - http://pve-main:3357",
"MeTube - https://metube.suda.codes", "MeTube - https://metube.suda.codes",
"Navidrome - https://navidrome.suda.codes", "Navidrome - https://navidrome.suda.codes",
@@ -32,7 +34,9 @@
"Pihole - https://pihole.suda.codes/admin", "Pihole - https://pihole.suda.codes/admin",
"Pihole2 - https://pihole2.suda.codes/admin", "Pihole2 - https://pihole2.suda.codes/admin",
"Proxmox - https://thebox.unicorn-ilish.ts.net", "Proxmox - https://thebox.unicorn-ilish.ts.net",
"qBittorrent - https://qbit.suda.codes", "qBittorrent - https://qbittorrent.suda.codes",
"qui - https://qui.suda.codes",
"Plausible - https://plausible.sudacode.com",
"Paperless - https://paperless.suda.codes", "Paperless - https://paperless.suda.codes",
"Prometheus - http://prometheus:9090", "Prometheus - http://prometheus:9090",
"Radarr - https://radarr.suda.codes", "Radarr - https://radarr.suda.codes",
@@ -41,13 +45,16 @@
"Sabnzbd - https://sabnzbd.suda.codes", "Sabnzbd - https://sabnzbd.suda.codes",
"Sonarr - https://sonarr.suda.codes", "Sonarr - https://sonarr.suda.codes",
"Sonarr Anime - http://pve-main:6969", "Sonarr Anime - http://pve-main:6969",
"Speedtest Tracker - http://pve-main:8765",
"Sudacode - https://sudacode.com", "Sudacode - https://sudacode.com",
"Suwayomi - https://suwayomi.suda.codes",
"Tailscale - https://login.tailscale.com/admin/machines", "Tailscale - https://login.tailscale.com/admin/machines",
"Tranga - http://pve-main:9555", "Tranga - http://pve-main:9555",
"Truenas - https://truenas.unicorn-ilish.ts.net", "Truenas - https://truenas.unicorn-ilish.ts.net",
"Tdarr - https://tdarr.suda.codes", "Tdarr - https://tdarr.suda.codes",
"Tubearchivist - https://tubearchivist.suda.codes",
"T3Chat - https://t3.chat", "T3Chat - https://t3.chat",
"Umami - https://umami.sudacode.com", "Unifi - https://unifi.suda.codes",
"Vaultwarden - https://vault.suda.codes", "Vaultwarden - https://vault.suda.codes",
"Wallabag - https://wallabag.suda.codes", "Wallabag - https://wallabag.suda.codes",
"Youtube - https://youtube.com", "Youtube - https://youtube.com",

View File

@@ -37,7 +37,7 @@ window {
location: center; location: center;
anchor: center; anchor: center;
fullscreen: false; fullscreen: false;
width: 45%; width: 37%;
x-offset: 0px; x-offset: 0px;
y-offset: 0px; y-offset: 0px;

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env bash
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/rofi-menu-helpers.sh"
BROWSER=/usr/bin/zen-browser
DOC_GROUPS=(
"Arch Linux (btw)|ARCH"
"Hyprland|HYPRLAND"
)
ARCH=(
"Archlinux Wiki|https://wiki.archlinux.org/title/Main_page"
)
HYPRLAND=(
"Hyprland Docs|https://wiki.hypr.land/"
"Hyprland Window Rules|https://wiki.hypr.land/Configuring/Window-Rules/"
)
select_group() {
rofi_select_label_value "Select Documentation Group" DOC_GROUPS
}
select_url() {
local urls_array="$1"
rofi_select_label_value "Select Documentation" "$urls_array" "Back"
}
main() {
while true; do
group_key="$(select_group)" || exit 0
case "$group_key" in
ARCH)
urls_ref=ARCH
;;
HYPRLAND)
urls_ref=HYPRLAND
;;
*)
exit 0
;;
esac
selection="$(select_url "$urls_ref")" || exit 0
if [[ "$selection" == "Back" ]]; then
continue
fi
$BROWSER "$selection" &>/dev/null &
exit 0
done
}
main

View File

@@ -0,0 +1,68 @@
#!/usr/bin/env bash
# Lightweight helpers to build rofi menus with label/value pairs.
# Intended to be sourced from other scripts.
# Allow callers to override theme/args without touching code.
: "${ROFI_THEME:=$HOME/.config/rofi/launchers/type-2/style-2.rasi}"
: "${ROFI_THEME_STR:="window {width: 25%;} listview {columns: 1; lines: 10;}"}"
: "${ROFI_DMENU_ARGS:=-i -l 5}"
# rofi_menu prompt option...
# Prints the selected option to stdout and propagates the rofi exit code
# (1 when the user cancels).
rofi_menu() {
local prompt="$1"
shift
local -a options=("$@")
local selection
selection="$(printf "%s\n" "${options[@]}" | rofi -dmenu $ROFI_DMENU_ARGS \
${ROFI_THEME:+-theme "$ROFI_THEME"} \
${ROFI_THEME_STR:+-theme-str "$ROFI_THEME_STR"} \
-p "$prompt")"
local status=$?
[[ $status -ne 0 ]] && return "$status"
printf "%s\n" "$selection"
}
# rofi_select_label_value prompt array_name [back_label]
# array_name should contain entries shaped as "Label|Value".
# Prints the mapped value (or the back label when chosen). Returns 1 on cancel.
rofi_select_label_value() {
local prompt="$1"
local array_name="$2"
local back_label="${3:-}"
# Access caller's array by name
local -n kv_source="$array_name"
local -A kv_map=()
local -a display=()
for entry in "${kv_source[@]}"; do
local label="${entry%%|*}"
local value="${entry#*|}"
kv_map["$label"]="$value"
display+=("$label")
done
if [[ -n "$back_label" ]]; then
kv_map["$back_label"]="$back_label"
display+=("$back_label")
fi
local selection
selection="$(rofi_menu "$prompt" "${display[@]}")" || return "$?"
[[ -z "$selection" ]] && return 1
printf "%s\n" "${kv_map[$selection]}"
}
# rofi_select_list prompt array_name
# Convenience wrapper for plain lists (no label/value mapping).
rofi_select_list() {
local prompt="$1"
local array_name="$2"
local -n list_source="$array_name"
rofi_menu "$prompt" "${list_source[@]}"
}

View File

@@ -7,5 +7,7 @@ DIR="$HOME/Pictures/wallpapers/favorites"
SELECTED_WALL=$(cd "$DIR" && for a in *.jpg *.png; do echo -en "$a\0icon\x1f$a\n"; done | rofi -dmenu -i -no-custom -theme "$THEME" -p "Select a wallpaper" -theme-str 'configuration {icon-size: 128; dpi: 96;} window {width: 45%; height: 45%;}') SELECTED_WALL=$(cd "$DIR" && for a in *.jpg *.png; do echo -en "$a\0icon\x1f$a\n"; done | rofi -dmenu -i -no-custom -theme "$THEME" -p "Select a wallpaper" -theme-str 'configuration {icon-size: 128; dpi: 96;} window {width: 45%; height: 45%;}')
PTH="$(printf "%s" "$DIR/$SELECTED_WALL" | tr -s '/')" PTH="$(printf "%s" "$DIR/$SELECTED_WALL" | tr -s '/')"
notify-send -a "rofi-wallpaper" "Wallpaper set to" -i "$PTH" "$PTH" notify-send -a "rofi-wallpaper" "Wallpaper set to" -i "$PTH" "$PTH"
hyprctl hyprpaper reload , "$DIR/$SELECTED_WALL" hyprctl hyprpaper preload "$PTH"
hyprctl hyprpaper wallpaper "DP-1,$PTH"
hyprctl hyprpaper unload "$(cat "$HOME/.wallpaper")"
echo "$PTH" >"$HOME/.wallpaper" echo "$PTH" >"$HOME/.wallpaper"

View File

@@ -1,3 +1,4 @@
export BROWSER=zen-browser
export XCURSOR_THEME=dracula export XCURSOR_THEME=dracula
export XCURSOR_SIZE=24 export XCURSOR_SIZE=24
export GDK_SCALE=1 export GDK_SCALE=1

View File

@@ -2,7 +2,7 @@
"layer": "bottom", "layer": "bottom",
"position": "top", "position": "top",
"height": 40, "height": 40,
"width": 2545, "width": 3422,
"spacing": 1, "spacing": 1,
"reload_style_on_change": true, "reload_style_on_change": true,
"fixed-center": true, "fixed-center": true,
@@ -11,16 +11,15 @@
"custom/launcher", "custom/launcher",
"hyprland/workspaces", "hyprland/workspaces",
"tray", "tray",
"hyprland/submap",
"custom/mpd-scroll", "custom/mpd-scroll",
"custom/mpv-scroll", "custom/mpv-scroll",
"custom/firefox-scroll", "custom/firefox-scroll",
"cava", "hyprland/submap"
], ],
// "modules-center": ["hyprland/window"], // "modules-center": ["hyprland/window"],
"modules-center": ["custom/notification"], "modules-center": ["custom/notification"],
"modules-right": [ "modules-right": [
"hyprland/scratchpad", // "hyprland/scratchpad",
// "idle_inhibitor", // "idle_inhibitor",
// "custom/notification", // "custom/notification",
"custom/updates", "custom/updates",
@@ -157,13 +156,13 @@
"format-disconnected": "Disconnected ⚠", "format-disconnected": "Disconnected ⚠",
"on-click": "$HOME/.config/rofi/scripts/rofi-wifi-menu.sh", "on-click": "$HOME/.config/rofi/scripts/rofi-wifi-menu.sh",
}, },
// "custom/weather": { "custom/weather": {
// "interval": 600, "interval": 600,
// "exec": "~/.config/waybar/scripts/wttr.sh Los_Angeles", "exec": "~/.config/waybar/scripts/wttr.sh Los_Angeles",
// "return-type": "json", "return-type": "json",
// "format": "{}", "format": "{}",
// "tooltip": true, "tooltip": true,
// }, },
"custom/kernel": { "custom/kernel": {
"exec": "uname -r | sed -E 's/^([0-9]+\\.[0-9]+\\.[0-9]+)-.*-([a-zA-Z0-9]+)/\\1-\\2/'", "exec": "uname -r | sed -E 's/^([0-9]+\\.[0-9]+\\.[0-9]+)-.*-([a-zA-Z0-9]+)/\\1-\\2/'",
"format": "{} ", "format": "{} ",
@@ -233,8 +232,8 @@
// "20": "十", // "20": "十",
}, },
"persistent-workspaces": { "persistent-workspaces": {
// "*": 10, "*": 10,
"*": 5, // "*": 5,
}, },
"sort-by": "number", "sort-by": "number",
"all-outputs": false, "all-outputs": false,
@@ -305,7 +304,7 @@
"exec": "$HOME/.config/waybar/scripts/scroll-mpv.sh", "exec": "$HOME/.config/waybar/scripts/scroll-mpv.sh",
"format": "<span color='#450241'> </span> {}", "format": "<span color='#450241'> </span> {}",
"max-length": 35, "max-length": 35,
"on-click": "playerctl -p firefox play-pause", "on-click": "playerctl -p mpv play-pause",
"hide-empty-text": true, "hide-empty-text": true,
}, },
"custom/notification": { "custom/notification": {
@@ -313,13 +312,13 @@
"format": "{icon}", "format": "{icon}",
"format-icons": { "format-icons": {
"notification": "<span foreground='red'><sup></sup></span>", "notification": "<span foreground='red'><sup></sup></span>",
"none": "", "none": "<span foreground='red'><sup> </sup></span>",
"dnd-notification": "<span foreground='red'><sup></sup></span>", "dnd-notification": "<span foreground='red'><sup></sup></span>",
"dnd-none": "", "dnd-none": "<span foreground='red'><sup> </sup></span>",
"inhibited-notification": "<span foreground='red'><sup></sup></span>", "inhibited-notification": "<span foreground='red'><sup></sup></span>",
"inhibited-none": "", "inhibited-none": "<span foreground='red'><sup> </sup></span>",
"dnd-inhibited-notification": "<span foreground='red'><sup></sup></span>", "dnd-inhibited-notification": "<span foreground='red'><sup></sup></span>",
"dnd-inhibited-none": "", "dnd-inhibited-none": "<span foreground='red'><sup> </sup></span>",
}, },
"return-type": "json", "return-type": "json",
"exec-if": "which swaync-client", "exec-if": "which swaync-client",

View File

@@ -92,6 +92,8 @@ button:hover {
#submap { #submap {
background-color: @base; background-color: @base;
box-shadow: inset 0 -2px @text; box-shadow: inset 0 -2px @text;
padding: 0 10px;
margin: 5px 1px 5px 2px;
} }
#custom-weather, #custom-weather,
@@ -107,7 +109,6 @@ button:hover {
#custom-kernel, #custom-kernel,
#idle_inhibitor, #idle_inhibitor,
#scratchpad, #scratchpad,
#submap,
#tray { #tray {
padding: 0 10px; padding: 0 10px;
margin: 5px 1px; margin: 5px 1px;
@@ -124,6 +125,12 @@ button:hover {
margin-left: 0; margin-left: 0;
} }
.modules-right {
padding-left: 1px;
}
.modules-left {
padding-right: 4px;
}
.modules-right > widget:last-child > #workspaces { .modules-right > widget:last-child > #workspaces {
margin-right: 0; margin-right: 0;
} }
@@ -213,7 +220,7 @@ label:focus {
/* background-color: @overlay0; */ /* background-color: @overlay0; */
background-color: @surface0; background-color: @surface0;
color: @mantle; color: @mantle;
margin: 5px 3px 5px 1px; margin: 5px 1px 5px 1px;
} }
#tray > .passive { #tray > .passive {
@@ -255,7 +262,7 @@ label:focus {
color: @mantle; color: @mantle;
background-color: @mauve; background-color: @mauve;
padding: 0 10px; padding: 0 10px;
margin: 5px 1px; margin: 5px 1px 5px 2px;
} }
#custom-updates { #custom-updates {
background-color: @yellow; background-color: @yellow;
@@ -274,7 +281,7 @@ label:focus {
color: @mantle; color: @mantle;
background-color: @peach; background-color: @peach;
padding: 0 10px; padding: 0 10px;
margin: 5px 5px 5px 1px; margin: 5px 1px 5px 2px;
} }
#cava { #cava {
@@ -311,7 +318,7 @@ label:focus {
background-color: @flamingo; background-color: @flamingo;
color: @base; color: @base;
padding: 0 10px; padding: 0 10px;
margin: 5px 5px 5px 1px; margin: 5px 1px 5px 2px;
} }
#custom-notification { #custom-notification {

View File

@@ -3,6 +3,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"image"
"io" "io"
"math/rand" "math/rand"
"net/http" "net/http"
@@ -14,6 +15,12 @@ import (
"sort" "sort"
"strings" "strings"
"time" "time"
_ "image/gif"
"image/jpeg"
"image/png"
"golang.org/x/image/draw"
) )
const ( const (
@@ -66,6 +73,12 @@ type WallhavenResponse struct {
} `json:"data"` } `json:"data"`
} }
type monitor struct {
Name string `json:"name"`
Width int `json:"width"`
Height int `json:"height"`
}
func main() { func main() {
// Initialize random source // Initialize random source
r := rand.New(rand.NewSource(time.Now().UnixNano())) r := rand.New(rand.NewSource(time.Now().UnixNano()))
@@ -162,7 +175,7 @@ func downloadRandomWallpaper(wallpaperPath string, r *rand.Rand, topics []string
fmt.Fprintf(os.Stderr, "Searching for wallpapers related to: %s\n", displayName) fmt.Fprintf(os.Stderr, "Searching for wallpapers related to: %s\n", displayName)
// Get wallpapers from Wallhaven API // Get wallpapers from Wallhaven API
resp, err := http.Get(fmt.Sprintf("%s/search?q=%s&purity=100&categories=110&sorting=random", wallhavenAPI, query)) resp, err := http.Get(fmt.Sprintf("%s/search?q=%s&purity=100&categories=110&sorting=random&atleast=3440x1440", wallhavenAPI, query))
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Error fetching from Wallhaven: %v\n", err) fmt.Fprintf(os.Stderr, "Error fetching from Wallhaven: %v\n", err)
return "", "" return "", ""
@@ -213,27 +226,165 @@ func downloadRandomWallpaper(wallpaperPath string, r *rand.Rand, topics []string
return filepath, displayName return filepath, displayName
} }
func activeMonitors() ([]monitor, error) {
out, err := exec.Command("hyprctl", "-j", "monitors").Output()
if err != nil {
return nil, err
}
var monitors []monitor
if err := json.Unmarshal(out, &monitors); err != nil {
return nil, err
}
return monitors, nil
}
func ensureSized(wallpaperPath string) (string, error) {
monitors, err := activeMonitors()
if err != nil {
return "", err
}
if len(monitors) == 0 {
return wallpaperPath, nil
}
targetWidth := 0
targetHeight := 0
for _, m := range monitors {
if m.Width > targetWidth {
targetWidth = m.Width
}
if m.Height > targetHeight {
targetHeight = m.Height
}
}
if targetWidth == 0 || targetHeight == 0 {
return wallpaperPath, nil
}
file, err := os.Open(wallpaperPath)
if err != nil {
return "", err
}
defer file.Close()
src, format, err := image.Decode(file)
if err != nil {
return "", err
}
srcWidth := float64(src.Bounds().Dx())
srcHeight := float64(src.Bounds().Dy())
targetW := float64(targetWidth)
targetH := float64(targetHeight)
// Calculate scale factor to fit image within target while maintaining aspect ratio
scaleW := targetW / srcWidth
scaleH := targetH / srcHeight
scale := min(scaleW, scaleH)
// If image already fits within target dimensions, no resize needed
if scale >= 1.0 {
return wallpaperPath, nil
}
// Calculate new dimensions maintaining aspect ratio (best fit)
newWidth := int(srcWidth * scale)
newHeight := int(srcHeight * scale)
dst := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight))
draw.CatmullRom.Scale(dst, dst.Bounds(), src, src.Bounds(), draw.Over, nil)
var ext string
switch format {
case "jpeg":
ext = ".jpg"
case "png":
ext = ".png"
case "gif":
ext = ".png"
default:
ext = filepath.Ext(wallpaperPath)
if ext == "" {
ext = ".jpg"
}
}
base := strings.TrimSuffix(filepath.Base(wallpaperPath), filepath.Ext(wallpaperPath))
resizedPath := filepath.Join(filepath.Dir(wallpaperPath), fmt.Sprintf("%s-%dx%d%s", base, newWidth, newHeight, ext))
outFile, err := os.Create(resizedPath)
if err != nil {
return "", err
}
defer outFile.Close()
switch format {
case "png", "gif":
if err := png.Encode(outFile, dst); err != nil {
return "", err
}
default:
if err := jpeg.Encode(outFile, dst, &jpeg.Options{Quality: 90}); err != nil {
return "", err
}
}
return resizedPath, nil
}
func changeWallpaper(wallpaperPath, topic string) { func changeWallpaper(wallpaperPath, topic string) {
resizedPath, err := ensureSized(wallpaperPath)
if err != nil {
fmt.Fprintf(os.Stderr, "Error resizing wallpaper: %v\n", err)
resizedPath = wallpaperPath
}
if resizedPath == "" {
resizedPath = wallpaperPath
}
// Save current wallpaper path // Save current wallpaper path
homeDir, _ := os.UserHomeDir() homeDir, _ := os.UserHomeDir()
wallpaperFile := filepath.Join(homeDir, ".wallpaper") wallpaperFile := filepath.Join(homeDir, ".wallpaper")
if err := os.WriteFile(wallpaperFile, []byte(wallpaperPath), 0644); err != nil { if err := os.WriteFile(wallpaperFile, []byte(resizedPath), 0644); err != nil {
fmt.Fprintf(os.Stderr, "Error saving wallpaper path: %v\n", err) fmt.Fprintf(os.Stderr, "Error saving wallpaper path: %v\n", err)
} }
// Change wallpaper using hyprctl monitors, monitorErr := activeMonitors()
cmd := exec.Command("hyprctl", "hyprpaper", "reload", ","+wallpaperPath) if monitorErr != nil {
fmt.Fprintf(os.Stderr, "Error getting monitors: %v\n", monitorErr)
}
cmd := exec.Command("hyprctl", "hyprpaper", "preload", resizedPath)
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
fmt.Fprintf(os.Stderr, "Error changing wallpaper: %v\n", err) fmt.Fprintf(os.Stderr, "Error preloading wallpaper: %v\n", err)
}
if monitorErr != nil || len(monitors) == 0 {
cmd = exec.Command("hyprctl", "hyprpaper", "wallpaper", ","+resizedPath)
if err := cmd.Run(); err != nil {
fmt.Fprintf(os.Stderr, "Error applying wallpaper: %v\n", err)
}
} else {
for _, m := range monitors {
cmd = exec.Command("hyprctl", "hyprpaper", "wallpaper", fmt.Sprintf("%s,%s", m.Name, resizedPath))
if err := cmd.Run(); err != nil {
fmt.Fprintf(os.Stderr, "Error applying wallpaper for monitor %s: %v\n", m.Name, err)
}
}
}
cmd = exec.Command("hyprctl", "hyprpaper", "reload")
if err := cmd.Run(); err != nil {
fmt.Fprintf(os.Stderr, "Error reloading hyprpaper: %v\n", err)
} }
// Send notification with wallpaper as icon // Send notification with wallpaper as icon
filename := filepath.Base(wallpaperPath) filename := filepath.Base(resizedPath)
message := fmt.Sprintf("Wallpaper changed to %s", filename) message := fmt.Sprintf("Wallpaper changed to %s", filename)
if topic != "" { if topic != "" {
message += fmt.Sprintf(" (%s)", topic) message += fmt.Sprintf(" (%s)", topic)
} }
notifyWithIcon(message, "normal", wallpaperPath) notifyWithIcon(message, "normal", resizedPath)
} }
func notify(message, urgency string) { func notify(message, urgency string) {

202
projects/scripts/record-audio.sh Normal file → Executable file
View File

@@ -1,93 +1,145 @@
#!/bin/sh #!/usr/bin/env bash
# Version 1.2 # Toggle desktop audio recording and attach the result to the newest Anki note
# shoutout to https://gist.github.com/Cephian/f849e326e3522be9a4386b60b85f2f23 for the original script, # (as tagged by Yomichan). Run once to start recording, run again to stop.
# https://github.com/xythh/ added the ankiConnect functionality # Dependencies: jq, curl, ffmpeg/ffprobe, pulseaudio (parec+pactl), bc, notify-send
# toggle record computer audio (run once to start, run again to stop)
# dependencies: ffmpeg, pulseaudio, curl
# where recording gets saved, gets deleted after being imported to anki set -euo pipefail
DIRECTORY="$HOME/.cache/"
FORMAT="mp3" # ogg or mp3
# cut file since it glitches a bit at the end sometimes
CUT_DURATION="0.1"
#port used by ankiconnect
ankiConnectPort="8765"
# gets the newest created card, so make sure to create the card first with yomichan
newestNoteId=$(curl -s localhost:$ankiConnectPort -X POST -d '{"action": "findNotes", "version": 6, "params": { "query": "is:new"}}' | jq '.result[-1]')
#Audio field name
audioFieldName="SentenceAudio"
#if there is no newest note, you either have a complete empty anki or ankiconnect isn't running ANKI_CONNECT_PORT="${ANKI_CONNECT_PORT:-8765}"
if [ "$newestNoteId" = "" ]; then AUDIO_FIELD_NAME="${AUDIO_FIELD_NAME:-SentenceAudio}"
notify-send "anki connect not found" FORMAT="${FORMAT:-mp3}" # mp3 or ogg
CUT_DURATION="${CUT_DURATION:-0.1}"
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/record-audio"
RECORD_TIMEOUT="${RECORD_TIMEOUT:-60}"
ANKI_URL="http://localhost:${ANKI_CONNECT_PORT}"
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "Missing dependency: $1" >&2
exit 1
}
}
notify() {
# Best-effort notification; keep script running if notify-send is missing.
if command -v notify-send >/dev/null 2>&1; then
notify-send -t 1000 "$@"
fi
}
get_active_sink() {
pactl list sinks short 2>/dev/null | awk '$6=="RUNNING"{print $1; exit 0}'
}
get_newest_note_id() {
local response
response=$(curl -sS "$ANKI_URL" -X POST -H 'Content-Type: application/json' \
-d '{"action":"findNotes","version":6,"params":{"query":"is:new"}}')
jq -r '.result[-1] // empty' <<<"$response"
}
update_anki_note() {
local note_id="$1" audio_path="$2" filename="$3"
local payload
payload=$(jq -n --argjson noteId "$note_id" --arg field "$AUDIO_FIELD_NAME" \
--arg path "$audio_path" --arg filename "$filename" '
{action:"updateNoteFields",version:6,
params:{note:{id:$noteId,fields:{($field):""},
audio:[{path:$path,filename:$filename,fields:[$field]}]}}}')
curl -sS "$ANKI_URL" -X POST -H 'Content-Type: application/json' -d "$payload" >/dev/null
}
open_note_in_browser() {
local note_id="$1"
local payload
payload=$(jq -n --argjson noteId "$note_id" '
{action:"guiBrowse",version:6,params:{query:("nid:" + ($noteId|tostring))}}')
curl -sS "$ANKI_URL" -X POST -H 'Content-Type: application/json' -d "$payload" >/dev/null
}
record_audio() {
local note_id="$1"
local sink
sink=$(get_active_sink) || true
if [[ -z "$sink" ]]; then
notify "Record Error" "No running PulseAudio sink found"
exit 1 exit 1
fi fi
if pgrep -f "parec"; then mkdir -p "$CACHE_DIR"
pkill -f "parec"
else
time=$(date +%s)
name="$DIRECTORY/$time"
wav_file="$name.wav"
out_file="$name.$FORMAT"
if ! [ -d "$DIRECTORY" ]; then local timestamp wav_file out_file
mkdir "$DIRECTORY" timestamp=$(date +%s)
fi wav_file="$CACHE_DIR/$timestamp.wav"
notify-send -t 1000 "Audio recording started" out_file="$CACHE_DIR/$timestamp.$FORMAT"
#timeout 1m arecord -t wav -f cd "$wav_file"
# just grabs last running source... may not always work if your pulseaudio setup is complicated notify "Audio recording started"
if ! timeout 1m parec -d"$(pactl list sinks | grep -B1 'State: RUNNING' | sed -nE 's/Sink #(.*)/\1/p' | tail -n 1)" --file-format=wav "$wav_file"; then
notify-send "Error recording " "most likely no audio playing" if ! timeout "$RECORD_TIMEOUT" parec -d"$sink" --file-format=wav "$wav_file"; then
rm "$wav_file" notify "Record Error" "No audio captured (timeout or sink issue)"
rm -f "$wav_file"
exit 1 exit 1
fi fi
input_duration=$(ffprobe -v error -select_streams a:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 "$wav_file") local input_duration output_duration
output_duration=$(echo "$input_duration"-"$CUT_DURATION" | bc) input_duration=$(ffprobe -v error -select_streams a:0 \
-show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 "$wav_file")
output_duration=$(echo "$input_duration - $CUT_DURATION" | bc -l)
# encode file and delete OG # Guard against negative durations
if [ $FORMAT = "ogg" ]; then if [[ $(echo "$output_duration < 0" | bc -l) -eq 1 ]]; then
ffmpeg -i "$wav_file" -vn -codec:a libvorbis -b:a 64k -t "$output_duration" "$out_file" output_duration="0"
elif [ $FORMAT = "mp3" ]; then
ffmpeg -i "$wav_file" -vn -codec:a libmp3lame -qscale:a 1 -t "$output_duration" "$out_file"
else
notify-send "Record Error" "Unknown format $FORMAT"
fi fi
rm "$wav_file"
# Update newest note with recorded audio case "$FORMAT" in
curl -s localhost:$ankiConnectPort -X POST -d '{ ogg)
ffmpeg -nostdin -y -i "$wav_file" -vn -codec:a libvorbis -b:a 64k \
-t "$output_duration" "$out_file"
;;
mp3)
ffmpeg -nostdin -y -i "$wav_file" -vn -codec:a libmp3lame -qscale:a 1 \
-t "$output_duration" "$out_file"
;;
*)
notify "Record Error" "Unknown format: $FORMAT"
rm -f "$wav_file"
exit 1
;;
esac
"action": "updateNoteFields", rm -f "$wav_file"
"version": 6,
"params": { update_anki_note "$note_id" "$out_file" "$timestamp.$FORMAT"
"note": { open_note_in_browser "$note_id"
"id": '"$newestNoteId"',
"fields": { notify "Audio recording copied"
"'$audioFieldName'": "" rm -f "$out_file"
},
"audio": [{
"path": "'"$out_file"'",
"filename": "'"$time"'.'$FORMAT'",
"fields": [
"'$audioFieldName'"
]
}]
} }
}
}' main() {
# opens changed note, comment if you don't want it. for cmd in curl jq ffmpeg ffprobe parec pactl bc; do
curl -s localhost:$ankiConnectPort -X POST -d '{ require_cmd "$cmd"
"action": "guiBrowse", done
"version": 6,
"params": { if pgrep -x parec >/dev/null 2>&1; then
"query": "nid:'"$newestNoteId"'" pkill -x parec
} notify "Audio recording stopped"
}' exit 0
notify-send -t 1000 "Audio recording copied"
rm "$out_file"
fi fi
local newest_note
newest_note=$(get_newest_note_id)
if [[ -z "$newest_note" ]]; then
notify "Anki Connect" "No new notes found or AnkiConnect unavailable"
exit 1
fi
record_audio "$newest_note"
}
main "$@"

106
projects/scripts/rmpv Executable file
View File

@@ -0,0 +1,106 @@
#!/usr/bin/env bash
THEME="${THEME:-$HOME/.config/rofi/launchers/type-2/style-2.rasi}"
THUMBNAIL_PATH="/tmp/rmpv-thumbnail.jpg"
FONTCONFIG_FILE=$HOME/.config/mpv/mpv-fonts.conf
COMMAND=mpv
# Parse command-line options first
while getopts ":it:" opt; do
case $opt in
i)
COMMAND="$COMMAND --profile=immersion"
;;
t)
THEME="$OPTARG"
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
shift $((OPTIND - 1))
generate_thumbnail() {
local video_file="$1"
local temp_thumb="/tmp/rmpv-thumbnail-$$.jpg"
local thumbnail_file="${video_file%.*}.jpg"
# Clean up previous thumbnail
rm -f "$THUMBNAIL_PATH"
# Validate input
if [[ -z "$video_file" ]]; then
echo "Error: No video file specified" >&2
return 1
fi
if [[ ! -f "$video_file" ]]; then
echo "Error: Video file '$video_file' not found" >&2
return 1
fi
# Check if it's a video file
if ! file "$video_file" | grep -qE "(video|Video)"; then
echo "Error: '$video_file' doesn't appear to be a video file" >&2
return 1
fi
# Generate thumbnail if it doesn't exist
if [[ ! -f "$thumbnail_file" ]]; then
echo "Generating thumbnail for $(basename "$video_file")..."
# Try generating thumbnail side-by-side
if ! ffmpeg -ss 00:00:01 -i "$video_file" \
-vf "scale=320:240:force_original_aspect_ratio=decrease,pad=320:240:(ow-iw)/2:(oh-ih)/2" \
-frames:v 1 \
-q:v 4 \
"$thumbnail_file" \
-loglevel error -y 2>/dev/null; then
# Fallback to temp file if side-by-side fails (e.g. read-only fs)
echo "Warning: Failed to write to $thumbnail_file, trying temp location" >&2
thumbnail_file="$temp_thumb"
if ! ffmpeg -ss 00:00:01 -i "$video_file" \
-vf "scale=320:240:force_original_aspect_ratio=decrease,pad=320:240:(ow-iw)/2:(oh-ih)/2" \
-frames:v 1 \
-q:v 4 \
"$thumbnail_file" \
-loglevel error -y 2>/dev/null; then
echo "Error: Failed to generate thumbnail" >&2
return 1
fi
fi
fi
# Copy to consistent location for notify-send
# We use a fixed path so notify-send always finds it
if cp "$thumbnail_file" "$THUMBNAIL_PATH" 2>/dev/null; then
echo "Thumbnail ready at: $THUMBNAIL_PATH"
ls -l "$THUMBNAIL_PATH"
file "$THUMBNAIL_PATH"
else
echo "Error: Failed to copy thumbnail to $THUMBNAIL_PATH" >&2
fi
}
choice="$(find . -iname "*[.mkv|.mp4]" | sort -h | rofi -dmenu -i -theme "$THEME" -theme-str 'listview {columns: 1; lines: 15;} window {width: 88%;}' -p "Choose Video")"
if [[ -z "$choice" ]]; then
echo "No video selected."
exit 1
fi
generate_thumbnail "$choice"
if [[ ! -f "$THUMBNAIL_PATH" ]]; then
echo "Warning: Thumbnail not created, notification will have no icon" >&2
fi
notify-send -i "$THUMBNAIL_PATH" "Playing Video" "$(basename "$choice")"
$COMMAND "$choice" &
# vim: ft=sh

163
projects/scripts/screenshot-anki.sh Normal file → Executable file
View File

@@ -1,75 +1,112 @@
#!/bin/sh #!/usr/bin/env bash
# Version 1.2 # Capture a region with slurp+grim. If AnkiConnect is available, attach the
# click and drag to screenshot dragged portion # JPEG to the newest note; otherwise copy a PNG to the clipboard.
# click on specific window to screenshot window area
# dependencies: imagemagick, xclip,curl maybe xdotool (see comment below)
# shoutout to https://gist.github.com/Cephian/f849e326e3522be9a4386b60b85f2f23 for the original script,
# https://github.com/xythh/ added the ankiConnect functionality
# if anki is running the image is added to your latest note as a jpg, if anki is not running it's added to your clipboard as a png
time=$(date +%s)
tmp_file="$HOME/.cache/$time"
ankiConnectPort="8765"
pictureField="Picture"
quality="90"
# This gets your notes marked as new and returns the newest one. set -euo pipefail
newestNoteId=$(curl -s localhost:$ankiConnectPort -X POST -d '{"action": "findNotes", "version": 6, "params": { "query": "is:new"}}' | jq '.result[-1]')
# you can remove these two lines if you don't have software which ANKI_CONNECT_PORT="${ANKI_CONNECT_PORT:-8765}"
# makes your mouse disappear when you use the keyboard (e.g. xbanish, unclutter) PICTURE_FIELD="${PICTURE_FIELD:-Picture}"
# https://github.com/ImageMagick/ImageMagick/issues/1745#issuecomment-777747494 QUALITY="${QUALITY:-90}"
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/screenshot-anki"
ANKI_URL="http://localhost:${ANKI_CONNECT_PORT}"
REQUIREMENTS=(slurp grim wl-copy xdotool curl jq)
notify() {
if command -v notify-send >/dev/null 2>&1; then
notify-send "$@"
fi
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
notify "Missing dependency" "$1 is required"
exit 1
}
}
wiggle_mouse() {
# Avoid disappearing cursor on some compositors
xdotool mousemove_relative 1 1 xdotool mousemove_relative 1 1
xdotool mousemove_relative -- -1 -1 xdotool mousemove_relative -- -1 -1
}
# if anki connect is running it will return your latest note id, and the following code will run, if anki connect is not running nothing is return. capture_region() {
if [ "$newestNoteId" != "" ]; then local fmt="$1" quality="$2" output="$3"
if ! import -quality $quality "$tmp_file.jpg"; then local geometry
# most likley reason this returns a error, is for fullscreen applications that take full control which does not allowing imagemagick to select the area, use windowed fullscreen or if running wine use a virtual desktop to avoid this. geometry=$(slurp)
notify-send "Error screenshoting " "most likely unable to find selection" if [[ -z "$geometry" ]]; then
notify "Screenshot cancelled" "No region selected"
exit 1 exit 1
fi fi
if [[ "$fmt" == "jpeg" ]]; then
curl -s localhost:$ankiConnectPort -X POST -d '{ grim -g "$geometry" -t jpeg -q "$quality" "$output"
"action": "updateNoteFields",
"version": 6,
"params": {
"note": {
"id": '"$newestNoteId"',
"fields": {
"'$pictureField'": ""
},
"picture": [{
"path": "'"$tmp_file"'.jpg",
"filename": "paste-'"$time"'.jpg",
"fields": [
"'$pictureField'"
]
}]
}
}
}'
#remove if you don't want anki to show you the card you just edited
curl -s localhost:$ankiConnectPort -X POST -d '{
"action": "guiBrowse",
"version": 6,
"params": {
"query": "nid:'"$newestNoteId"'"
}
}'
#you can comment this if you do not use notifcations.
notify-send "Screenshot Taken" "Added to note"
rm "$tmp_file.jpg"
else else
if ! import -quality $quality "$tmp_file.png"; then grim -g "$geometry" -t png "$output"
notify-send "Error screenshoting " "most likely unable to find selection" fi
}
copy_to_clipboard() {
local file="$1"
if ! wl-copy <"$file"; then
notify "Error copying screenshot" "wl-copy failed"
exit 1 exit 1
fi fi
# we use pngs when copying to clipboard because they have greater support when pasting. }
xclip -selection clipboard -target image/png -i "$tmp_file.png"
rm "$tmp_file.png" get_newest_note_id() {
#you can comment this if you do not use notifcations. local response
notify-send "Screenshot Taken" "Copied to clipboard" response=$(curl -sS "$ANKI_URL" -X POST -H 'Content-Type: application/json' \
-d '{"action":"findNotes","version":6,"params":{"query":"is:new"}}')
jq -r '.result[-1] // empty' <<<"$response"
}
update_note_with_image() {
local note_id="$1" image_path="$2" filename="$3"
local payload
payload=$(jq -n --argjson noteId "$note_id" --arg field "$PICTURE_FIELD" \
--arg path "$image_path" --arg filename "$filename" '
{action:"updateNoteFields",version:6,
params:{note:{id:$noteId,fields:{($field):""},
picture:[{path:$path,filename:$filename,fields:[$field]}]}}}')
curl -sS "$ANKI_URL" -X POST -H 'Content-Type: application/json' -d "$payload" >/dev/null
}
open_note_in_browser() {
local note_id="$1"
local payload
payload=$(jq -n --argjson noteId "$note_id" '
{action:"guiBrowse",version:6,params:{query:("nid:" + ($noteId|tostring))}}')
curl -sS "$ANKI_URL" -X POST -H 'Content-Type: application/json' -d "$payload" >/dev/null
}
main() {
for cmd in "${REQUIREMENTS[@]}"; do
require_cmd "$cmd"
done
mkdir -p "$CACHE_DIR"
local timestamp base newest_note image_path
timestamp=$(date +%s)
base="$CACHE_DIR/$timestamp"
wiggle_mouse
newest_note=$(get_newest_note_id)
if [[ -n "$newest_note" ]]; then
image_path="$base.jpg"
capture_region "jpeg" "$QUALITY" "$image_path"
update_note_with_image "$newest_note" "$image_path" "paste-$timestamp.jpg"
open_note_in_browser "$newest_note"
notify -i "$image_path" "Screenshot Taken" "Added to Anki note"
rm -f "$image_path"
else
image_path="$base.png"
capture_region "png" "" "$image_path"
copy_to_clipboard "$image_path"
notify -i "$image_path" "Screenshot Taken" "Copied to clipboard"
rm -f "$image_path"
fi fi
}
main "$@"

View File

@@ -8,13 +8,13 @@ import logging
import os import os
import signal import signal
import sys import sys
from typing import List
import gi import gi
from gi.repository import GLib, Playerctl from gi.repository import GLib, Playerctl
from gi.repository.Playerctl import Player from gi.repository.Playerctl import Player
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
is_plain = False is_plain = False
@@ -66,7 +66,7 @@ class PlayerManager:
self.manager.manage_player(player) self.manager.manage_player(player)
self.on_metadata_changed(player, player.props.metadata) self.on_metadata_changed(player, player.props.metadata)
def get_players(self) -> List[Player]: def get_players(self) -> list[Player]:
return self.manager.props.players return self.manager.props.players
def write_output(self, text, player): def write_output(self, text, player):
@@ -234,5 +234,4 @@ def main():
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -7,17 +7,18 @@ if [ -z "$PLAYER" ]; then
exit 1 exit 1
fi fi
STATUS="$(playerctl -p "$PLAYER" status)" STATUS="$(playerctl -sp "$PLAYER" status)"
if [ -z "$STATUS" ] || [ "$STATUS" = "Stopped" ]; then case "$STATUS" in "" | "Stopped")
exit 0 exit 0
elif [ "$STATUS" = "Paused" ]; then ;;
"Paused")
STATUS=" " STATUS=" "
elif [ "$STATUS" = "Playing" ]; then ;;
"Playing")
STATUS=" " STATUS=" "
else ;;
exit 0 esac
fi
TITLE="$(playerctl -p "$PLAYER" metadata title)" TITLE="$(playerctl -p "$PLAYER" metadata title)"
ARTIST="$(playerctl -p "$PLAYER" metadata artist)" ARTIST="$(playerctl -p "$PLAYER" metadata artist)"

View File

@@ -2,6 +2,7 @@
if pgrep -af "waybar -c /home/sudacode/.config/waybar/catppuccin-macchiato/config-battery.jsonc -s /home/sudacode/.config/waybar/catppuccin-macchiato/style.css" || if pgrep -af "waybar -c /home/sudacode/.config/waybar/catppuccin-macchiato/config-battery.jsonc -s /home/sudacode/.config/waybar/catppuccin-macchiato/style.css" ||
pgrep -af "waybar -c /home/sudacode/.config/waybar/catppuccin-macchiato/config.jsonc -s /home/sudacode/.config/waybar/catppuccin-macchiato/style.css"; then pgrep -af "waybar -c /home/sudacode/.config/waybar/catppuccin-macchiato/config.jsonc -s /home/sudacode/.config/waybar/catppuccin-macchiato/style.css"; then
killall zscroll
killall waybar killall waybar
fi fi