[
  {
    "path": ".bashrc",
    "content": "# ~/.bashrc: executed by bash(1) for non-login shells.\n\n# If not running interactively, don't do anything\ncase $- in\n    *i*) ;;\n      *) return;;\nesac\n\n# History settings\nexport HISTCONTROL=ignoreboth:erasedups\nexport HISTIGNORE=\"ls:cd:exit:history*\"\nexport HISTSIZE=1000\nexport HISTFILESIZE=2000\nshopt -s histappend\n\n# Check window size after each command\nshopt -s checkwinsize\n\n# Git branch function\ngit_branch() {\n    local branch\n    branch=$(git branch --show-current 2>/dev/null)\n    if [[ -n \"$branch\" ]]; then\n        # Purple color for git branch\n        echo -e \"\\[\\e[35m\\]$branch\\[\\e[0m\\] \"\n    fi\n}\n\n# Color prompt setup\nif [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then\n    set_prompt() {\n        local branch=$(git_branch)\n        local title=\"\\[\\e]0;\\u@\\h: \\w\\a\\]\"\n        PS1=\"${title}[\\[\\e[32m\\]\\A\\[\\e[0m\\]][\\[\\e[34m\\]\\h\\[\\e[0m\\]][${branch}\\[\\e[33m\\]\\w\\[\\e[0m\\]]\\$ \"\n    }\n    prompt_command() {\n        history -a          # Append current session history to file\n        history -n          # Read new history entries from file\n        cleanup-history     # Clean up the history file\n        set_prompt          # Set the prompt dynamically\n    }\n    PROMPT_COMMAND=prompt_command\nelse\n    PS1='[\\A][\\h][\\w]\\$ '\nfi\n\n# Enable programmable completion\nif ! shopt -oq posix; then\n  if [ -f /usr/share/bash-completion/bash_completion ]; then\n    . /usr/share/bash-completion/bash_completion\n  elif [ -f /etc/bash_completion ]; then\n    . /etc/bash_completion\n  fi\nfi\n\n# Load aliases\n[[ -f ~/.config/aliasrc ]] && . ~/.config/aliasrc\n\n# Proper FZF integration\nif [[ -f /usr/share/doc/fzf/examples/key-bindings.bash ]]; then\n    source /usr/share/doc/fzf/examples/key-bindings.bash\nelif [[ -f ~/.fzf.bash ]]; then\n    source ~/.fzf.bash\nelif [[ -f /usr/share/fzf/key-bindings.bash ]]; then\n    source /usr/share/fzf/key-bindings.bash\nfi\n\n# Keep bash history clean\ncleanup-history() {\n    local histfile=\"$HOME/.bash_history\"\n    [[ -r \"$histfile\" ]] || return\n    awk '\n    {\n        cleaned = $0\n        gsub(/[[:space:]]*$/, \"\", cleaned)\n        if (cleaned != \"\") {\n            last[cleaned] = NR\n            line[NR] = cleaned\n        }\n    }\n    END {\n        for (i = 1; i <= NR; i++) {\n            if (i in line && last[line[i]] == i) {\n                print line[i]\n            }\n        }\n    }\n    ' \"$histfile\" > \"${histfile}.tmp\"\n    if [[ -s \"${histfile}.tmp\" ]]; then\n        command mv -f \"${histfile}.tmp\" \"$histfile\" >/dev/null 2>&1\n    else\n        rm -f \"${histfile}.tmp\" >/dev/null 2>&1\n    fi\n    history -c\n    history -r\n}\n\n# Enhanced history search (CTRL-R)\n__fzf_history__() {\n    history -a\n    history -c\n    history -r\n    local line\n    line=$(history | fzf --height 100% --tac --tiebreak=index --no-sort --exact \\\n            --bind 'ctrl-d:page-down,ctrl-u:page-up' | sed 's/^ *[0-9]* *//')\n    if [[ -n \"$line\" ]]; then\n        READLINE_LINE=$line\n        READLINE_POINT=${#line}\n    fi\n}\n\n# Bind CTRL-R to the history search function in interactive shells\nif [[ $- == *i* ]]; then\n    bind -x '\"\\C-r\": __fzf_history__'\nfi\n\n# FZF preview with bat if available, otherwise cat\nif command -v bat >/dev/null 2>&1; then\n    export FZF_CTRL_T_OPTS=\"--preview 'bat --color=always --line-range :500 {}'\"\nelse\n    export FZF_CTRL_T_OPTS=\"--preview 'cat {}'\"\nfi\n"
  },
  {
    "path": ".config/DankMaterialShell/settings.json",
    "content": "{\n  \"currentThemeName\": \"blue\",\n  \"customThemeFile\": \"\",\n  \"matugenScheme\": \"scheme-tonal-spot\",\n  \"runUserMatugenTemplates\": true,\n  \"matugenTargetMonitor\": \"\",\n  \"popupTransparency\": 1,\n  \"dockTransparency\": 0.5,\n  \"widgetBackgroundColor\": \"sch\",\n  \"widgetColorMode\": \"default\",\n  \"cornerRadius\": 5,\n  \"use24HourClock\": true,\n  \"showSeconds\": false,\n  \"useFahrenheit\": false,\n  \"nightModeEnabled\": false,\n  \"animationSpeed\": 1,\n  \"customAnimationDuration\": 500,\n  \"wallpaperFillMode\": \"Fill\",\n  \"blurredWallpaperLayer\": false,\n  \"blurWallpaperOnOverview\": false,\n  \"showLauncherButton\": true,\n  \"showWorkspaceSwitcher\": true,\n  \"showFocusedWindow\": true,\n  \"showWeather\": true,\n  \"showMusic\": true,\n  \"showClipboard\": true,\n  \"showCpuUsage\": true,\n  \"showMemUsage\": true,\n  \"showCpuTemp\": true,\n  \"showGpuTemp\": true,\n  \"selectedGpuIndex\": 0,\n  \"enabledGpuPciIds\": [],\n  \"showSystemTray\": true,\n  \"showClock\": true,\n  \"showNotificationButton\": true,\n  \"showBattery\": true,\n  \"showControlCenterButton\": true,\n  \"showCapsLockIndicator\": true,\n  \"controlCenterShowNetworkIcon\": true,\n  \"controlCenterShowBluetoothIcon\": true,\n  \"controlCenterShowAudioIcon\": true,\n  \"controlCenterShowVpnIcon\": true,\n  \"controlCenterShowBrightnessIcon\": false,\n  \"controlCenterShowMicIcon\": false,\n  \"controlCenterShowBatteryIcon\": false,\n  \"controlCenterShowPrinterIcon\": false,\n  \"showPrivacyButton\": true,\n  \"privacyShowMicIcon\": false,\n  \"privacyShowCameraIcon\": false,\n  \"privacyShowScreenShareIcon\": false,\n  \"controlCenterWidgets\": [\n    {\n      \"id\": \"volumeSlider\",\n      \"enabled\": true,\n      \"width\": 50\n    },\n    {\n      \"id\": \"brightnessSlider\",\n      \"enabled\": true,\n      \"width\": 50\n    },\n    {\n      \"id\": \"wifi\",\n      \"enabled\": true,\n      \"width\": 50\n    },\n    {\n      \"id\": \"bluetooth\",\n      \"enabled\": true,\n      \"width\": 50\n    },\n    {\n      \"id\": \"audioOutput\",\n      \"enabled\": true,\n      \"width\": 50\n    },\n    {\n      \"id\": \"audioInput\",\n      \"enabled\": true,\n      \"width\": 50\n    },\n    {\n      \"id\": \"builtin_vpn\",\n      \"enabled\": true,\n      \"width\": 50\n    },\n    {\n      \"id\": \"doNotDisturb\",\n      \"enabled\": true,\n      \"width\": 50\n    },\n    {\n      \"id\": \"nightMode\",\n      \"enabled\": true,\n      \"width\": 50\n    },\n    {\n      \"id\": \"darkMode\",\n      \"enabled\": true,\n      \"width\": 50\n    }\n  ],\n  \"showWorkspaceIndex\": false,\n  \"showWorkspacePadding\": false,\n  \"workspaceScrolling\": false,\n  \"showWorkspaceApps\": false,\n  \"maxWorkspaceIcons\": 3,\n  \"workspacesPerMonitor\": true,\n  \"showOccupiedWorkspacesOnly\": false,\n  \"dwlShowAllTags\": false,\n  \"workspaceNameIcons\": {},\n  \"waveProgressEnabled\": true,\n  \"scrollTitleEnabled\": true,\n  \"clockCompactMode\": true,\n  \"focusedWindowCompactMode\": true,\n  \"runningAppsCompactMode\": true,\n  \"keyboardLayoutNameCompactMode\": true,\n  \"runningAppsCurrentWorkspace\": false,\n  \"runningAppsGroupByApp\": false,\n  \"centeringMode\": \"index\",\n  \"clockDateFormat\": \"\",\n  \"lockDateFormat\": \"\",\n  \"mediaSize\": 0,\n  \"appLauncherViewMode\": \"list\",\n  \"spotlightModalViewMode\": \"list\",\n  \"sortAppsAlphabetically\": false,\n  \"appLauncherGridColumns\": 4,\n  \"spotlightCloseNiriOverview\": true,\n  \"niriOverviewOverlayEnabled\": true,\n  \"weatherLocation\": \"New York, NY\",\n  \"weatherCoordinates\": \"40.7128,-74.0060\",\n  \"useAutoLocation\": true,\n  \"weatherEnabled\": true,\n  \"networkPreference\": \"wifi\",\n  \"vpnLastConnected\": \"400fa537-b18c-4a96-b670-3f3713232299\",\n  \"iconTheme\": \"breeze\",\n  \"launcherLogoMode\": \"apps\",\n  \"launcherLogoCustomPath\": \"\",\n  \"launcherLogoColorOverride\": \"surface\",\n  \"launcherLogoColorInvertOnMode\": false,\n  \"launcherLogoBrightness\": 0.5,\n  \"launcherLogoContrast\": 1,\n  \"launcherLogoSizeOffset\": 0,\n  \"fontFamily\": \"Inter Variable\",\n  \"monoFontFamily\": \"Monospace\",\n  \"fontWeight\": 400,\n  \"fontScale\": 1,\n  \"notepadUseMonospace\": true,\n  \"notepadFontFamily\": \"\",\n  \"notepadFontSize\": 14,\n  \"notepadShowLineNumbers\": false,\n  \"notepadTransparencyOverride\": -1,\n  \"notepadLastCustomTransparency\": 0.7,\n  \"soundsEnabled\": true,\n  \"useSystemSoundTheme\": false,\n  \"soundNewNotification\": true,\n  \"soundVolumeChanged\": true,\n  \"soundPluggedIn\": true,\n  \"acMonitorTimeout\": 0,\n  \"acLockTimeout\": 0,\n  \"acSuspendTimeout\": 0,\n  \"acSuspendBehavior\": 0,\n  \"acProfileName\": \"\",\n  \"batteryMonitorTimeout\": 0,\n  \"batteryLockTimeout\": 0,\n  \"batterySuspendTimeout\": 0,\n  \"batterySuspendBehavior\": 0,\n  \"batteryProfileName\": \"\",\n  \"lockBeforeSuspend\": false,\n  \"loginctlLockIntegration\": true,\n  \"fadeToLockEnabled\": false,\n  \"fadeToLockGracePeriod\": 5,\n  \"launchPrefix\": \"\",\n  \"brightnessDevicePins\": {},\n  \"wifiNetworkPins\": {\n    \"preferredWifi\": \"Void\"\n  },\n  \"bluetoothDevicePins\": {},\n  \"audioInputDevicePins\": {},\n  \"audioOutputDevicePins\": {},\n  \"gtkThemingEnabled\": false,\n  \"qtThemingEnabled\": false,\n  \"syncModeWithPortal\": true,\n  \"terminalsAlwaysDark\": false,\n  \"showDock\": false,\n  \"dockAutoHide\": false,\n  \"dockGroupByApp\": true,\n  \"dockOpenOnOverview\": false,\n  \"dockPosition\": 1,\n  \"dockSpacing\": 4,\n  \"dockBottomGap\": -13,\n  \"dockMargin\": 0,\n  \"dockIconSize\": 34,\n  \"dockIndicatorStyle\": \"circle\",\n  \"dockBorderEnabled\": false,\n  \"dockBorderColor\": \"surfaceText\",\n  \"dockBorderOpacity\": 1,\n  \"dockBorderThickness\": 1,\n  \"notificationOverlayEnabled\": false,\n  \"modalDarkenBackground\": true,\n  \"lockScreenShowPowerActions\": true,\n  \"enableFprint\": false,\n  \"maxFprintTries\": 3,\n  \"lockScreenActiveMonitor\": \"all\",\n  \"lockScreenInactiveColor\": \"#000000\",\n  \"hideBrightnessSlider\": false,\n  \"notificationTimeoutLow\": 5000,\n  \"notificationTimeoutNormal\": 5000,\n  \"notificationTimeoutCritical\": 0,\n  \"notificationPopupPosition\": 0,\n  \"osdAlwaysShowValue\": false,\n  \"osdPosition\": 5,\n  \"osdVolumeEnabled\": true,\n  \"osdMediaVolumeEnabled\": true,\n  \"osdBrightnessEnabled\": true,\n  \"osdIdleInhibitorEnabled\": true,\n  \"osdMicMuteEnabled\": true,\n  \"osdCapsLockEnabled\": true,\n  \"osdPowerProfileEnabled\": true,\n  \"osdAudioOutputEnabled\": true,\n  \"powerActionConfirm\": true,\n  \"powerActionHoldDuration\": 0.5,\n  \"powerMenuActions\": [\n    \"reboot\",\n    \"logout\",\n    \"poweroff\",\n    \"lock\",\n    \"suspend\",\n    \"restart\"\n  ],\n  \"powerMenuDefaultAction\": \"logout\",\n  \"powerMenuGridLayout\": false,\n  \"customPowerActionLock\": \"\",\n  \"customPowerActionLogout\": \"\",\n  \"customPowerActionSuspend\": \"\",\n  \"customPowerActionHibernate\": \"\",\n  \"customPowerActionReboot\": \"\",\n  \"customPowerActionPowerOff\": \"\",\n  \"updaterUseCustomCommand\": false,\n  \"updaterCustomCommand\": \"\",\n  \"updaterTerminalAdditionalParams\": \"\",\n  \"displayNameMode\": \"model\",\n  \"screenPreferences\": {\n    \"dock\": []\n  },\n  \"showOnLastDisplay\": {\n    \"dock\": false\n  },\n  \"barConfigs\": [\n    {\n      \"id\": \"default\",\n      \"name\": \"Main Bar\",\n      \"enabled\": true,\n      \"position\": 2,\n      \"screenPreferences\": [\n        {\n          \"name\": \"DP-2\",\n          \"model\": \"24G4\"\n        }\n      ],\n      \"showOnLastDisplay\": true,\n      \"leftWidgets\": [\n        \"launcherButton\",\n        \"workspaceSwitcher\",\n        {\n          \"id\": \"runningApps\",\n          \"enabled\": true\n        }\n      ],\n      \"centerWidgets\": [],\n      \"rightWidgets\": [\n        {\n          \"id\": \"systemTray\",\n          \"enabled\": true\n        },\n        {\n          \"id\": \"clipboard\",\n          \"enabled\": true\n        },\n        {\n          \"id\": \"notificationButton\",\n          \"enabled\": true\n        },\n        {\n          \"id\": \"weather\",\n          \"enabled\": true\n        },\n        {\n          \"id\": \"controlCenterButton\",\n          \"enabled\": true\n        },\n        {\n          \"id\": \"clock\",\n          \"enabled\": true\n        },\n        {\n          \"id\": \"spacer\",\n          \"enabled\": true,\n          \"size\": 5\n        }\n      ],\n      \"spacing\": 5,\n      \"innerPadding\": 0,\n      \"bottomGap\": 0,\n      \"transparency\": 1,\n      \"widgetTransparency\": 1,\n      \"squareCorners\": false,\n      \"noBackground\": false,\n      \"gothCornersEnabled\": false,\n      \"gothCornerRadiusOverride\": false,\n      \"gothCornerRadiusValue\": 12,\n      \"borderEnabled\": false,\n      \"borderColor\": \"surfaceText\",\n      \"borderOpacity\": 1,\n      \"borderThickness\": 1,\n      \"fontScale\": 1,\n      \"autoHide\": false,\n      \"autoHideDelay\": 250,\n      \"openOnOverview\": false,\n      \"visible\": true,\n      \"popupGapsAuto\": true,\n      \"popupGapsManual\": 4,\n      \"maximizeDetection\": false,\n      \"widgetOutlineEnabled\": false,\n      \"widgetOutlineColor\": \"primary\"\n    },\n    {\n      \"id\": \"bar1765687519252\",\n      \"name\": \"Bar 2\",\n      \"enabled\": true,\n      \"position\": 0,\n      \"screenPreferences\": [\n        {\n          \"name\": \"HDMI-A-1\",\n          \"model\": \"LG FULL HD\"\n        }\n      ],\n      \"showOnLastDisplay\": false,\n      \"leftWidgets\": [\n        \"launcherButton\",\n        \"workspaceSwitcher\",\n        {\n          \"id\": \"runningApps\",\n          \"enabled\": true\n        }\n      ],\n      \"centerWidgets\": [],\n      \"rightWidgets\": [\n        {\n          \"id\": \"systemTray\",\n          \"enabled\": true\n        },\n        {\n          \"id\": \"clipboard\",\n          \"enabled\": true\n        },\n        {\n          \"id\": \"notificationButton\",\n          \"enabled\": true\n        },\n        {\n          \"id\": \"weather\",\n          \"enabled\": true\n        },\n        {\n          \"id\": \"controlCenterButton\",\n          \"enabled\": true\n        },\n        {\n          \"id\": \"clock\",\n          \"enabled\": true\n        },\n        {\n          \"id\": \"spacer\",\n          \"enabled\": true,\n          \"size\": 5\n        }\n      ],\n      \"spacing\": 5,\n      \"innerPadding\": 0,\n      \"bottomGap\": 0,\n      \"transparency\": 1,\n      \"widgetTransparency\": 1,\n      \"squareCorners\": false,\n      \"noBackground\": false,\n      \"gothCornersEnabled\": false,\n      \"gothCornerRadiusOverride\": false,\n      \"gothCornerRadiusValue\": 12,\n      \"borderEnabled\": false,\n      \"borderColor\": \"surfaceText\",\n      \"borderOpacity\": 1,\n      \"borderThickness\": 1,\n      \"widgetOutlineEnabled\": false,\n      \"widgetOutlineColor\": \"primary\",\n      \"widgetOutlineOpacity\": 1,\n      \"widgetOutlineThickness\": 1,\n      \"fontScale\": 1,\n      \"autoHide\": false,\n      \"autoHideDelay\": 250,\n      \"openOnOverview\": false,\n      \"visible\": true,\n      \"popupGapsAuto\": true,\n      \"popupGapsManual\": 4,\n      \"maximizeDetection\": false\n    }\n  ],\n  \"configVersion\": 2\n}"
  },
  {
    "path": ".config/MangoHud/MangoHud.conf",
    "content": "################### File Generated by Goverlay ###################\nlegacy_layout=false\n\nhorizontal\nhorizontal_stretch=0\nbackground_alpha=0.3\nround_corners=10\nbackground_alpha=0.3\nbackground_color=000000\n\nfont_size=24\nfont_size_text=24\ntext_color=FFFFFF\nposition=top-left\n\nhud_compact\nhud_no_margin\npci_dev=0:2d:00.0\ntable_columns=2\ngpu_text=GPU\ngpu_stats\ngpu_load_change\ngpu_load_value=50,90\ngpu_load_color=FFFFFF,FFAA7F,CC0000\ngpu_temp\ngpu_mem_temp\ngpu_color=2E9762\ncpu_text=CPU\ncpu_stats\n\ncpu_load_change\ncpu_load_value=50,90\ncpu_load_color=FFFFFF,FFAA7F,CC0000\ncpu_temp\ncpu_color=2E97CB\nvram\nvram_color=AD64C1\nvram_color=AD64C1\nram\nram_color=C26693\nfps\nframe_timing\nframetime_color=00FF00\nfps_limit_method=early\n\nshow_fps_limit\n\nfps_limit=119,59,48,30\nfsr\nfps_color_change\nfps_color=B22222,FDFD09,39F900\nfps_value=60,120\n#offset=-1\nvsync=0\ngl_vsync=-1\n\n\n\ntime#\n\n\noutput_folder=$HOME/.cache\nlog_duration=30\nautostart_log=0\nlog_interval=100\nblacklist=protonplus,lsfg-vk-ui,bazzar,gnome-calculator,pamac-manager,lact,ghb,bitwig-studio,ptyxis,yumex\ntoggle_logging=Shift_L+F2\n\n"
  },
  {
    "path": ".config/alacritty/alacritty.toml",
    "content": "[general]\nimport = [ \"~/.config/alacritty/colors.toml\" ]\n\n[window]\nopacity = 0.96\npadding.x = 24\npadding.y = 24\n\n[font]\nnormal = { family = \"monospace\", style = \"Regular\" }\nsize = 12.0\n\n[cursor]\nstyle = { shape = \"Block\", blinking = \"On\" }\n"
  },
  {
    "path": ".config/alacritty/colors.toml",
    "content": "# Base16 Gruvbox dark, medium - alacritty color config\n# Dawid Kurek (dawikur@gmail.com), morhetz (https://github.com/morhetz/gruvbox)\n\n[colors]\ndraw_bold_text_with_bright_colors = false\n\n# Default colors\n[colors.primary]\nbackground = '0x282828'\nforeground = '0xd5c4a1'\n\n# Colors the cursor will use if `custom_cursor_colors` is true\n[colors.cursor]\ntext = '0x282828'\ncursor = '0xd5c4a1'\n\n# Normal colors\n[colors.normal]\nblack = '0x282828'\nred = '0xfb4934'\ngreen = '0xb8bb26'\nyellow = '0xfabd2f'\nblue = '0x83a598'\nmagenta = '0xd3869b'\ncyan = '0x8ec07c'\nwhite = '0xd5c4a1'\n\n# Bright colors\n[colors.bright]\nblack = '0x665c54'\nred = '0xfe8019'\ngreen = '0x3c3836'\nyellow = '0x504945'\nblue = '0xbdae93'\nmagenta = '0xebdbb2'\ncyan = '0xd65d0e'\nwhite = '0xfbf1c7'"
  },
  {
    "path": ".config/aliasrc",
    "content": "#!/bin/sh\n# Colorized commands\nalias \\\n    ls=\"ls -shA --color=auto\" \\\n    dir=\"dir --color=auto\" \\\n    vdir=\"vdir --color=auto\" \\\n    grep=\"grep --color=auto\" \\\n    fgrep=\"fgrep --color=auto\" \\\n    egrep=\"egrep --color=auto\" \\\n    diff=\"diff --color=auto\" \\\n    ccat=\"highlight --out-format=ansi\" \\\n    dfg=\"df -BG\" \\\n    dfm=\"df -BM\" \\\n    ip=\"ip --color=auto\"\n\n# LS aliases with preserved color flags\nalias \\\n    ll=\"ls -l --color=auto\" \\\n    la=\"ls -A --color=auto\" \\\n    llt=\"ls -latrG --color=auto\"\n\n# Package management\nalias \\\n    xbs=\"sudo xbps-install\" \\\n    xbr=\"sudo xbps-remove -Rv\" \\\n    xbq=\"xbps-query -Rs\" \\\n    pac=\"sudo pacman\" \\\n    prm=\"sudo pacman -Rns\" \\\n    pror=\"sudo pacman -Rns $(pacman -Qtdq)\" \\\n    apti=\"sudo apt-get install --no-install-recommends\" \\\n    aptr=\"sudo apt-get --purge autoremove\" \\\n    zyi=\"sudo zypper install --no-recommends\" \\\n    zyr=\"sudo zypper remove --clean-deps --no-confirm\" \\\n    flinst=\"flatpak install\" \\\n    flrem=\"flatpak uninstall --delete-data\" \\\n    flclean=\"flatpak uninstall --unused --delete-data -y && flatpak repair\"\n\n# Network aliases\nalias \\\n    rsync=\"rsync -avh --progress\" \\\n    rsync-ssh=\"rsync -avzh --progress -e ssh\" \\\n    rsync-net=\"rsync -avzh --progress\" \\\n    nfs-mount=\"sudo mount -t nfs -o hard,tcp,rsize=32768,wsize=32768,actimeo=30\" \\\n    ssh-mount=\"sshfs -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3,sshfs_sync\"\n\n# Safe file operations\nalias \\\n    cp=\"cp -iv\" \\\n    mv=\"mv -iv\" \\\n    rm=\"rm -vI\" \\\n    mkd=\"mkdir -pv\" \\\n    clear=\"tput clear\" \\\n    reset=\"tput reset\"\n\n# System utilities\nalias \\\n    pyserv=\"python3 -m http.server\" \\\n    pyenv=\"python -m venv\" \\\n    cleanup-gamescope='pkill -9 -f \"wine|wineserver|winedevice.exe|explorer.exe|gamescope-wl\"' \\\n    reset=\"tput reset\"\n\n# Version control\nalias gcl='git clone --depth 1'\n\n# Use neovim if available\ncommand -v nvim >/dev/null && alias vim=\"nvim\" vimdiff=\"nvim -d\"\n\n# XDG-compliant tmux configuration\nalias tmux=\"tmux -f ${XDG_CONFIG_HOME:-$HOME/.config}/tmux/tmux.conf\"\n"
  },
  {
    "path": ".config/autostart/autostart",
    "content": "#!/bin/sh\n\nLOG=\"/tmp/autostart.log\"\n\n# Config\nAUDIO=false\nMODE=\"swaybg-random-online\" # swaybg, swaybg-random, mpvpaper-local, mpvpaper-online, swaybg-random-online, wallhaven, none\nTHEME_MODE=\"none\" # auto, fixed, none\nTHEME_NAME=\"gruvbox-dark-medium\"\nCURSOR=\"Kaela-Kovalskia-v2\"\nWAYBAR_STYLE=\"none\" # stacking, tiling, none\nUPDATE_SCAN=true\n\n# Defaults local\nDWALL=\"$HOME/pictures/walls/wall.jpg\"\nDVWALL=\"$HOME/pictures/walls/vert-wall.jpg\"\n\n# Pastebin URLs\nP_WALL=\"https://pastebin.com/raw/7YwMgZXg\"\nP_VWALL=\"https://pastebin.com/raw/Q8GUUAse\"\nP_VID=\"https://pastebin.com/raw/yHFpxMDB\"\nP_VVID=\"https://pastebin.com/raw/NTVA8RMd\"\n\n# Wait for Wayland compositor to be ready (max 10s)\ntimeout=20\nwhile { [ -z \"$WAYLAND_DISPLAY\" ] || [ ! -S \"$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY\" ]; } && [ \"$timeout\" -gt 0 ]; do\n  sleep 0.5\n  timeout=$((timeout - 1))\ndone\n\n# --- Env setup ---\ndbus-update-activation-environment --all >>\"$LOG\" 2>&1 &\n#/usr/libexec/polkit-gnome-authentication-agent-1 >>\"$LOG\" 2>&1 &\n/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 >>\"$LOG\" 2>&1 &\n\n# --- Monitor layout ---\n#wlr-randr --output DP-2 --on --mode 1920x1080@120 --pos 0,0 --transform normal --scale 1 --adaptive-sync enabled >>\"$LOG\" 2>&1\n#wlr-randr --output HDMI-A-1 --on --mode 1920x1080@60 --pos -1080,-840 --transform 270 --scale 1 --adaptive-sync enabled >>\"$LOG\" 2>&1 &\n\n# --- Process Management ---\nfor p in flavours mpvpaper swaybg fnott wlsunset cliphist; do\n  pkill -x \"$p\" >>\"$LOG\" 2>&1 || :\ndone\n\n# --- Audio ---\nif [ \"$AUDIO\" = true ]; then\n  for p in pipewire wireplumber pipewire-pulse; do pkill -x \"$p\" >>\"$LOG\" 2>&1 || :; done\n  pipewire >>\"$LOG\" 2>&1 &\n  sleep 1\n  wireplumber >>\"$LOG\" 2>&1 &\n  pipewire-pulse >>\"$LOG\" 2>&1 &\nfi\n\n# --- OpenRGB ---\nif command -v openrgb >/dev/null 2>&1; then\n  openrgb --server -p pureWhite >>\"$LOG\" 2>&1 &\nelse\n  echo \"OpenRGB not found\" >>\"$LOG\"\nfi\n\n# --- Helpers ---\nget_orient() {\n  wlr-randr | awk '\n    /^[A-Za-z0-9-]+/ { o = $1 }\n    /Transform:/ {\n      t = $2\n      if (t ~ /90|270/)\n        print o \":portrait\"\n      else\n        print o \":landscape\"\n    }\n  '\n}\n\nfetch_url() {\n  curl -fsSL \"$1\" | shuf -n1 | tr -d '\\r\\n' | xargs\n}\n\ndownload_wallhaven() {\n  r=$1\n  out=$2\n  fb=$3\n  res=$4\n\n  pg=$(shuf -i1-5 -n1)\n  json=$(curl -sf \"https://wallhaven.cc/api/v1/search?categories=110&purity=100&sorting=toplist&topRange=1y&ratios=$r&atleast=$res&page=$pg&per_page=24\") || {\n    echo \"Wallhaven fail $r\" >>\"$LOG\"\n    cp \"$fb\" \"$out\"\n    return\n  }\n\n  cnt=$(echo \"$json\" | jq '.data|length')\n  if [ \"$cnt\" -eq 0 ]; then\n    cp \"$fb\" \"$out\"\n    return\n  fi\n\n  idx=$(shuf -i0-$((cnt - 1)) -n1)\n  url=$(echo \"$json\" | jq -r \".data[$idx].path\")\n  curl -sfL \"$url\" -o \"$out\" || cp \"$fb\" \"$out\"\n}\n\napply_swaybg() {\n  w=$1\n  vw=$2\n  while IFS=: read -r o or; do\n    if [ \"$or\" = \"portrait\" ]; then\n      swaybg -o \"$o\" -i \"$vw\" -m fill >>\"$LOG\" 2>&1 &\n    else\n      swaybg -o \"$o\" -i \"$w\" -m fill >>\"$LOG\" 2>&1 &\n    fi\n  done <<EOF\n$(get_orient)\nEOF\n}\n\napply_mpvpaper() {\n  for entry in $(get_orient); do\n    o=${entry%%:*}\n    or=${entry##*:}\n    if [ \"$MODE\" = \"mpvpaper-local\" ]; then\n      v=$(find \"$HOME/pictures/walls/\" -type f -name \"*.mp4\" | shuf -n1)\n      if [ -z \"$v\" ]; then\n        echo \"No local vid found\" >>\"$LOG\"\n        continue\n      fi\n      mpvpaper -vsp -o \"no-audio pause=no --loop --ytdl-format='bestvideo[height<=1080]+bestaudio/best'\" \"$o\" \"$v\" >>\"$LOG\" 2>&1 &\n    else\n      if [ \"$or\" = \"portrait\" ]; then\n        u=$(fetch_url \"$P_VVID\")\n      else\n        u=$(fetch_url \"$P_VID\")\n      fi\n      mpvpaper -vsp -o \"no-audio pause=no --loop --ytdl-format='bestvideo[height<=1080]+bestaudio/best'\" \"$o\" \"$u\" >>\"$LOG\" 2>&1 &\n    fi\n  done\n}\n\nconfigure_theme() {\n  case \"$THEME_MODE\" in\n    auto)\n      if [ -f /tmp/wall.jpg ]; then\n        flavours generate dark /tmp/wall.jpg >>\"$LOG\" 2>&1\n        flavours apply generated >>\"$LOG\" 2>&1 &\n      fi\n      ;;\n    fixed)\n      flavours apply \"$THEME_NAME\" >>\"$LOG\" 2>&1 &\n      ;;\n    none)\n      ;;\n  esac\n}\n\nconfigure_waybar() {\n  case \"$WAYBAR_STYLE\" in\n    stacking)\n      pkill -x waybar >>\"$LOG\" 2>&1 || :\n      waybar -c \"$HOME/.config/waybar/stacking-config\" -s \"$HOME/.config/waybar/style.css\" >>\"$LOG\" 2>&1 &\n      ;;\n    tiling)\n      pkill -x waybar >>\"$LOG\" 2>&1 || :\n      waybar -c \"$HOME/.config/waybar/tiling-config\" -s \"$HOME/.config/waybar/style.css\" >>\"$LOG\" 2>&1 &\n      ;;\n    none)\n      ;;\n  esac\n}\n\n# --- Main ---\ncase \"$MODE\" in\n  swaybg-random-online)\n    w=$(fetch_url \"$P_WALL\")\n    curl -fsSL \"$w\" -o /tmp/wall.jpg || cp \"$DWALL\" /tmp/wall.jpg\n    vw=$(fetch_url \"$P_VWALL\")\n    curl -fsSL \"$vw\" -o /tmp/vert_wall.jpg || cp \"$DVWALL\" /tmp/vert_wall.jpg\n    apply_swaybg /tmp/wall.jpg /tmp/vert_wall.jpg\n    ;;\n  swaybg-random)\n    w=$(find \"$HOME/pictures/walls/\"*.jpg -type f | shuf -n1)\n    [ -z \"$w\" ] && w=\"$DWALL\"\n    vw=$(find \"$HOME/pictures/walls/\"vert-*.jpg -type f | shuf -n1)\n    [ -z \"$vw\" ] && vw=\"$DVWALL\"\n    apply_swaybg \"$w\" \"$vw\"\n    ;;\n  swaybg)\n    apply_swaybg \"$DWALL\" \"$DVWALL\"\n    ;;\n  mpvpaper-local|mpvpaper-online)\n    apply_mpvpaper\n    ;;\n  wallhaven)\n    download_wallhaven \"16x9\" /tmp/wall.jpg \"$DWALL\" \"1920x1080\"\n    download_wallhaven \"9x16\" /tmp/vert_wall.jpg \"$DVWALL\" \"1080x1920\"\n    apply_swaybg /tmp/wall.jpg /tmp/vert_wall.jpg\n    ;;\n  none)\n    ;;\n  *)\n    echo \"Unknown MODE: $MODE\" >>\"$LOG\"\n    ;;\nesac\n\nconfigure_theme\nconfigure_waybar\n\n# --- Cursor ---\ngsettings set org.gnome.desktop.interface cursor-theme \"$CURSOR\" >>\"$LOG\" 2>&1 &\nseat seat0 xcursor_theme \"$CURSOR\" >>\"$LOG\" 2>&1 &\n\n# --- Extras ---\n#fnott >>\"$LOG\" 2>&1 &\nwlsunset -l 36.7 -L 3.08 >>\"$LOG\" 2>&1 &\nwl-paste --watch cliphist store -max-items 100 >>\"$LOG\" 2>&1 &\ngsettings set org.gnome.desktop.interface color-scheme 'prefer-dark' &\n\n# --- Updates ---\nif [ \"$UPDATE_SCAN\" = true ]; then\n  sleep 2\n  \"$HOME/.local/bin/updtscan\" >>\"$LOG\" 2>&1 &\nfi\n"
  },
  {
    "path": ".config/autostart/openrgb.desktop",
    "content": "[Desktop Entry]\nType=Application\nExec=bash -c 'if command -v openrgb >/dev/null 2>&1; then openrgb --server -p pureWhite >>\"$HOME/openrgb.log\" 2>&1 & else echo \"OpenRGB is not installed, skipping RGB startup.\" >>\"$HOME/openrgb.log\"; fi'\nHidden=false\nNoDisplay=false\nX-GNOME-Autostart-enabled=true\nName=OpenRGB Autostart\nComment=Start OpenRGB server with pureWhite profile at login\n"
  },
  {
    "path": ".config/flavours/config.toml",
    "content": "shell = \"bash -c '{}'\"\n\n[[item]]\nfile = \"~/.config/waybar/colors.css\"\ntemplate = \"waybar\"\nhook = \"pkill -SIGRTMIN+7 waybar\"\nrewrite = true\n\n[[item]]\nfile = \"~/.config/foot/colors.ini\"\ntemplate = \"foot\"\nhook = \"footclient -e 'source ~/.config/foot/colors.ini'\"\nrewrite = true\n\n[[item]]\nfile = \"~/.config/alacritty/colors.toml\"\ntemplate = \"alacritty\"\nrewrite = true\n\n[[items]]\nfile = \"~/.config/fuzzel/colors.ini\"\ntemplate = \"fuzzel\"\nrewrite = true\n\n[[items]]\nfile = \"/home/lyes/.local/share/themes/Base16/openbox-3/themerc\"\ntemplate = \"labwc\"\nhook = \"labwc -r\"\nstart= \"!! Start flavours\"\nend = \"!! End flavours\"\n\n[[items]]\nfile = \"/home/lyes/.config/nvim/lua/speyll/plugins/colorscheme.lua\"\ntemplate = \"nvim\"\nhook = \"nvim --server /tmp/nvim-server --remote-send ':source ~/.config/nvim/lua/speyll/plugins/colorscheme.lua<CR>:lua require(\\\"base16-colorscheme\\\").setup()<CR>'\"\nstart= \"-- Start flavours\"\nend = \"-- End flavours\"\n\n[[items]]\nfile = \"/home/lyes/.config/nvim/lua/speyll/plugins/nvim-hardline.lua\"\ntemplate = \"nvim-hardline\"\nstart= \"-- Start flavours\"\nend = \"-- End flavours\"\n\n[[items]]\nfile = \"~/.config/imv/config\"\ntemplate = \"imv\"\n\n[[items]]\nfile = \"~/.config/fnott/fnott.ini\"\ntemplate = \"fnott\"\n\n[[item]]\nfile = \"~/.config/swayimg/config\"\ntemplate = \"swayimg\"\n\n[[item]]\nfile = \"~/.config/sway/config.d/colors\"\ntemplate = \"sway\"\nsubtemplate = \"colors\"\nrewrite = true\nlight = false\nhook = \"swaymsg reload\"\n\n[[items]]\nfile = \"~/.config/hypr/colors.conf\"\ntemplate = \"hyprland\"\nsubtemplate = \"colors\"\nrewrite = true\nhook = \"hyprctl reload\"\n\n[[item]]\nfile = \"~/.config/river/init\"\ntemplate = \"river\"\n\n[[item]]\nfile = \"~/.config/wayfire.ini\"\ntemplate = \"wayfire\"\n"
  },
  {
    "path": ".config/flavours/schemes/catppuccin/catppuccin-dark.yaml",
    "content": "scheme: \"Catppuccin Mocha\"\nauthor: \"https://github.com/catppuccin/catppuccin\"\nbase00: \"1e1e2e\" # base\nbase01: \"181825\" # mantle\nbase02: \"313244\" # surface0\nbase03: \"45475a\" # surface1\nbase04: \"585b70\" # surface2\nbase05: \"cdd6f4\" # text\nbase06: \"f5e0dc\" # rosewater\nbase07: \"b4befe\" # lavender\nbase08: \"f38ba8\" # red\nbase09: \"fab387\" # peach\nbase0A: \"f9e2af\" # yellow\nbase0B: \"a6e3a1\" # green\nbase0C: \"94e2d5\" # teal\nbase0D: \"89b4fa\" # blue\nbase0E: \"cba6f7\" # mauve\nbase0F: \"f2cdcd\" # flamingo\n"
  },
  {
    "path": ".config/flavours/schemes/catppuccin/catppuccin-light.yaml",
    "content": "scheme: \"Catppuccin Latte\"\nauthor: \"https://github.com/catppuccin/catppuccin\"\nbase00: \"eff1f5\" # base\nbase01: \"e6e9ef\" # mantle\nbase02: \"ccd0da\" # surface0\nbase03: \"bcc0cc\" # surface1\nbase04: \"acb0be\" # surface2\nbase05: \"4c4f69\" # text\nbase06: \"dc8a78\" # rosewater\nbase07: \"7287fd\" # lavender\nbase08: \"d20f39\" # red\nbase09: \"fe640b\" # peach\nbase0A: \"df8e1d\" # yellow\nbase0B: \"40a02b\" # green\nbase0C: \"179299\" # teal\nbase0D: \"1e66f5\" # blue\nbase0E: \"8839ef\" # mauve\nbase0F: \"dd7878\" # flamingo\n"
  },
  {
    "path": ".config/flavours/schemes/gruvbox/gruvbox-dark-medium.yaml",
    "content": "scheme: \"Gruvbox dark, medium\"\nauthor: \"Dawid Kurek (dawikur@gmail.com), morhetz (https://github.com/morhetz/gruvbox)\"\nbase00: \"282828\" # ----\nbase01: \"3c3836\" # ---\nbase02: \"504945\" # --\nbase03: \"665c54\" # -\nbase04: \"bdae93\" # +\nbase05: \"d5c4a1\" # ++\nbase06: \"ebdbb2\" # +++\nbase07: \"fbf1c7\" # ++++\nbase08: \"fb4934\" # red\nbase09: \"fe8019\" # orange\nbase0A: \"fabd2f\" # yellow\nbase0B: \"b8bb26\" # green\nbase0C: \"8ec07c\" # aqua/cyan\nbase0D: \"83a598\" # blue\nbase0E: \"d3869b\" # purple\nbase0F: \"d65d0e\" # brown\n"
  },
  {
    "path": ".config/flavours/schemes/gruvbox/gruvbox-light-medium.yaml",
    "content": "scheme: \"Gruvbox light, medium\"\nauthor: \"Dawid Kurek (dawikur@gmail.com), morhetz (https://github.com/morhetz/gruvbox)\"\nbase00: \"fbf1c7\" # ----\nbase01: \"ebdbb2\" # ---\nbase02: \"d5c4a1\" # --\nbase03: \"bdae93\" # -\nbase04: \"665c54\" # +\nbase05: \"504945\" # ++\nbase06: \"3c3836\" # +++\nbase07: \"282828\" # ++++\nbase08: \"9d0006\" # red\nbase09: \"af3a03\" # orange\nbase0A: \"b57614\" # yellow\nbase0B: \"79740e\" # green\nbase0C: \"427b58\" # aqua/cyan\nbase0D: \"076678\" # blue\nbase0E: \"8f3f71\" # purple\nbase0F: \"d65d0e\" # brown\n"
  },
  {
    "path": ".config/flavours/schemes/solarized/solarized-dark.yaml",
    "content": "scheme: \"Solarized Dark\"\nauthor: \"Ethan Schoonover (modified by aramisgithub)\"\nbase00: \"002b36\"\nbase01: \"073642\"\nbase02: \"586e75\"\nbase03: \"657b83\"\nbase04: \"839496\"\nbase05: \"93a1a1\"\nbase06: \"eee8d5\"\nbase07: \"fdf6e3\"\nbase08: \"dc322f\"\nbase09: \"cb4b16\"\nbase0A: \"b58900\"\nbase0B: \"859900\"\nbase0C: \"2aa198\"\nbase0D: \"268bd2\"\nbase0E: \"6c71c4\"\nbase0F: \"d33682\"\n"
  },
  {
    "path": ".config/flavours/schemes/solarized/solarized-light.yaml",
    "content": "scheme: \"Solarized Light\"\nauthor: \"Ethan Schoonover (modified by aramisgithub)\"\nbase00: \"fdf6e3\"\nbase01: \"eee8d5\"\nbase02: \"93a1a1\"\nbase03: \"839496\"\nbase04: \"657b83\"\nbase05: \"586e75\"\nbase06: \"073642\"\nbase07: \"002b36\"\nbase08: \"dc322f\"\nbase09: \"cb4b16\"\nbase0A: \"b58900\"\nbase0B: \"859900\"\nbase0C: \"2aa198\"\nbase0D: \"268bd2\"\nbase0E: \"6c71c4\"\nbase0F: \"d33682\"\n"
  },
  {
    "path": ".config/flavours/templates/ags/templates/config.yaml",
    "content": "colors:\n    extension: .scss\n    output: colors\n"
  },
  {
    "path": ".config/flavours/templates/ags/templates/default.mustache",
    "content": "@define-color theme-base00 #{{base00-hex}};\n@define-color theme-base01 #{{base01-hex}};\n@define-color theme-base02 #{{base02-hex}};\n@define-color theme-base03 #{{base03-hex}};\n@define-color theme-base04 #{{base04-hex}};\n@define-color theme-base05 #{{base05-hex}};\n@define-color theme-base06 #{{base06-hex}};\n@define-color theme-base07 #{{base07-hex}};\n@define-color theme-base08 #{{base08-hex}};\n@define-color theme-base09 #{{base09-hex}};\n@define-color theme-base0A #{{base0A-hex}};\n@define-color theme-base0B #{{base0B-hex}};\n@define-color theme-base0C #{{base0C-hex}};\n@define-color theme-base0D #{{base0D-hex}};\n@define-color theme-base0E #{{base0E-hex}};\n@define-color theme-base0F #{{base0F-hex}};\n"
  },
  {
    "path": ".config/flavours/templates/alacritty/templates/config.yaml",
    "content": "default:\n  extension: .toml\n  output: colors\ndefault-256:\n  extension: -256.toml\n  output: colors\n"
  },
  {
    "path": ".config/flavours/templates/alacritty/templates/default-256.mustache",
    "content": "# Base16 {{scheme-name}} 256 - alacritty color config\n# {{scheme-author}}\n\n# Default colors\n[colors.primary]\nbackground = '0x{{base00-hex}}'\nforeground = '0x{{base05-hex}}'\n\n# Colors the cursor will use if `custom_cursor_colors` is true\n[colors.cursor]\ntext = '0x{{base00-hex}}'\ncursor = '0x{{base05-hex}}'\n\n# Normal colors\n[colors.normal]\nblack = '0x{{base00-hex}}'\nred = '0x{{base08-hex}}'\ngreen = '0x{{base0B-hex}}'\nyellow = '0x{{base0A-hex}}'\nblue = '0x{{base0D-hex}}'\nmagenta = '0x{{base0E-hex}}'\ncyan = '0x{{base0C-hex}}'\nwhite = '0x{{base05-hex}}'\n\n# Bright colors\n[colors.bright]\nblack = '0x{{base03-hex}}'\nred = '0x{{base08-hex}}'\ngreen = '0x{{base0B-hex}}'\nyellow = '0x{{base0A-hex}}'\nblue = '0x{{base0D-hex}}'\nmagenta = '0x{{base0E-hex}}'\ncyan = '0x{{base0C-hex}}'\nwhite = '0x{{base07-hex}}'\n\n[[colors.indexed_colors]]\nindex = 16\ncolor = \"0x{{base09-hex}}\"\n\n[[colors.indexed_colors]]\nindex = 17\ncolor = \"0x{{base0F-hex}}\"\n\n[[colors.indexed_colors]]\nindex = 18\ncolor = \"0x{{base01-hex}}\"\n\n[[colors.indexed_colors]]\nindex = 19\ncolor = \"0x{{base02-hex}}\"\n\n[[colors.indexed_colors]]\nindex = 20\ncolor = \"0x{{base04-hex}}\"\n\n[[colors.indexed_colors]]\nindex = 21\ncolor = \"0x{{base06-hex}}\"\n"
  },
  {
    "path": ".config/flavours/templates/alacritty/templates/default.mustache",
    "content": "# Base16 {{scheme-name}} - alacritty color config\n# {{scheme-author}}\n\n[colors]\ndraw_bold_text_with_bright_colors = false\n\n# Default colors\n[colors.primary]\nbackground = '0x{{base00-hex}}'\nforeground = '0x{{base05-hex}}'\n\n# Colors the cursor will use if `custom_cursor_colors` is true\n[colors.cursor]\ntext = '0x{{base00-hex}}'\ncursor = '0x{{base05-hex}}'\n\n# Normal colors\n[colors.normal]\nblack = '0x{{base00-hex}}'\nred = '0x{{base08-hex}}'\ngreen = '0x{{base0B-hex}}'\nyellow = '0x{{base0A-hex}}'\nblue = '0x{{base0D-hex}}'\nmagenta = '0x{{base0E-hex}}'\ncyan = '0x{{base0C-hex}}'\nwhite = '0x{{base05-hex}}'\n\n# Bright colors\n[colors.bright]\nblack = '0x{{base03-hex}}'\nred = '0x{{base09-hex}}'\ngreen = '0x{{base01-hex}}'\nyellow = '0x{{base02-hex}}'\nblue = '0x{{base04-hex}}'\nmagenta = '0x{{base06-hex}}'\ncyan = '0x{{base0F-hex}}'\nwhite = '0x{{base07-hex}}'\n"
  },
  {
    "path": ".config/flavours/templates/fnott/templates/config.yaml",
    "content": "default:\n  extension: .ini\n  output: colors\n"
  },
  {
    "path": ".config/flavours/templates/fnott/templates/default.mustache",
    "content": "background={{base00-hex}}bf\nborder-color={{base0B-hex}}ff\ntitle-color={{base0B-hex}}ff\nprogress-bar-color={{base0B-hex}}ff\n\n[low]\nbackground={{base00-hex}}bf\ntitle-color={{base0D-hex}}ff\nsummary-color={{base05-hex}}ff\nbody-color={{base05-hex}}ff\n\n# [normal]\n\n[critical]\ntitle-color={{base0A-hex}}ff\n"
  },
  {
    "path": ".config/flavours/templates/foot/templates/config.yaml",
    "content": "default:\n  extension: .ini\n  output: colors\n"
  },
  {
    "path": ".config/flavours/templates/foot/templates/default.mustache",
    "content": "# Base16 {{scheme-name}} - foot color config\n# {{scheme-author}}\n[colors]\nbackground={{base00-hex}}\nforeground={{base06-hex}}\n\n# Normal colors\nregular0={{base00-hex}} # Black, could also be base01\nregular1={{base08-hex}} # Red\nregular2={{base0B-hex}} # Green\nregular3={{base0A-hex}} # Yellow\nregular4={{base0D-hex}} # Blue\nregular5={{base0E-hex}} # Magenta\nregular6={{base0C-hex}} # Cyan\nregular7={{base06-hex}} # White\n\n# Bright colors\nbright0={{base03-hex}}\nbright1={{base09-hex}}\nbright2={{base01-hex}}\nbright3={{base02-hex}}\nbright4={{base04-hex}}\nbright5={{base06-hex}}\nbright6={{base0F-hex}}\nbright7={{base07-hex}}\n"
  },
  {
    "path": ".config/flavours/templates/fuzzel/templates/config.yaml",
    "content": "default:\n  extension: .ini\n  output: colors\n"
  },
  {
    "path": ".config/flavours/templates/fuzzel/templates/default.mustache",
    "content": "[colors]\nbackground=#{{base00-hex}}df\ntext=#{{base06-hex}}ff\ninput=#{{base06-hex}}ff\nmatch=#{{base08-hex}}ff\nselection=#{{base0C-hex}}ff\nselection-text=#{{base00-hex}}df\nselection-match=#{{base08-hex}}ff\nborder=#{{base0C-hex}}ff\n"
  },
  {
    "path": ".config/flavours/templates/gtk-flatcolor/templates/config.yaml",
    "content": "gtk-2:\n    extension: -gtkrc\n    output: gtk-2\n\ngtk-3:\n    extension: -gtk.css\n    output: gtk-3\n"
  },
  {
    "path": ".config/flavours/templates/gtk-flatcolor/templates/gtk-2.mustache",
    "content": "## Base16 {{scheme-name}}\n# Scheme author: {{scheme-author}}\n# Template author: Tinted Theming (https://github.com/tinted-theming)\n# In file gtk-2.0/gtkrc, delete \"gtk-color-scheme\" including everything between quotes (don't delete gtk-auto-mnemonics) and inject this.\ngtk-color-scheme = \"bg_color:#{{base00-hex}}\ncolor0:#{{base00-hex}}\ntext_color:#{{base05-hex}}\nselected_bg_color:#{{base02-hex}}\nselected_fg_color:#{{base05-hex}}\ntooltip_bg_color:#{{base00-hex}}\ntooltip_fg_color:#{{base05-hex}}\ntitlebar_bg_color:#{{base00-hex}}\ntitlebar_fg_color:#{{base05-hex}}\nmenu_bg_color:#{{base00-hex}}\nmenu_fg_color:#{{base05-hex}}\nlink_color:#{{base02-hex}}\"\n"
  },
  {
    "path": ".config/flavours/templates/gtk-flatcolor/templates/gtk-3.mustache",
    "content": "/*\nBase16 {{scheme-name}}\nScheme author: {{scheme-author}}\nTemplate author: Tinted Theming (https://github.com/tinted-theming)\nIn files gtk-3.0/gtk.css and gtk-3.20/gtk.css, delete section \"Default color scheme\" and inject this\n*/\n\n@define-color bg_color #{{base00-hex}};\n@define-color fg_color #{{base05-hex}};\n@define-color base_color #{{base01-hex}};\n@define-color text_color #{{base05-hex}};\n@define-color text_color_disabled #{{base03-hex}};\n@define-color selected_bg_color #{{base02-hex}};\n@define-color selected_fg_color #{{base05-hex}};\n@define-color tooltip_bg_color #{{base00-hex}};\n@define-color tooltip_fg_color #{{base05-hex}};\n"
  },
  {
    "path": ".config/flavours/templates/hyprland/templates/colors.mustache",
    "content": "# Base16 {{scheme-name}}\n# Author: {{scheme-author}}\n\n$base00 = 0xff{{base00-hex}}\n$base01 = 0xff{{base01-hex}}\n$base02 = 0xff{{base02-hex}}\n$base03 = 0xff{{base03-hex}}\n$base04 = 0xff{{base04-hex}}\n$base05 = 0xff{{base05-hex}}\n$base06 = 0xff{{base06-hex}}\n$base07 = 0xff{{base07-hex}}\n$base08 = 0xff{{base08-hex}}\n$base09 = 0xff{{base09-hex}}\n$base0A = 0xff{{base0A-hex}}\n$base0B = 0xff{{base0B-hex}}\n$base0C = 0xff{{base0C-hex}}\n$base0D = 0xff{{base0D-hex}}\n$base0E = 0xff{{base0E-hex}}\n$base0F = 0xff{{base0F-hex}}\n"
  },
  {
    "path": ".config/flavours/templates/hyprland/templates/config.yaml",
    "content": "colors:\n  extension: .conf\n  output: themes\n"
  },
  {
    "path": ".config/flavours/templates/imv/templates/config.yaml",
    "content": "default:\n  extension: .ini\n  output: colors\n"
  },
  {
    "path": ".config/flavours/templates/imv/templates/default.mustache",
    "content": "background = {{base00-hex}}\noverlay_text_color = {{base06-hex}}\noverlay_background_color = {{base00-hex}}\n"
  },
  {
    "path": ".config/flavours/templates/labwc/templates/config.yaml",
    "content": "default:\n  output: colors\n"
  },
  {
    "path": ".config/flavours/templates/labwc/templates/default.mustache",
    "content": "!! Window colors\nwindow.active.title.bg.color: #{{base05-hex}}\nwindow.inactive.title.bg.color: #{{base00-hex}}\nwindow.active.label.text.color: #{{base00-hex}}\nwindow.inactive.label.text.color: #{{base05-hex}}\nwindow.active.border.color: #{{base05-hex}}\nwindow.inactive.border.color: #{{base00-hex}}\nwindow.active.button.iconify.pressed.image.color: #{{base00-hex}}\nwindow.active.button.iconify.disabled.image.color: #{{base0D-hex}}\nwindow.active.button.iconify.unpressed.image.color: #{{base00-hex}}\nwindow.active.button.iconify.toggled.pressed.image.color: #{{base00-hex}}\nwindow.active.button.iconify.toggled.unpressed.image.color: #{{base00-hex}}\nwindow.active.button.max.pressed.image.color: #{{base00-hex}}\nwindow.active.button.max.disabled.image.color: #{{base0D-hex}}\nwindow.active.button.max.unpressed.image.color: #{{base00-hex}}\nwindow.active.button.max.toggled.pressed.image.color: #{{base00-hex}}\nwindow.active.button.max.toggled.unpressed.image.color: #{{base00-hex}}\nwindow.active.button.close.pressed.image.color: #{{base00-hex}}\nwindow.active.button.close.disabled.image.color: #{{base0D-hex}}\nwindow.active.button.close.unpressed.image.color: #{{base00-hex}}\nwindow.active.button.close.toggled.pressed.image.color: #{{base00-hex}}\nwindow.active.button.close.toggled.unpressed.image.color: #{{base00-hex}}\nwindow.active.button.menu.pressed.image.color: #{{base00-hex}}\nwindow.active.button.menu.disabled.image.color: #{{base0D-hex}}\nwindow.active.button.menu.unpressed.image.color: #{{base00-hex}}\nwindow.active.button.menu.toggled.pressed.image.color: #{{base00-hex}}\nwindow.active.button.menu.toggled.unpressed.image.color: #{{base00-hex}}\nwindow.inactive.button.iconify.pressed.image.color: #{{base03-hex}}\nwindow.inactive.button.iconify.disabled.image.color: #{{base0D-hex}}\nwindow.inactive.button.iconify.unpressed.image.color: #{{base03-hex}}\nwindow.inactive.button.iconify.toggled.pressed.image.color: #{{base03-hex}}\nwindow.inactive.button.iconify.toggled.unpressed.image.color: #{{base03-hex}}\nwindow.inactive.button.max.pressed.image.color: #{{base03-hex}}\nwindow.inactive.button.max.disabled.image.color: #{{base0D-hex}}\nwindow.inactive.button.max.unpressed.image.color: #{{base03-hex}}\nwindow.inactive.button.max.toggled.pressed.image.color: #{{base06-hex}}\nwindow.inactive.button.max.toggled.unpressed.image.color: #{{base06-hex}}\nwindow.inactive.button.close.pressed.image.color: #{{base03-hex}}\nwindow.inactive.button.close.disabled.image.color: #{{base0D-hex}}\nwindow.inactive.button.close.unpressed.image.color: #{{base03-hex}}\nwindow.inactive.button.close.toggled.pressed.image.color: #{{base03-hex}}\nwindow.inactive.button.close.toggled.unpressed.image.color: #{{base03-hex}}\nwindow.inactive.button.menu.pressed.image.color: #{{base03-hex}}\nwindow.inactive.button.menu.disabled.image.color: #{{base0D-hex}}\nwindow.inactive.button.menu.unpressed.image.color: #{{base03-hex}}\nwindow.inactive.button.menu.toggled.pressed.image.color: #{{base03-hex}}\nwindow.inactive.button.menu.toggled.unpressed.image.color: #{{base03-hex}}\n\n!! Menu colors\nmenu.items.bg.color: #{{base00-hex}}\nmenu.items.text.color: #{{base05-hex}}\nmenu.items.disabled.text.color: #{{base03-hex}}\nmenu.items.active.bg.color: #{{base05-hex}}\nmenu.items.active.text.color: #{{base00-hex}}\nmenu.separator.color: #{{base05-hex}}\nmenu.border.color: #{{base05-hex}}\nmenu.title.bg.color: #{{base05-hex}}\nmenu.title.text.color: #{{base00-hex}}\n\n!! OSD colors\nosd.border.color: #{{base05-hex}}\nosd.label.text.color: #{{base05-hex}}\nosd.bg.color: #{{base00-hex}}\n"
  },
  {
    "path": ".config/flavours/templates/nvim/templates/config.yaml",
    "content": "default:\n  extension: .lua\n  output: colors\n"
  },
  {
    "path": ".config/flavours/templates/nvim/templates/default.mustache",
    "content": "            base00 = \"none\", base01 = \"#{{base01-hex}}\", base02 = \"#{{base02-hex}}\", base03 = \"#{{base03-hex}}\",\n            base04 = \"#{{base04-hex}}\", base05 = \"#{{base05-hex}}\", base06 = \"#{{base06-hex}}\", base07 = \"#{{base07-hex}}\",\n            base08 = \"#{{base08-hex}}\", base09 = \"#{{base09-hex}}\", base0A = \"#{{base0A-hex}}\", base0B = \"#{{base0B-hex}}\",\n            base0C = \"#{{base0C-hex}}\", base0D = \"#{{base0D-hex}}\", base0E = \"#{{base0E-hex}}\", base0F = \"#{{base0F-hex}}\"\n"
  },
  {
    "path": ".config/flavours/templates/nvim-hardline/templates/config.yaml",
    "content": "default:\n  extension: .lua\n  output: colors\n"
  },
  {
    "path": ".config/flavours/templates/nvim-hardline/templates/default.mustache",
    "content": "            custom_theme = {\n                text = {gui = \"#{{base00-hex}}\", cterm = \"235\", cterm16 = \"0\"},\n                normal = {gui = \"#{{base0D-hex}}\", cterm = \"109\", cterm16 = \"6\"},\n                insert = {gui = \"#{{base0B-hex}}\", cterm = \"142\", cterm16 = \"2\"},\n                replace = {gui = \"#{{base0A-hex}}\", cterm = \"214\", cterm16 = \"3\"},\n                inactive_comment = {gui = \"NONE\", cterm = \"NONE\", cterm16 = \"NONE\"},\n                inactive_cursor = {gui = \"NONE\", cterm = \"NONE\", cterm16 = \"NONE\"},\n                inactive_menu = {gui = \"NONE\", cterm = \"NONE\", cterm16 = \"NONE\"},\n                visual = {gui = \"#{{base0C-hex}}\", cterm = \"108\", cterm16 = \"6\"},\n                command = {gui = \"#{{base0E-hex}}\", cterm = \"132\", cterm16 = \"5\"},\n                alt_text = {gui = \"#{{base06-hex}}\", cterm = \"223\", cterm16 = \"7\"},\n                warning = {gui = \"#{{base08-hex}}\", cterm = \"167\", cterm16 = \"1\"},\n            },\n"
  },
  {
    "path": ".config/flavours/templates/river/templates/config.yaml",
    "content": "colors:\n    extension: .sh\n    output: colors\n"
  },
  {
    "path": ".config/flavours/templates/river/templates/default.mustache",
    "content": "riverctl background-color 0x{{base00-hex}}ff\nriverctl border-color-focused 0x{{base0C-hex}}ff\nriverctl border-color-unfocused 0x{{base00-hex}}ff\n"
  },
  {
    "path": ".config/flavours/templates/sway/templates/colors.mustache",
    "content": "## Base16 {{scheme-name}}\n# Author: {{scheme-author}}\n\nset $base00 #{{base00-hex}}\nset $base01 #{{base01-hex}}\nset $base02 #{{base02-hex}}\nset $base03 #{{base03-hex}}\nset $base04 #{{base04-hex}}\nset $base05 #{{base05-hex}}\nset $base06 #{{base06-hex}}\nset $base07 #{{base07-hex}}\nset $base08 #{{base08-hex}}\nset $base09 #{{base09-hex}}\nset $base0A #{{base0A-hex}}\nset $base0B #{{base0B-hex}}\nset $base0C #{{base0C-hex}}\nset $base0D #{{base0D-hex}}\nset $base0E #{{base0E-hex}}\nset $base0F #{{base0F-hex}}\n"
  },
  {
    "path": ".config/flavours/templates/sway/templates/config.yaml",
    "content": "colors:\n    extension: .config\n    output: themes\n"
  },
  {
    "path": ".config/flavours/templates/swayimg/templates/config.yaml",
    "content": "colors:\n    output: colors\n"
  },
  {
    "path": ".config/flavours/templates/swayimg/templates/default.mustache",
    "content": "[viewer]\nwindow = {{base00-hex}}\ntransparency = grid\nscale = optimal\nfixed = yes\nantialiasing = yes\nslideshow = no\nslideshow_time = 7\nhistory = 1\npreload = 1\n\n[gallery]\nsize = 200\ncache = 100\nfill = yes\nantialiasing = no\nwindow = {{base00-hex}}\nbackground = {{base00-hex}}\nselect = {{base06-hex}}\nborder = {{base0C-hex}}\nshadow = {{base03-hex}}\n\n[list]\norder = alpha\nloop = yes\nrecursive = no\nall = yes\n\n[font]\nname = monospace\nsize = 14\ncolor = {{base06-hex}}\nshadow = {{base03-hex}}\n"
  },
  {
    "path": ".config/flavours/templates/tmux/templates/config.yaml",
    "content": "default:\n  output: colors\n"
  },
  {
    "path": ".config/flavours/templates/tmux/templates/default.mustache",
    "content": "            custom_theme = {\n                text = {gui = \"#{{base00-hex}}\", cterm = \"235\", cterm16 = \"0\"},\n                normal = {gui = \"#{{base0D-hex}}\", cterm = \"109\", cterm16 = \"6\"},\n                insert = {gui = \"#{{base0B-hex}}\", cterm = \"142\", cterm16 = \"2\"},\n                replace = {gui = \"#{{base0A-hex}}\", cterm = \"214\", cterm16 = \"3\"},\n                inactive_comment = {gui = \"NONE\", cterm = \"NONE\", cterm16 = \"NONE\"},\n                inactive_cursor = {gui = \"NONE\", cterm = \"NONE\", cterm16 = \"NONE\"},\n                inactive_menu = {gui = \"NONE\", cterm = \"NONE\", cterm16 = \"NONE\"},\n                visual = {gui = \"#{{base0C-hex}}\", cterm = \"108\", cterm16 = \"6\"},\n                command = {gui = \"#{{base0E-hex}}\", cterm = \"132\", cterm16 = \"5\"},\n                alt_text = {gui = \"#{{base06-hex}}\", cterm = \"223\", cterm16 = \"7\"},\n                warning = {gui = \"#{{base08-hex}}\", cterm = \"167\", cterm16 = \"1\"},\n            },\n"
  },
  {
    "path": ".config/flavours/templates/waybar/templates/config.yaml",
    "content": "default:\n  extension: .css\n  output: colors\n"
  },
  {
    "path": ".config/flavours/templates/waybar/templates/default.mustache",
    "content": "/*\n*\n* Base16 {{scheme-name}}\n* Author: {{scheme-author}}\n*\n*/\n\n@define-color base00 #{{base00-hex}};\n@define-color base01 #{{base01-hex}};\n@define-color base02 #{{base02-hex}};\n@define-color base03 #{{base03-hex}};\n@define-color base04 #{{base04-hex}};\n@define-color base05 #{{base05-hex}};\n@define-color base06 #{{base06-hex}};\n@define-color base07 #{{base07-hex}};\n@define-color base08 #{{base08-hex}};\n@define-color base09 #{{base09-hex}};\n@define-color base0A #{{base0A-hex}};\n@define-color base0B #{{base0B-hex}};\n@define-color base0C #{{base0C-hex}};\n@define-color base0D #{{base0D-hex}};\n@define-color base0E #{{base0E-hex}};\n@define-color base0F #{{base0F-hex}};\n@define-color bg rgba({{base00-rgb-r}}, {{base00-rgb-g}}, {{base00-rgb-b}}, 0.90);\n@define-color accentDim rgba({{base0C-rgb-r}}, {{base0C-rgb-g}}, {{base0C-rgb-b}}, 0.35);\n"
  },
  {
    "path": ".config/flavours/templates/wayfire/templates/config.yaml",
    "content": "colors:\n    extension: .ini\n    output: colors\n"
  },
  {
    "path": ".config/flavours/templates/wayfire/templates/default.mustache",
    "content": "active_color = \\#{{base0C-hex}FF\ninactive_color = \\#{{base00-hex}}FF\n"
  },
  {
    "path": ".config/fontconfig/fonts.conf",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">\n<fontconfig>\n\n  <!-- Enable sub-pixel rendering for LCD screens -->\n  <match target=\"font\">\n    <edit mode=\"assign\" name=\"rgba\">\n      <const>rgb</const>\n    </edit>\n  </match>\n\n  <!-- Enable anti-aliasing for smoother font rendering -->\n  <match target=\"font\">\n    <edit mode=\"assign\" name=\"antialias\">\n      <bool>true</bool>\n    </edit>\n  </match>\n\n  <!-- Hint style can be set to hintfull, hintmedium, or hintslight -->\n  <match target=\"font\">\n    <edit mode=\"assign\" name=\"hintstyle\">\n      <const>hintfull</const>\n    </edit>\n  </match>\n\n  <!-- Subpixel hinting type can be set to rgb, bgr, vrgb, vbgr -->\n  <match target=\"font\">\n    <edit mode=\"assign\" name=\"hinting\" >\n      <bool>true</bool>\n    </edit>\n  </match>\n\n  <!-- Adjust the hinting strength for your preference -->\n  <match target=\"font\">\n    <edit mode=\"assign\" name=\"hinting-factors\">\n      <double>8</double>\n    </edit>\n  </match>\n\n  <!-- Set the default sans-serif font -->\n  <alias>\n    <family>sans-serif</family>\n    <prefer>\n      <family>Noto Sans</family>\n      <family>Ubuntu</family>\n    </prefer>\n  </alias>\n\n  <!-- Set the default serif font -->\n  <alias>\n    <family>serif</family>\n    <prefer>\n      <family>Noto Serif</family>\n    </prefer>\n  </alias>\n\n  <!-- Set the default monospace font -->\n  <alias>\n    <family>monospace</family>\n    <prefer>\n      <family>Cascadia Mono</family>\n      <family>Terminus (TTF)</family>\n      <family>Hack</family>\n      <family>Noto Sans Mono</family>\n      <family>Ubuntu Mono</family>\n    </prefer>\n  </alias>\n\n  <!-- Set the emoji font -->\n  <alias>\n    <family>emoji</family>\n    <prefer>\n      <family>Noto Color Emoji</family>\n      <family>Twemoji</family>\n    </prefer>\n  </alias>\n\n</fontconfig>\n"
  },
  {
    "path": ".config/gtk-2.0/gtkfilechooser.ini",
    "content": "[Filechooser Settings]\nLocationMode=path-bar\nShowHidden=true\nShowSizeColumn=true\nGeometryX=0\nGeometryY=0\nGeometryWidth=889\nGeometryHeight=662\nSortColumn=name\nSortOrder=ascending\nStartupMode=recent\n"
  },
  {
    "path": ".config/gtk-2.0/gtkrc-2.0",
    "content": "gtk-theme-name=\"Breeze\"\ngtk-icon-theme-name=\"Breeze\"\ngtk-font-name=\"Sans 11\"\ngtk-cursor-theme-name=\"Kaela-Kovalskia-v2\"\ngtk-cursor-theme-size=24\ngtk-toolbar-style=GTK_TOOLBAR_BOTH_HORIZ\ngtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR\ngtk-button-images=0\ngtk-menu-images=0\ngtk-enable-event-sounds=1\ngtk-enable-input-feedback-sounds=0\ngtk-xft-antialias=1\ngtk-xft-hinting=1\ngtk-xft-hintstyle=\"hintslight\"\ngtk-xft-rgba=\"rgb\"\n"
  },
  {
    "path": ".config/gtk-3.0/settings.ini",
    "content": "[Settings]\ngtk-button-images=1\ngtk-theme-name=Breeze\ngtk-icon-theme-name=Breeze\ngtk-font-name=Sans 11\ngtk-cursor-theme-name=Kaela-Kovalskia-v2\ngtk-cursor-theme-size=24\ngtk-decoration-layout=icon:minimize,maximize,close\ngtk-toolbar-style=GTK_TOOLBAR_BOTH_HORIZ\ngtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR\ngtk-menu-images=1\ngtk-enable-event-sounds=1\ngtk-enable-input-feedback-sounds=0\ngtk-xft-antialias=1\ngtk-xft-hinting=1\ngtk-xft-hintstyle=hintsmedium\ngtk-xft-rgba=rgb\ngtk-application-prefer-dark-theme=1\n"
  },
  {
    "path": ".config/gtk-4.0/settings.ini",
    "content": "[Settings]\ngtk-application-prefer-dark-theme=true\ngtk-theme-name=\"Breeze\"\ngtk-icon-theme-name=Breeze\ngtk-cursor-theme-name=Kaela-Kovalskia-v2\ngtk-cursor-theme-size=24\ngtk-can-change-accels=1\ngtk-xft-antialias=1\ngtk-xft-hinting=1\ngtk-xft-hintstyle=hintmedium\ngtk-xft-rgba=rgb\n"
  },
  {
    "path": ".config/htop/htoprc",
    "content": "# Beware! This file is rewritten by htop when settings are changed in the interface.\n# The parser is also very primitive, and not human-friendly.\nhtop_version=3.3.0\nconfig_reader_min_version=3\nfields=0 48 17 18 38 39 40 2 46 47 49 1\nhide_kernel_threads=1\nhide_userland_threads=1\nhide_running_in_container=1\nshadow_other_users=0\nshow_thread_names=0\nshow_program_path=1\nhighlight_base_name=1\nhighlight_deleted_exe=1\nshadow_distribution_path_prefix=0\nhighlight_megabytes=1\nhighlight_threads=1\nhighlight_changes=0\nhighlight_changes_delay_secs=5\nfind_comm_in_cmdline=1\nstrip_exe_from_cmdline=1\nshow_merged_command=0\nheader_margin=1\nscreen_tabs=1\ndetailed_cpu_time=0\ncpu_count_from_one=0\nshow_cpu_usage=1\nshow_cpu_frequency=0\nshow_cpu_temperature=1\ndegree_fahrenheit=0\nupdate_process_names=0\naccount_guest_in_cpu_meter=0\ncolor_scheme=0\nenable_mouse=1\ndelay=15\nhide_function_bar=0\ntopology_affinity=0\nheader_layout=two_50_50\ncolumn_meters_0=CPU Memory Swap NetworkIO\ncolumn_meter_modes_0=1 1 1 2\ncolumn_meters_1=Tasks LoadAverage Uptime DiskIO\ncolumn_meter_modes_1=2 2 2 2\ntree_view=0\nsort_key=47\ntree_sort_key=47\nsort_direction=-1\ntree_sort_direction=-1\ntree_view_always_by_pid=0\nall_branches_collapsed=0\nscreen:Main=PID USER PRIORITY NICE M_VIRT M_RESIDENT M_SHARE STATE PERCENT_CPU PERCENT_MEM TIME Command\n.sort_key=PERCENT_MEM\n.tree_sort_key=PERCENT_MEM\n.tree_view_always_by_pid=0\n.tree_view=0\n.sort_direction=-1\n.tree_sort_direction=-1\n.all_branches_collapsed=0\nscreen:I/O=PID USER IO_PRIORITY IO_RATE IO_READ_RATE IO_WRITE_RATE PERCENT_SWAP_DELAY PERCENT_IO_DELAY Command\n.sort_key=PID\n.tree_sort_key=PID\n.tree_view_always_by_pid=0\n.tree_view=0\n.sort_direction=1\n.tree_sort_direction=1\n.all_branches_collapsed=0\n"
  },
  {
    "path": ".config/mimeapps.list",
    "content": "[Added Associations]\nimage/gif=video.desktop;\napplication/zip=lxqt-archiver.desktop;\napplication/x-zerosize=text.desktop;\napplication/x-trash=text.desktop;\ninode/symlink=text.desktop;\napplication/xml=nvim.desktop;\napplication/x-executable=nvim.desktop;\nimage/webp=img.desktop;\nimage/png=img.desktop;\nimage/jpg=img.desktop;\nimage/jpeg=img.desktop;\n\n[Default Applications]\ntext/*=text.desktop;\napplication/x-shellscript=text.desktop;\napplication/octet-stream=text.desktop;\napplication/x-wine-extension-ini=text.desktop;\nimage/*=img.desktop;\nvideo/*=video.desktop;\naudio/*=video.desktop;\nx-scheme-handler/magnet=torrent.desktop;\napplication/x-bittorrent=torrent.desktop;\nx-scheme-handler/mailto=mail.desktop;\napplication/postscript=pdf.desktop;\napplication/pdf=pdf.desktop;\napplication/rss+xml=rss.desktop;\nx-scheme-handler/lbry=lbry.desktop;\ninode/directory=file.desktop;\napplication/xml=nvim.desktop;\nx-scheme-handler/http=browser.desktop\nx-scheme-handler/https=browser.desktop\nx-scheme-handler/about=browser.desktop;\nx-scheme-handler/unknown=browser.desktop;\ntext/html=browser.desktop\n"
  },
  {
    "path": ".config/mpv/input.conf",
    "content": "Ctrl+Shift+R write-watch-later-config ; loadfile ${path}\nF10 cycle_values video-rotate 90 180 270 0\nF11 cycle-values loop-playlist yes no\nF12 playlist-shuffle ; show-text \"${playlist}\" 4000\nAlt+P script-message save-playlist\n"
  },
  {
    "path": ".config/mpv/mpv.conf",
    "content": "# general\nhwdec=auto-safe\nhwdec-codecs=all\ndeband=no\ninterpolation=no\nvd-lavc-dr=yes\ndrag-and-drop=append\ninput-ipc-server=/tmp/mpvsocket\nscreenshot-directory=pictures\n\n# window\ngeometry=50%:50%\nautofit-larger=60%x60%\nautofit-smaller=60%x60%\n\n# video control\nkeep-open=yes\npause=yes\nvolume=50\n\n# cache\ncache=yes\ndemuxer-max-bytes=20480KiB\n\n# youtube-dl\nytdl-format=best[height<=?480]+bestaudio/best\nytdl-raw-options=no-check-certificate=\n\n# osd\nosd-playing-msg = '${filename}'\n[protocol.https]\nosd-playing-msg = '${media-title}'\nterm-playing-msg='$(media-title)'\n\n"
  },
  {
    "path": ".config/mpv/script-modules/user-input-module.lua",
    "content": "--[[\n    This is a module designed to interface with mpv-user-input\n    https://github.com/CogentRedTester/mpv-user-input\n\n    Loading this script as a module will return a table with two functions to format\n    requests to get and cancel user-input requests. See the README for details.\n\n    Alternatively, developers can just paste these functions directly into their script,\n    however this is not recommended as there is no guarantee that the formatting of\n    these requests will remain the same for future versions of user-input.\n]]\n\nlocal API_VERSION = \"0.1.0\"\n\nlocal mp = require 'mp'\nlocal msg = require \"mp.msg\"\nlocal utils = require 'mp.utils'\nlocal mod = {}\n\nlocal name = mp.get_script_name()\nlocal counter = 1\n\nlocal function pack(...)\n    local t = {...}\n    t.n = select(\"#\", ...)\n    return t\nend\n\nlocal request_mt = {}\n\n-- ensures the option tables are correctly formatted based on the input\nlocal function format_options(options, response_string)\n    return {\n        response = response_string,\n        version = API_VERSION,\n        id = name..'/'..(options.id or \"\"),\n        source = name,\n        request_text = (\"[%s] %s\"):format(options.source or name, options.request_text or options.text or \"requesting user input:\"),\n        default_input = options.default_input,\n        cursor_pos = tonumber(options.cursor_pos),\n        queueable = options.queueable and true,\n        replace = options.replace and true\n    }\nend\n\n-- cancels the request\nfunction request_mt:cancel()\n    assert(self.uid, \"request object missing UID\")\n    mp.commandv(\"script-message-to\", \"user_input\", \"cancel-user-input/uid\", self.uid)\nend\n\n-- updates the options for the request\nfunction request_mt:update(options)\n    assert(self.uid, \"request object missing UID\")\n    options = utils.format_json( format_options(options) )\n    mp.commandv(\"script-message-to\", \"user_input\", \"update-user-input/uid\", self.uid, options)\nend\n\n-- sends a request to ask the user for input using formatted options provided\n-- creates a script message to recieve the response and call fn\nfunction mod.get_user_input(fn, options, ...)\n    options = options or {}\n    local response_string = name..\"/__user_input_request/\"..counter\n    counter = counter + 1\n\n    local request = {\n        uid = response_string,\n        passthrough_args = pack(...),\n        callback = fn,\n        pending = true\n    }\n\n    -- create a callback for user-input to respond to\n    mp.register_script_message(response_string, function(response)\n        mp.unregister_script_message(response_string)\n        request.pending = false\n\n        response = utils.parse_json(response)\n        request.callback(response.line, response.err, unpack(request.passthrough_args, 1, request.passthrough_args.n))\n    end)\n\n    -- send the input command\n    options = utils.format_json( format_options(options, response_string) )\n    mp.commandv(\"script-message-to\", \"user_input\", \"request-user-input\", options)\n\n    return setmetatable(request, { __index = request_mt })\nend\n\n-- runs the request synchronously using coroutines\n-- takes the option table and an optional coroutine resume function\nfunction mod.get_user_input_co(options, co_resume)\n    local co, main = coroutine.running()\n    assert(not main and co, \"get_user_input_co must be run from within a coroutine\")\n\n    local uid = {}\n    local request = mod.get_user_input(function(line, err)\n        if co_resume then\n            co_resume(uid, line, err)\n        else\n            local success, er = coroutine.resume(co, uid, line, err)\n            if not success then\n                msg.warn(debug.traceback(co))\n                msg.error(er)\n            end\n        end\n    end, options)\n\n    -- if the uid was not sent then the coroutine was resumed by the user.\n    -- we will treat this as a cancellation request\n    local success, line, err = coroutine.yield(request)\n    if success ~= uid then\n        request:cancel()\n        request.callback = function() end\n        return nil, \"cancelled\"\n    end\n\n    return line, err\nend\n\n-- sends a request to cancel all input requests with the given id\nfunction mod.cancel_user_input(id)\n    id = name .. '/' .. (id or \"\")\n    mp.commandv(\"script-message-to\", \"user_input\", \"cancel-user-input/id\", id)\nend\n\nreturn mod"
  },
  {
    "path": ".config/mpv/scripts/delete-current-video.lua",
    "content": "local utils = require 'mp.utils'\n\nfunction delete_current_file()\n    local file_path = mp.get_property(\"path\")\n    if file_path == nil then\n        mp.msg.error(\"No file is currently loaded.\")\n        return\n    end\n\n    local args = {\"rm\", file_path}\n    local res = utils.subprocess({ args = args, cancellable = false })\n\n    if res.status == 0 then\n        mp.msg.info(\"Deleted file: \" .. file_path)\n        -- Move to the next file in the playlist\n        mp.command(\"playlist-next\")\n    else\n        mp.msg.error(\"Failed to delete file: \" .. file_path)\n    end\nend\n\nmp.register_command(\"delete-current\", delete_current_file, \"Delete the currently playing file.\")\n"
  },
  {
    "path": ".config/mpv/scripts/keep-session.lua",
    "content": "--[[\n    This script automatically saves the current playlist and can reload it if the player is started in idle mode (specifically\n    if there are 0 files in the playlist), or if the correct command is sent via script-messages.\n    It remembers the playlist position the player was in when shutdown and reloads the playlist at that entry.\n    This can be disabled with script-opts\n\n    The script saves a text file containing the previous session playlist in the watch_later directory (changeable via opts)\n    This file is saved in plaintext with the exact file paths of each playlist entry.\n    Note that since it uses the same file, only the latest mpv window to be closed will be saved\n\n    The script attempts to correct relative playlist paths using the utils.join_path function. I've tried to automatically\n    detect when any non-files are loaded (if it has the sequence :// in the path), so that it'll work with URLs\n\n    You can disable the automatic stuff and use script messages to load/save playlists as well\n\n    script-message save-session [session-file]\n    script-message reload-session [session-file] [load_playlist]\n\n    If not included `session-file` will use the default file specified in script-opts.\n    `load_playlist` controls whether the whole playlist should be restored or just the one file,\n    the value can be `yes` or `no`. If not included it defaults to the value of the `load_playlist` script opt.\n\n    available at: https://github.com/CogentRedTester/mpv-scripts\n]]--\n\nlocal mp = require 'mp'\nlocal utils = require 'mp.utils'\nlocal opt = require 'mp.options'\nlocal msg = require 'mp.msg'\n\nlocal o = {\n    --automatically save the prev session\n    auto_save = true,\n\n    --runs the script automatically when started in idle mode and no files are in the playlist\n    auto_load = true,\n\n    --reloads the full playlist from the previous session\n    --can be individually overwritten when sending script-messages\n    load_playlist = true,\n\n    --file path of the default session file\n    --save it as a .pls file to be able to open directly (though it will not maintain the playlist positions)\n    session_file = \"\",\n\n    --maintain position in the playlist\n    --does nothing if load_playlist is disabled\n    maintain_pos = true,\n}\n\nopt.read_options(o, 'keep_session', function() end)\n\n--sets the default session file to the watch_later directory or ~~/watch_later/\nif o.session_file == \"\" then\n    local watch_later = mp.get_property('watch-later-directory', \"\")\n    if watch_later == \"\" then watch_later = \"~~state/watch_later/\" end\n    if not watch_later:find(\"[/\\\\]$\") then watch_later = watch_later..'/' end\n\n    o.session_file = watch_later..\"prev-session\"\nend\nlocal save_file = mp.command_native({\"expand-path\", o.session_file})\n\n--saves the current playlist as a json string\nlocal function save_playlist(file)\n    if not file then file = save_file end\n    msg.verbose('saving current session to', file)\n\n    local playlist = mp.get_property_native('playlist')\n\n    if #playlist == 0 then\n        msg.verbose('session empty, aborting save')\n        return\n    end\n\n    local session = io.open(file, 'w')\n    if not session then return msg.error(\"Failed to write to file\", file) end\n\n    session:write(\"[playlist]\\n\")\n    session:write(mp.get_property('playlist-pos') .. \"\\n\")\n\n    local working_directory = mp.get_property('working-directory')\n    for _, v in ipairs(playlist) do\n        msg.debug('adding ' .. v.filename .. ' to playlist')\n\n        --if the file is available then it attempts to expand the path in-case of relative playlists\n        --presumably if the file contains a protocol then it shouldn't be expanded\n        if not v.filename:find(\"^%a*://\") then\n            v.filename = utils.join_path(working_directory, v.filename)\n            msg.debug('expanded path: ' .. v.filename)\n        end\n\n        session:write(\"File=\" .. v.filename .. \"\\n\")\n    end\n    session:close()\nend\n\n--turns the previous json string into a table and adds all the files to the playlist\nlocal function load_prev_session(file, load_playlist)\n    if not file or file == '' then file = save_file end\n\n    if load_playlist == 'yes' then load_playlist = true\n    elseif load_playlist == 'no' then load_playlist = false\n    else load_playlist = o.load_playlist end\n\n    --loads the previous session file\n    msg.verbose('loading previous session from', file)\n    local session = io.open(file, \"r+\")\n\n    --this should only occur when loading the script for the first time,\n    --or if someone manually deletes the previous session file\n    if session == nil or session:read() ~= \"[playlist]\" then\n        msg.verbose('no previous session, cancelling load')\n        if session then session:close() end\n        return\n    end\n\n    local previous_playlist_pos = session:read('*n')\n\n    if load_playlist then\n        msg.debug('reloading playlist')\n\n        if not o.maintain_pos then\n            mp.commandv('loadlist', file)\n        else\n            local prev_playlist_start = mp.get_property('playlist-start')\n            msg.verbose(\"restoring playlist position\", previous_playlist_pos)\n            mp.set_property_number('playlist-start', previous_playlist_pos)\n\n            mp.commandv('loadlist', file)\n\n            -- restore the original value unless the `playlist-start` property has been otherwise modified\n            if mp.get_property_number('playlist-start') ~= previous_playlist_pos then\n                mp.set_property('playlist-start', prev_playlist_start)\n            end\n        end\n    else\n        msg.debug('discarding playlist')\n        local files = {}\n        for line in session:lines() do\n            table.insert(files, string.match(line, 'File=(.+)'))\n        end\n\n        -- mpv and keep-session uses 0 based array indices, but lua uses 1-based\n        mp.commandv('loadfile', files[previous_playlist_pos+1])\n    end\n\n    session:close()\nend\n\nlocal function shutdown()\n    if o.auto_save then\n        save_playlist()\n    end\nend\n\nmp.register_script_message('save-session', save_playlist)\nmp.register_script_message('reload-session', load_prev_session)\nmp.register_event('shutdown', shutdown)\n\n--Load the previous session if auto_load is enabled and the playlist is empty\n--the function is not called until the first property observation is triggered to let everything initialise\n--otherwise modifying playlist-start becomes unreliable\nif o.auto_load and (mp.get_property_number('playlist-count', 0) == 0) then\n    local function temp()\n        load_prev_session()\n        mp.unobserve_property(temp)\n    end\n    mp.observe_property(\"idle\", \"string\", temp)\nend\n"
  },
  {
    "path": ".config/mpv/scripts/mpv-scut.lua",
    "content": "local start_time = nil\nlocal segments = {}\nlocal osd_message_id = nil\nlocal osd_persistent = false\nlocal segments_file_path = nil\n\n-- Get the path for the segments file based on the video file name\nfunction getSegmentsFilePath()\n    local input_file = mp.get_property(\"path\")\n    input_file = mp.command_native({\"expand-path\", input_file})\n    local file_dir = input_file:match(\"(.*/)\")\n    local file_name = input_file:match(\"([^/]+)%.%w+$\")\n    return string.format(\"%s/%s_segments.txt\", file_dir, file_name)\nend\n\n-- Start segment at the current playback position\nfunction startSegment()\n    start_time = mp.get_property_number(\"time-pos\")\n    osd_persistent = true\n    osd_message_id = mp.osd_message(\"Segment start point set\")\nend\n\n-- End segment at the current playback position\nfunction endSegment()\n    local end_time = mp.get_property_number(\"time-pos\")\n    if start_time then\n        table.insert(segments, {start = start_time, stop = end_time})\n        start_time = nil\n        osd_persistent = true\n        osd_message_id = mp.osd_message(\"Segment end point set\")\n    else\n        osd_persistent = false\n        osd_message_id = mp.osd_message(\"No start point set\")\n    end\nend\n\n-- Save segments to file\nfunction saveSegmentsToFile()\n    if #segments == 0 then\n        osd_persistent = false\n        osd_message_id = mp.osd_message(\"No segments to save\")\n        return\n    end\n\n    segments_file_path = getSegmentsFilePath()\n    local segments_file = io.open(segments_file_path, \"w\")\n    if not segments_file then\n        osd_persistent = false\n        osd_message_id = mp.osd_message(\"Failed to create segments file\")\n        return\n    end\n\n    for _, segment in ipairs(segments) do\n        segments_file:write(string.format(\"%s,%s\\n\", segment.start, segment.stop))\n    end\n    segments_file:close()\n    osd_persistent = true\n    osd_message_id = mp.osd_message(\"Segments saved to file\")\nend\n\n-- Load segments from file\nfunction loadSegmentsFromFile()\n    segments_file_path = getSegmentsFilePath()\n    local segments_file = io.open(segments_file_path, \"r\")\n    if not segments_file then\n        osd_persistent = false\n        osd_message_id = mp.osd_message(\"Failed to read segments file\")\n        return\n    end\n\n    segments = {}\n    for line in segments_file:lines() do\n        local start, stop = line:match(\"([^,]+),([^,]+)\")\n        table.insert(segments, {start = tonumber(start), stop = tonumber(stop)})\n    end\n    segments_file:close()\nend\n\n-- Process segments (cut and merge)\nfunction processSegments()\n    if #segments == 0 then\n        osd_persistent = false\n        osd_message_id = mp.osd_message(\"No segments to process\")\n        return\n    end\n\n    saveSegmentsToFile()\n\n    local input_file = mp.get_property(\"path\")\n    input_file = mp.command_native({\"expand-path\", input_file})\n    local file_dir = input_file:match(\"(.*/)\")\n    local file_name = input_file:match(\"([^/]+)%.%w+$\")\n    if not file_dir or not file_name then\n        osd_persistent = false\n        osd_message_id = mp.osd_message(\"Failed to determine video directory or file name\")\n        return\n    end\n\n    for i, segment in ipairs(segments) do\n        local segment_file = string.format(\"%s/%s_segment_%d.mp4\", file_dir, file_name, i)\n        local command = string.format('ffmpeg -i \"%s\" -ss %s -to %s -c copy \"%s\"', input_file, segment.start, segment.stop, segment_file)\n        print(\"Executing command:\", command)\n        os.execute(command)\n    end\n\n    local concat_file_path = string.format(\"%s/%s_concat.txt\", file_dir, file_name)\n    local concat_file = io.open(concat_file_path, \"w\")\n    if not concat_file then\n        osd_persistent = false\n        osd_message_id = mp.osd_message(\"Failed to create concat file\")\n        return\n    end\n\n    for i, _ in ipairs(segments) do\n        local segment_file = string.format(\"%s_segment_%d.mp4\", file_name, i)\n        concat_file:write(string.format(\"file '%s'\\n\", segment_file))\n    end\n    concat_file:close()\n\n    local output_file = string.format(\"%s/%s_merged.mp4\", file_dir, file_name)\n    local concat_command = string.format('ffmpeg -f concat -safe 0 -i \"%s\" -c copy \"%s\"', concat_file_path, output_file)\n    print(\"Executing concat command:\", concat_command)\n    osd_persistent = true\n    osd_message_id = mp.osd_message(\"Merging segments...\")\n    os.execute(concat_command)\n    osd_message_id = mp.osd_message(\"Segments merged\")\n\n    os.remove(concat_file_path)\n    for i, _ in ipairs(segments) do\n        local segment_file = string.format(\"%s/%s_segment_%d.mp4\", file_dir, file_name, i)\n        os.remove(segment_file)\n    end\n\n    osd_persistent = false\n    osd_message_id = mp.osd_message(\"Segments processed, temporary files deleted\")\nend\n\n-- Retry processing segments using the segments file\nfunction retryProcessSegments()\n    loadSegmentsFromFile()\n    processSegments()\nend\n\n-- Update OSD message if persistent\nfunction updateOSDMessage(message)\n    if osd_persistent then\n        osd_message_id = mp.osd_message(message, osd_message_id)\n    end\nend\n\n-- Key bindings\nmp.add_key_binding(\"c\", \"start_segment\", startSegment)\nmp.add_key_binding(\"x\", \"end_segment\", endSegment)\nmp.add_key_binding(\"z\", \"process_segments\", processSegments)\nmp.add_key_binding(\"r\", \"retry_process_segments\", retryProcessSegments)\nmp.add_key_binding(\"s\", \"save_segments_to_file\", saveSegmentsToFile)\n\n-- Clear OSD on shutdown\nmp.register_event(\"shutdown\", function()\n    if osd_message_id then\n        mp.osd_message(\"\")\n    end\nend)\n\n-- Periodic OSD update\nmp.add_periodic_timer(0.5, function()\n    if osd_persistent and start_time then\n        updateOSDMessage(\"Segment in progress...\")\n    end\nend)\n\n"
  },
  {
    "path": ".config/mpv/scripts/mpv-splice.lua",
    "content": "-- -----------------------------------------------------------------------------\n--\n-- MPV Splice\n-- URL: https://github.com/pvpscript/mpv-video-splice\n--\n-- Requires: ffmpeg\n--\n-- Description:\n--\n-- This script provides the hability to create video slices by grabbing two\n-- timestamps, which generate a slice from timestamp A[i] to timestamp B[i],\n-- e.g.:\n-- \t-> Slice 1: 00:10:34.25 -> 00:15:00.00.\n-- \t-> Slice 2: 00:23:00.84 -> 00:24:10.00.\n-- \t...\n-- \t-> Slice n: 01:44:22.47 -> 01:56:00.00.\n--\n-- Then, all the slices from 1 to n are joined together, creating a new\n-- video.\n--\n-- The output file will appear at the directory that the mpv command was ran,\n-- or in the environment variable set for it (see Environment variables below)\n--\n-- Note: This script prevents the mpv player from closing when the video ends,\n-- so that the slices don't get lost. Keep this in mind if there's the option\n-- 'keep-open=no' in the current config file.\n--\n-- Note: This script will also silence the terminal, so the script messages\n-- can be seen more clearly.\n--\n-- -----------------------------------------------------------------------------\n--\n--\n-- Usage:\n--\n-- In the video screen, press Alt + T to grab the first timestamp and then\n-- press Alt + T again to get the second timestamp. This process will generate\n-- a time range, which represents a video slice. Repeat this process to create\n-- more slices.\n--\n-- To see all the slices made, press Alt + P. All of the slices will appear\n-- in the terminal in order of creation, with their corresponding timestamps.\n-- Incomplete slices will show up as 'Slice N in progress', where N is the\n-- slice number.\n--\n-- To reset an incomplete slice, press Alt + R. If the first part of a slice\n-- was created at the wrong time, this will reset the current slice.\n--\n-- To delete a whole slice, start the slice deletion mode by pressing Alt + D.\n-- When in this mode, it's possible to press Alt + NUM, where NUM is any\n-- number between 0 inclusive and 9 inclusive. For each Alt + NUM pressed, a\n-- number will be concatenated to make the final number referring to the slice\n-- to be removed, then press Alt + D again to stop the slicing deletion mode\n-- and delete the slice corresponding to the formed number.\n--\n-- Example 1: Deleting slice number 3\n-- \t-> Alt + D \t# Start slice deletion mode\n-- \t-> Alt + 3\t# Concatenate number 3\n-- \t-> Alt + D\t# Exit slice deletion mode\n--\n-- Example 2> Deleting slice number 76\n-- \t-> Alt + D \t# Start slice deletion mode\n-- \t-> Alt + 7\t# Concatenate number 7\n-- \t-> Alt + 6\t# Concatenate number 6\n-- \t-> Alt + D\t# Exit slice deletion mode\n--\n-- To fire up ffmpeg, which will slice up the video and concatenate the slices\n-- together, press Alt + C. It's important that there are at least one\n-- slice, otherwise no video will be created.\n--\n-- Note: No cut will be made unless the user presses Alt + C.\n-- Also, the original video file won't be affected by the cutting.\n--\n--\n-- -----------------------------------------------------------------------------\n--\n--\n-- Log level:\n--\n-- Everytime a timestamp is grabbed, a text will appear on the screen showing\n-- the selected time.\n-- When Alt + P is pressed, besides showing the slices in the terminal,\n-- it will also show on the screen the total number of cuts (or slices)\n-- that were made.\n-- When the actual cutting and joining process begins, a message will be shown\n-- on the screen and the terminal telling that it began. When the process ends,\n-- a message will appear on the screen and the terminal displaying the full path\n-- of the generated video. It will also appear a message in the terminal telling\n-- that the process ended.\n--\n-- Note: Every message that appears on the terminal has the log level of 'info'.\n--\n--\n-- -----------------------------------------------------------------------------\n--\n--\n-- Environment Variables:\n--\n-- This script uses environment variables to allow the user to\n-- set the temporary location of the video cuts and for setting the location for\n-- the resulting video.\n--\n-- To set the temporary directory, set the variable MPV_SPLICE_TEMP;\n-- e.g.: export MPV_SPLICE_TEMP=\"$HOME/temporary_location\"\n--\n-- To set the video output directory, set the variable MPV_SPLICE_OUTPUT;\n-- e.g.: export MPV_SPLICE_OUTPUT=\"$HOME/output_location\"\n--\n-- Make sure the directories set in the variables really exist, or else the\n-- script might fail.\n--\n-- -----------------------------------------------------------------------------\n\n--------------------------------------------------------------------------------\n-- Importing the mpv libraries\n\nlocal mp = require 'mp'\nlocal msg = require 'mp.msg'\nlocal opt = require 'mp.options'\nlocal utils = require 'mp.utils'\n\n--------------------------------------------------------------------------------\n-- Setup os dependent stuff\n\n-- Not the best way to check OS, but it should work\nlocal _os = package.config:sub(1, 1) == \"/\" and \"unix\" or \"windows\"\n\nlocal _default_output_path = mp.get_property(\"working-directory\")\n\nsystem_dependent = {\n    default_output_path = _os == \"unix\"\n                                 and _default_output_path\n                                 or _default_output_path:gsub(\"\\\\\", \"/\"),\n\n    tmp_path = _os == \"unix\"\n                      and \"/tmp\"\n                      or string.format(\"%s/Temp\", os.getenv(\"LOCALAPPDATA\"):gsub(\"\\\\\", \"/\")),\n\n    mkdir = _os == \"unix\" and \"mkdir\" or \"md\",\n\n    rm = _os == \"unix\" and \"rm -rf\" or \"rd /s /q\",\n}\n\n--------------------------------------------------------------------------------\n-- Setup config\n\nlocal SCRIPT_NAME = \"mpv-splice\"\n\nlocal config = {\n    concat_file_name = \"concat\",\n\n    ffmpeg_cmd = \"ffmpeg -hide_banner -loglevel warning\",\n    ffmpeg_filter = \"-c copy -copyts -avoid_negative_ts make_zero\",\n\n    tmp_path = system_dependent.tmp_path,\n    output_path = system_dependent.default_output_path,\n}\nopt.read_options(config, SCRIPT_NAME)\n\n--------------------------------------------------------------------------------\n\nlocal function notify(message, duration)\n\tlocal duration = duration or 2\n\n\tmsg.info(message)\n\tmp.osd_message(message, duration)\nend\n\nlocal function seconds_to_clock(secs)\n\tlocal hours = math.floor(secs / 3600)\n\tlocal mins = math.floor((secs - hours * 3600) / 60)\n\tlocal secs = secs - hours * 3600 - mins * 60\n\n    return {\n        h = hours,\n        m = mins,\n        s = secs,\n    }\nend\n\nlocal function current_timestamp()\n\tlocal seconds = mp.get_property_number('time-pos')\n    local time_data = seconds_to_clock(seconds)\n\n\treturn string.format('%02d:%02d:%05.2f', time_data.h, time_data.m, time_data.s)\nend\n\nslice_data = {\n    _start_timestamp_message = \"[START TIMESTAMP]\",\n    _end_timestamp_message = \"[END TIMESTAMP]\",\n\n    _timestamps = {},\n    _pieces = function(self)\n        return #self._timestamps\n    end,\n    pieces = function(self)\n        return self:_pieces()\n    end,\n\n    remove = {\n        _ongoing = false,\n        to_be_removed = \"\",\n\n        append = function(self, value)\n            self.to_be_removed = self.to_be_removed .. value\n        end,\n\n        is_ongoing = function(self)\n            return self._ongoing\n        end,\n\n        is_empty = function(self)\n            return self.to_be_removed == \"\"\n        end,\n\n        set_ongoing = function(self)\n            self._ongoing = true\n        end,\n\n        clear = function(self)\n            self._ongoing = false\n            self.to_be_removed = \"\"\n\n            notify(\"Exited slice deletion mode.\")\n        end,\n    },\n\n    _pairs = function(self)\n        return math.floor(self:_pieces() / 2)\n    end,\n\n    _has_incomplete_slice = function(self)\n        return not (self:_pieces() % 2 == 0)\n    end,\n\n    _put_time = function(self, value)\n        table.insert(self._timestamps, value)\n    end,\n\n    _add_piece = function(self, timestamp)\n        self:_put_time(timestamp)\n\n        local message = self:_has_incomplete_slice()\n                        and self._start_timestamp_message\n                        or self._end_timestamp_message\n\n        notify(message)\n    end,\n\n    _as_pairs_coroutine_handler = nil,\n    _as_pairs_coroutine_create = function(self)\n        local function _as_pairs_coroutine_closure(self)\n            local pair = 1\n\n            for piece = 1, self:_pieces(), 2 do\n                coroutine.yield({\n                    index = pair,\n                    p_start = self._timestamps[piece],\n                    p_end = self._timestamps[piece + 1],\n                })\n\n                pair = pair + 1\n            end\n        end\n\n        self._as_pairs_coroutine_handler =\n            coroutine.create(_as_pairs_coroutine_closure)\n    end,\n\n    as_pairs = function(self)\n        self:_as_pairs_coroutine_create()\n\n        return function()\n            local _, ret = coroutine.resume(self._as_pairs_coroutine_handler, self)\n            return ret\n        end\n    end,\n\n    add_time = function(self)\n        local timestamp = current_timestamp()\n\n        slice_data:_add_piece(timestamp)\n    end,\n    \n    show_timestamps = function(self)\n        notify(string.format(\"Total cuts: %d\", self:_pairs()))\n\n        local pair = 1\n\n        for piece = 1, self:_pieces(), 2 do\n            local t_start = self._timestamps[piece]\n            local t_end = self._timestamps[piece + 1]\n\n            msg.info(string.format(\"Slice %d: %s -> %s\", pair, t_start, t_end))\n\n            pair = pair + 1\n        end\n\n        if self:_has_incomplete_slice() then\n            notify(string.format(\"Slice %d in progress.\", self:_pairs() + 1))\n        end\n    end,\n\n    reset_current_slice = function(self)\n        if self:_has_incomplete_slice() then\n            notify(string.format(\"Slice %d reset.\", self:_pairs() + 1))\n            \n            table.remove(self._timestamps)\n        end\n    end,\n\n    remove_slice = function(self)\n        local pair_index = tonumber(self.remove.to_be_removed)\n        local piece_index = pair_index * 2 - 1\n\n        if pair_index > 0 and pair_index <= self:_pairs() then\n            table.remove(self._timestamps, piece_index)\n            table.remove(self._timestamps, piece_index)\n\n            notify(string.format(\"Removed slice %d\", pair_index))\n        end\n    end,\n\n    add_number_key_bindings = function(self)\n        -- Add shortcut keys to the interval {0..9}.\n        for i = 0, 9, 1 do\n            local key_code = \"Alt+\" .. i\n            local binding_name = \"num_key_\" .. i\n            local key_action = function()\n                self.remove:append(i)\n                notify(string.format(\"Slice to remove: %d\", self.remove.to_be_removed), 1)\n            end\n\n            mp.add_key_binding(key_code, binding_name, key_action)\n        end\n    end,\n\n    remove_number_key_bindings = function(self)\n        for i = 0, 9, 1 do\n            mp.remove_key_binding(\"num_key_\" .. i)\n        end\n    end,\n\n    delete_slice = function(self, index)\n        if not self.remove:is_ongoing() then\n            self.remove:set_ongoing()\n\n            notify(\"Entered slice deletion mode.\")\n\n            self:add_number_key_bindings()\n        elseif self.remove:is_ongoing() and self.remove:is_empty() then\n            self.remove:clear()\n        else\n            self:remove_number_key_bindings()\n            self:remove_slice()\n            self.remove:clear()\n        end\n    end,\n}\n\nlocal quit = {\n    _exit_count = 0,\n\n    prevent_quit = function(self, pieces, name)\n        if pieces > 0 then\n            if self._exit_count >= 1 then\n                mp.command(name)\n            else\n                notify(\"There are timestamp pieces set. Press again to quit.\", 3)\n                self._exit_count = self._exit_count + 1\n            end\n        else\n            mp.command(name)\n        end\n    end,\n}\n\nlocal random = {\n    alphabet = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\",\n\n    _started = false,\n\n\t-- Better seed randomization\n    _first_startup = function(self)\n        if not self._started then\n            math.randomseed(os.time())\n            for i = 1, 3, 1 do\n                math.random()\n            end\n\n            self._started = true\n        end\n    end,\n\n    random_string = function(self, size)\n        self:_first_startup()\n\n        local rnd_str = \"\"\n\n        for i = 1, size, 1 do\n            local rnd_index = math.floor(math.random() * #self.alphabet + 0.5)\n            rnd_str = rnd_str .. self.alphabet:sub(rnd_index, rnd_index)\n        end\n\n        return rnd_str\n    end,\n}\n\nconcat_file = {\n    _path = nil,\n    _handler = nil,\n\n    _create_file_path = function(self, tmp_path, name)\n        local name = name or \"concat\"\n        local file_name = string.format(\"%s.txt\", name)\n\n        return utils.join_path(tmp_path, file_name)\n    end,\n\n    get_path = function(self)\n        return self._path\n    end,\n\n    create = function(self, tmp_path, name)\n        self._path = self:_create_file_path(tmp_path, name)\n        self._handler = io.open(self._path, \"w\")\n    end,\n\n    add_file = function(self, path)\n        local path_line = string.format(\"file '%s'\\n\", path)\n\n        self._handler:write(path_line)\n    end,\n\n    close = function(self)\n        self._handler:close()\n    end,\n}\n\n--------------------------------------------------------------------------------\n\nlocal function add_time()\n    slice_data:add_time()\nend\n\nlocal function show_timestamps()\n    slice_data:show_timestamps()\nend\n\nlocal function reset_current_slice()\n    slice_data:reset_current_slice()\nend\n\nlocal function delete_slice()\n    slice_data:delete_slice()\nend\n\n--------------------------------------------------------------------------------\n\nlocal function file_info()\n    local path = mp.get_property('path')\n    local name = mp.get_property('filename')\n    local name_without_ext = mp.get_property('filename/no-ext')\n\n    local ext = name == name_without_ext\n                and \"\"\n                or string.gsub(name, '.*%.(.*)$', '%1')\n\n    return {\n        path = path,\n        full_name = name,\n        name_only = name_without_ext,\n        ext = ext\n    }\nend\n\nlocal function make_temp_dir(tmp_path)\n    local tmp_path_name = string.format(\n        \"%s_%s\",\n        \"video-splice-tmp\", random:random_string(10)\n    )\n    local full_tmp_path = utils.join_path(tmp_path, tmp_path_name)\n\n    local mkdir_cmd = string.format(\n        \"%s \\\"%s\\\" 2>&1\",\n        system_dependent.mkdir, full_tmp_path\n    )\n\n    local handler = io.popen(mkdir_cmd)\n    local cmd_output = handler:read(\"*l\")\n\n    handler:close()\n\n    if cmd_output ~= nil then\n        error(cmd_output)\n    end\n\n    return full_tmp_path\nend\n\nlocal function output_file_path(file_name, ext)\n    local random_string = random:random_string(10)\n    local output_file = string.format(\n        \"%s_%s_cut.%s\",\n        file_name, random_string, ext\n    )\n\n    return utils.join_path(config.output_path, output_file)\nend\n\nlocal function make_cut_path(tmp_path, piece_index, ext)\n    local random_string = random:random_string(10)\n\n    local file_name = string.format(\n        \"slice_%s_%d.%s\",\n        random_string, piece_index, ext\n    )\n\n    return utils.join_path(tmp_path, file_name)\nend\n\nlocal function run_ffmpeg_cut(piece, input_file_path, output_cut_path)\n    local cmd = string.format(\n        \"%s -ss %s -i \\\"%s\\\" -to %s %s %s\",\n        config.ffmpeg_cmd,\n        piece.p_start, input_file_path, piece.p_end,\n        config.ffmpeg_filter,\n        output_cut_path\n    )\n\n    os.execute(cmd)\nend\n\nlocal function make_timestamp_cuts(tmp_path, curr_file_path, curr_file_ext)\n    for piece in slice_data:as_pairs() do\n        local cut_path = make_cut_path(tmp_path, piece.index, curr_file_ext)\n\n        run_ffmpeg_cut(piece, curr_file_path, cut_path)\n        concat_file:add_file(cut_path)\n    end\n\n    concat_file:close()\nend\n\nlocal function concat_pieces(cat_file_path, output_file)\n    cmd = string.format(\n        \"%s -f concat -safe 0 -i \\\"%s\\\" -c copy \\\"%s\\\"\",\n        config.ffmpeg_cmd, cat_file_path, output_file\n    )\n    os.execute(cmd)\nend\n\nlocal function cleanup(path)\n    cmd = string.format(\n        \"%s \\\"%s\\\"\",\n        system_dependent.rm, path\n    )\n    os.execute(cmd)\n\n    msg.info(string.format(\"Directory \\\"%s\\\" removed!\", path))\nend\n\nfunction process_video()\n    local file_info = file_info()\n    local output_file = output_file_path(file_info.name_only, file_info.ext)\n    local tmp_path = make_temp_dir(config.tmp_path)\n\n    -- Make concat file\n    concat_file:create(tmp_path, config.concat_file_name)\n\n    notify(\"Process started!\")\n\n    -- Make timestamp cuts\n    make_timestamp_cuts(tmp_path, file_info.path, file_info.ext)\n\n    -- Make the concat cmd, using the concat.txt file\n    concat_pieces(concat_file:get_path(), output_file)\n\n    notify(string.format(\"File saved as: %s\", output_file), 10)\n    msg.info(\"Process ended!\")\n\n    -- Cleanup\n    cleanup(tmp_path)\nend\n\nmp.set_property(\"keep-open\", \"yes\") -- Prevent mpv from exiting when the video ends\nmp.set_property(\"quiet\", \"yes\") -- Silence terminal.\n\nmp.add_key_binding('q', \"quit\", function()\n\tquit:prevent_quit(slice_data:pieces(), \"quit\")\nend)\nmp.add_key_binding('Shift+q', \"quit-watch-later\", function()\n\tquit:prevent_quit(slice_data:pieces(), \"quit-watch-later\")\nend)\n\nmp.add_key_binding('Alt+t', \"put_time\", add_time)\nmp.add_key_binding('Alt+p', \"show_times\", show_timestamps)\nmp.add_key_binding('Alt+c', \"process_video\", process_video)\nmp.add_key_binding('Alt+r', \"reset_current_slice\", reset_current_slice)\nmp.add_key_binding('Alt+d', \"delete_slice\", delete_slice)\n"
  },
  {
    "path": ".config/mpv/scripts/playlist-shuffle.lua",
    "content": "--[[\n    shuffles the playlist and moves the currently playing file to the start of the playlist\n    available at: https://github.com/CogentRedTester/mpv-scripts\n]]--\n\nfunction main()\n    mp.command('playlist-shuffle')\n\n    local pos = mp.get_property_number('playlist-pos')\n\n    mp.commandv('playlist-move', pos, 0)\n    mp.osd_message('playlist shuffled')\nend\n\nmp.register_script_message('playlist-shuffle', main)"
  },
  {
    "path": ".config/mpv/scripts/save-playlist.lua",
    "content": "--[[\n    A script for saving m3u playlists based on mpvs current internal playlist.\n    Users can set the name and directory to save the file in the initial script message,\n    or can enter custom strings in the osd.\n    Available at: https://github.com/CogentRedTester/mpv-scripts\n\n    To support requesting user input this script requires that the script mpv-user-input be\n    loaded by mpv in the ~~/scripts directory, and that user-input-module is in the ~~/script-modules directory.\n    mpv-user-input is available here: https://github.com/CogentRedTester/mpv-user-input\n\n    Syntax:\n        script-message save-playlist [directory] [filename] [flags]\n\n        If the directory and/or filename are missing, or are empty strings, then the user will be\n        prompted for input. The filename will be appended with the .m3u extension.\n        The flags are a string of options\n\n    Flags:\n        Currently there is only one flag: `relative`\n        When relative is passed to the script the playlist will use paths relative to the saved playlist.\n        This is currently very primitive, and only works with files that are children of the save directory.\n]]--\n\nlocal mp = require \"mp\"\nlocal msg = require \"mp.msg\"\nlocal utils = require \"mp.utils\"\n\nlocal input = dofile(mp.command_native({\"expand-path\", \"~~/script-modules/user-input-module.lua\"}))\nlocal working = mp.get_property(\"working-directory\", \"\")\n\nlocal function save_playlist(directory, name, relative)\n    if not directory or not name then return end\n    directory = mp.command_native({\"expand-path\", directory})\n    local path = directory..\"/\"..name..\".m3u\"\n    local file = io.open(path, \"w\")\n    if not file then msg.error(\"could not open file '\"..path..\"' for writing\") ; return end\n\n    local playlist = mp.get_property_native(\"playlist\")\n    for _, item in ipairs(playlist) do\n        local path = item.filename\n\n        if not path:find(\"^%a+://\") then\n            path = utils.join_path(working, path)\n            path = path:gsub(\"\\\\\", \"/\")\n            path = path:gsub(\"/./\", \"/\")\n\n            if relative then\n                local _, finish = path:find(directory, 1, true)\n                if finish then path = path:sub(finish+1) end\n            end\n        end\n\n        msg.verbose(\"wrote\", '\"'..path..'\"', \"to playlist\")\n        file:write(path..\"\\n\")\n    end\n    msg.info(\"Saved\", #playlist, \"files to\", '\"'..directory..'\"')\n    mp.osd_message(\"Saved \"..(#playlist)..\" files to playlist\")\n    file:close()\nend\n\nlocal function handle_save_request(directory, name, relative)\n    local need_dir = not directory or directory == \"\"\n    local need_name = not name or name == \"\"\n    relative = relative == \"relative\"\n\n    if need_dir then\n        input.get_user_input(function(res)\n            if not need_name then save_playlist(res, name, relative)\n            else directory = res end\n        end, {id = \"dir\", text = \"Enter save directory:\"})\n    end\n\n    if need_name then\n        input.get_user_input(function(res)\n            save_playlist(directory, res, relative)\n        end, {id = \"name\", text = \"Enter playlist name:\"})\n    end\nend\n\nmp.add_key_binding(\"Ctrl+p\", \"save-playlist\", handle_save_request)\n"
  },
  {
    "path": ".config/mpv/scripts/user-input.lua",
    "content": "local mp = require 'mp'\nlocal msg = require 'mp.msg'\nlocal utils = require 'mp.utils'\nlocal options = require 'mp.options'\n\n-- Default options\nlocal opts = {\n    -- All drawing is scaled by this value, including the text borders and the\n    -- cursor. Change it if you have a high-DPI display.\n    scale = 1,\n    -- Set the font used for the REPL and the console. This probably doesn't\n    -- have to be a monospaced font.\n    font = \"\",\n    -- Set the font size used for the REPL and the console. This will be\n    -- multiplied by \"scale.\"\n    font_size = 16,\n}\n\noptions.read_options(opts, \"user_input\")\n\nlocal API_VERSION = \"0.1.0\"\nlocal API_MAJOR_MINOR = API_VERSION:match(\"%d+%.%d+\")\n\nlocal co = nil\nlocal queue  = {}\nlocal active_ids = {}\nlocal histories = {}\nlocal request = nil\n\nlocal line = ''\n\n\n--[[\n    The below code is a modified implementation of text input from mpv's console.lua:\n    https://github.com/mpv-player/mpv/blob/7ca14d646c7e405f3fb1e44600e2a67fc4607238/player/lua/console.lua\n\n    Modifications:\n        removed support for log messages, sending commands, tab complete, help commands\n        removed update timer\n        Changed esc key to call handle_esc function\n        handle_esc and handle_enter now resume the main coroutine with a response table\n        made history specific to request ids\n        localised all functions - reordered some to fit\n        keybindings use new names\n]]--\n\n------------------------------START ORIGINAL MPV CODE-----------------------------------\n----------------------------------------------------------------------------------------\n----------------------------------------------------------------------------------------\n----------------------------------------------------------------------------------------\n----------------------------------------------------------------------------------------\n\n-- Copyright (C) 2019 the mpv developers\n--\n-- Permission to use, copy, modify, and/or distribute this software for any\n-- purpose with or without fee is hereby granted, provided that the above\n-- copyright notice and this permission notice appear in all copies.\n--\n-- THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n-- SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION\n-- OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\n-- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\nlocal assdraw = require 'mp.assdraw'\n\nlocal function detect_platform()\n    local o = {}\n    -- Kind of a dumb way of detecting the platform but whatever\n    if mp.get_property_native('options/vo-mmcss-profile', o) ~= o then\n        return 'windows'\n    elseif mp.get_property_native('options/macos-force-dedicated-gpu', o) ~= o then\n        return 'macos'\n    elseif os.getenv('WAYLAND_DISPLAY') then\n        return 'wayland'\n    end\n    return 'x11'\nend\n\n-- Pick a better default font for Windows and macOS\nlocal platform = detect_platform()\nif platform == 'windows' then\n    opts.font = 'Consolas'\nelseif platform == 'macos' then\n    opts.font = 'Menlo'\nelse\n    opts.font = 'monospace'\nend\n\nlocal repl_active = false\nlocal insert_mode = false\nlocal cursor = 1\nlocal key_bindings = {}\nlocal global_margin_y = 0\n\n-- Escape a string for verbatim display on the OSD\nlocal function ass_escape(str)\n    -- There is no escape for '\\' in ASS (I think?) but '\\' is used verbatim if\n    -- it isn't followed by a recognised character, so add a zero-width\n    -- non-breaking space\n    str = str:gsub('\\\\', '\\\\\\239\\187\\191')\n    str = str:gsub('{', '\\\\{')\n    str = str:gsub('}', '\\\\}')\n    -- Precede newlines with a ZWNBSP to prevent ASS's weird collapsing of\n    -- consecutive newlines\n    str = str:gsub('\\n', '\\239\\187\\191\\\\N')\n    -- Turn leading spaces into hard spaces to prevent ASS from stripping them\n    str = str:gsub('\\\\N ', '\\\\N\\\\h')\n    str = str:gsub('^ ', '\\\\h')\n    return str\nend\n\n-- Render the REPL and console as an ASS OSD\nlocal function update()\n    local dpi_scale = mp.get_property_native(\"display-hidpi-scale\", 1.0)\n\n    dpi_scale = dpi_scale * opts.scale\n\n    local screenx, screeny, aspect = mp.get_osd_size()\n    screenx = screenx / dpi_scale\n    screeny = screeny / dpi_scale\n\n    -- Clear the OSD if the REPL is not active\n    if not repl_active then\n        mp.set_osd_ass(screenx, screeny, '')\n        return\n    end\n\n    local ass = assdraw.ass_new()\n    local style = '{\\\\r' ..\n                  '\\\\1a&H00&\\\\3a&H00&\\\\4a&H99&' ..\n                  '\\\\1c&Heeeeee&\\\\3c&H111111&\\\\4c&H000000&' ..\n                  '\\\\fn' .. opts.font .. '\\\\fs' .. opts.font_size ..\n                  '\\\\bord1\\\\xshad0\\\\yshad1\\\\fsp0\\\\q1}'\n\n    local queue_style = '{\\\\r' ..\n                        '\\\\1a&H00&\\\\3a&H00&\\\\4a&H99&' ..\n                        '\\\\1c&Heeeeee&\\\\3c&H111111&\\\\4c&H000000&' ..\n                        '\\\\fn' .. opts.font .. '\\\\fs' .. opts.font_size .. '\\\\c&H66ccff&' ..\n                        '\\\\bord1\\\\xshad0\\\\yshad1\\\\fsp0\\\\q1}'\n\n    -- Create the cursor glyph as an ASS drawing. ASS will draw the cursor\n    -- inline with the surrounding text, but it sets the advance to the width\n    -- of the drawing. So the cursor doesn't affect layout too much, make it as\n    -- thin as possible and make it appear to be 1px wide by giving it 0.5px\n    -- horizontal borders.\n    local cheight = opts.font_size * 8\n    local cglyph = '{\\\\r' ..\n                   '\\\\1a&H44&\\\\3a&H44&\\\\4a&H99&' ..\n                   '\\\\1c&Heeeeee&\\\\3c&Heeeeee&\\\\4c&H000000&' ..\n                   '\\\\xbord0.5\\\\ybord0\\\\xshad0\\\\yshad1\\\\p4\\\\pbo24}' ..\n                   'm 0 0 l 1 0 l 1 ' .. cheight .. ' l 0 ' .. cheight ..\n                   '{\\\\p0}'\n    local before_cur = ass_escape(line:sub(1, cursor - 1))\n    local after_cur = ass_escape(line:sub(cursor))\n\n    ass:new_event()\n    ass:an(1)\n    ass:pos(2, screeny - 2 - global_margin_y * screeny)\n\n    if (#queue == 2) then ass:append(queue_style .. string.format(\"There is 1 more request queued\\\\N\"))\n    elseif (#queue > 2) then ass:append(queue_style .. string.format(\"There are %d more requests queued\\\\N\", #queue-1)) end\n    ass:append(style .. request.text .. '\\\\N')\n    ass:append('> ' .. before_cur)\n    ass:append(cglyph)\n    ass:append(style .. after_cur)\n\n    -- Redraw the cursor with the REPL text invisible. This will make the\n    -- cursor appear in front of the text.\n    ass:new_event()\n    ass:an(1)\n    ass:pos(2, screeny - 2)\n    ass:append(style .. '{\\\\alpha&HFF&}> ' .. before_cur)\n    ass:append(cglyph)\n    ass:append(style .. '{\\\\alpha&HFF&}' .. after_cur)\n\n    mp.set_osd_ass(screenx, screeny, ass.text)\nend\n\n-- Naive helper function to find the next UTF-8 character in 'str' after 'pos'\n-- by skipping continuation bytes. Assumes 'str' contains valid UTF-8.\nlocal function next_utf8(str, pos)\n    if pos > str:len() then return pos end\n    repeat\n        pos = pos + 1\n    until pos > str:len() or str:byte(pos) < 0x80 or str:byte(pos) > 0xbf\n    return pos\nend\n\n-- As above, but finds the previous UTF-8 charcter in 'str' before 'pos'\nlocal function prev_utf8(str, pos)\n    if pos <= 1 then return pos end\n    repeat\n        pos = pos - 1\n    until pos <= 1 or str:byte(pos) < 0x80 or str:byte(pos) > 0xbf\n    return pos\nend\n\n-- Insert a character at the current cursor position (any_unicode)\nlocal function handle_char_input(c)\n    if insert_mode then\n        line = line:sub(1, cursor - 1) .. c .. line:sub(next_utf8(line, cursor))\n    else\n        line = line:sub(1, cursor - 1) .. c .. line:sub(cursor)\n    end\n    cursor = cursor + #c\n    update()\nend\n\n-- Remove the character behind the cursor (Backspace)\nlocal function handle_backspace()\n    if cursor <= 1 then return end\n    local prev = prev_utf8(line, cursor)\n    line = line:sub(1, prev - 1) .. line:sub(cursor)\n    cursor = prev\n    update()\nend\n\n-- Remove the character in front of the cursor (Del)\nlocal function handle_del()\n    if cursor > line:len() then return end\n    line = line:sub(1, cursor - 1) .. line:sub(next_utf8(line, cursor))\n    update()\nend\n\n-- Toggle insert mode (Ins)\nlocal function handle_ins()\n    insert_mode = not insert_mode\nend\n\n-- Move the cursor to the next character (Right)\nlocal function next_char(amount)\n    cursor = next_utf8(line, cursor)\n    update()\nend\n\n-- Move the cursor to the previous character (Left)\nlocal function prev_char(amount)\n    cursor = prev_utf8(line, cursor)\n    update()\nend\n\n-- Clear the current line (Ctrl+C)\nlocal function clear()\n    line = ''\n    cursor = 1\n    insert_mode = false\n    request.history.pos = #request.history.list + 1\n    update()\nend\n\n-- Close the REPL if the current line is empty, otherwise do nothing (Ctrl+D)\nlocal function maybe_exit()\n    if line == '' then\n    else\n        handle_del()\n    end\nend\n\nlocal function handle_esc()\n    coroutine.resume(co, {\n        line = nil,\n        err = \"exited\"\n    })\nend\n\n-- Run the current command and clear the line (Enter)\nlocal function handle_enter()\n    if request.history.list[#request.history.list] ~= line and line ~= \"\" then\n        request.history.list[#request.history.list + 1] = line\n    end\n    coroutine.resume(co, {\n        line = line\n    })\nend\n\n-- Go to the specified position in the command history\nlocal function go_history(new_pos)\n    local old_pos = request.history.pos\n    request.history.pos = new_pos\n\n    -- Restrict the position to a legal value\n    if request.history.pos > #request.history.list + 1 then\n        request.history.pos = #request.history.list + 1\n    elseif request.history.pos < 1 then\n        request.history.pos = 1\n    end\n\n    -- Do nothing if the history position didn't actually change\n    if request.history.pos == old_pos then\n        return\n    end\n\n    -- If the user was editing a non-history line, save it as the last history\n    -- entry. This makes it much less frustrating to accidentally hit Up/Down\n    -- while editing a line.\n    if old_pos == #request.history.list + 1 and line ~= '' and request.history.list[#request.history.list] ~= line then\n        request.history.list[#request.history.list + 1] = line\n    end\n\n    -- Now show the history line (or a blank line for #history + 1)\n    if request.history.pos <= #request.history.list then\n        line = request.history.list[request.history.pos]\n    else\n        line = ''\n    end\n    cursor = line:len() + 1\n    insert_mode = false\n    update()\nend\n\n-- Go to the specified relative position in the command history (Up, Down)\nlocal function move_history(amount)\n    go_history(request.history.pos + amount)\nend\n\n-- Go to the first command in the command history (PgUp)\nlocal function handle_pgup()\n    go_history(1)\nend\n\n-- Stop browsing history and start editing a blank line (PgDown)\nlocal function handle_pgdown()\n    go_history(#request.history.list + 1)\nend\n\n-- Move to the start of the current word, or if already at the start, the start\n-- of the previous word. (Ctrl+Left)\nlocal function prev_word()\n    -- This is basically the same as next_word() but backwards, so reverse the\n    -- string in order to do a \"backwards\" find. This wouldn't be as annoying\n    -- to do if Lua didn't insist on 1-based indexing.\n    cursor = line:len() - select(2, line:reverse():find('%s*[^%s]*', line:len() - cursor + 2)) + 1\n    update()\nend\n\n-- Move to the end of the current word, or if already at the end, the end of\n-- the next word. (Ctrl+Right)\nlocal function next_word()\n    cursor = select(2, line:find('%s*[^%s]*', cursor)) + 1\n    update()\nend\n\n-- Move the cursor to the beginning of the line (HOME)\nlocal function go_home()\n    cursor = 1\n    update()\nend\n\n-- Move the cursor to the end of the line (END)\nlocal function go_end()\n    cursor = line:len() + 1\n    update()\nend\n\n-- Delete from the cursor to the beginning of the word (Ctrl+Backspace)\nlocal function del_word()\n    local before_cur = line:sub(1, cursor - 1)\n    local after_cur = line:sub(cursor)\n\n    before_cur = before_cur:gsub('[^%s]+%s*$', '', 1)\n    line = before_cur .. after_cur\n    cursor = before_cur:len() + 1\n    update()\nend\n\n-- Delete from the cursor to the end of the word (Ctrl+Del)\nlocal function del_next_word()\n    if cursor > line:len() then return end\n\n    local before_cur = line:sub(1, cursor - 1)\n    local after_cur = line:sub(cursor)\n\n    after_cur = after_cur:gsub('^%s*[^%s]+', '', 1)\n    line = before_cur .. after_cur\n    update()\nend\n\n-- Delete from the cursor to the end of the line (Ctrl+K)\nlocal function del_to_eol()\n    line = line:sub(1, cursor - 1)\n    update()\nend\n\n-- Delete from the cursor back to the start of the line (Ctrl+U)\nlocal function del_to_start()\n    line = line:sub(cursor)\n    cursor = 1\n    update()\nend\n\n-- Returns a string of UTF-8 text from the clipboard (or the primary selection)\nlocal function get_clipboard(clip)\n    if platform == 'x11' then\n        local res = utils.subprocess({\n            args = { 'xclip', '-selection', clip and 'clipboard' or 'primary', '-out' },\n            playback_only = false,\n        })\n        if not res.error then\n            return res.stdout\n        end\n    elseif platform == 'wayland' then\n        local res = utils.subprocess({\n            args = { 'wl-paste', clip and '-n' or  '-np' },\n            playback_only = false,\n        })\n        if not res.error then\n            return res.stdout\n        end\n    elseif platform == 'windows' then\n        local res = utils.subprocess({\n            args = { 'powershell', '-NoProfile', '-Command', [[& {\n                Trap {\n                    Write-Error -ErrorRecord $_\n                    Exit 1\n                }\n\n                $clip = \"\"\n                if (Get-Command \"Get-Clipboard\" -errorAction SilentlyContinue) {\n                    $clip = Get-Clipboard -Raw -Format Text -TextFormatType UnicodeText\n                } else {\n                    Add-Type -AssemblyName PresentationCore\n                    $clip = [Windows.Clipboard]::GetText()\n                }\n\n                $clip = $clip -Replace \"`r\",\"\"\n                $u8clip = [System.Text.Encoding]::UTF8.GetBytes($clip)\n                [Console]::OpenStandardOutput().Write($u8clip, 0, $u8clip.Length)\n            }]] },\n            playback_only = false,\n        })\n        if not res.error then\n            return res.stdout\n        end\n    elseif platform == 'macos' then\n        local res = utils.subprocess({\n            args = { 'pbpaste' },\n            playback_only = false,\n        })\n        if not res.error then\n            return res.stdout\n        end\n    end\n    return ''\nend\n\n-- Paste text from the window-system's clipboard. 'clip' determines whether the\n-- clipboard or the primary selection buffer is used (on X11 and Wayland only.)\nlocal function paste(clip)\n    local text = get_clipboard(clip)\n    local before_cur = line:sub(1, cursor - 1)\n    local after_cur = line:sub(cursor)\n    line = before_cur .. text .. after_cur\n    cursor = cursor + text:len()\n    update()\nend\n\n-- List of input bindings. This is a weird mashup between common GUI text-input\n-- bindings and readline bindings.\nlocal function get_bindings()\n    local bindings = {\n        { 'esc',         handle_esc                             },\n        { 'enter',       handle_enter                           },\n        { 'kp_enter',    handle_enter                           },\n        { 'shift+enter', function() handle_char_input('\\n') end },\n        { 'ctrl+j',      handle_enter                           },\n        { 'ctrl+m',      handle_enter                           },\n        { 'bs',          handle_backspace                       },\n        { 'shift+bs',    handle_backspace                       },\n        { 'ctrl+h',      handle_backspace                       },\n        { 'del',         handle_del                             },\n        { 'shift+del',   handle_del                             },\n        { 'ins',         handle_ins                             },\n        { 'shift+ins',   function() paste(false) end            },\n        { 'mbtn_mid',    function() paste(false) end            },\n        { 'left',        function() prev_char() end             },\n        { 'ctrl+b',      function() prev_char() end             },\n        { 'right',       function() next_char() end             },\n        { 'ctrl+f',      function() next_char() end             },\n        { 'up',          function() move_history(-1) end        },\n        { 'ctrl+p',      function() move_history(-1) end        },\n        { 'wheel_up',    function() move_history(-1) end        },\n        { 'down',        function() move_history(1) end         },\n        { 'ctrl+n',      function() move_history(1) end         },\n        { 'wheel_down',  function() move_history(1) end         },\n        { 'wheel_left',  function() end                         },\n        { 'wheel_right', function() end                         },\n        { 'ctrl+left',   prev_word                              },\n        { 'alt+b',       prev_word                              },\n        { 'ctrl+right',  next_word                              },\n        { 'alt+f',       next_word                              },\n        { 'ctrl+a',      go_home                                },\n        { 'home',        go_home                                },\n        { 'ctrl+e',      go_end                                 },\n        { 'end',         go_end                                 },\n        { 'pgup',        handle_pgup                            },\n        { 'pgdwn',       handle_pgdown                          },\n        { 'ctrl+c',      clear                                  },\n        { 'ctrl+d',      maybe_exit                             },\n        { 'ctrl+k',      del_to_eol                             },\n        { 'ctrl+u',      del_to_start                           },\n        { 'ctrl+v',      function() paste(true) end             },\n        { 'meta+v',      function() paste(true) end             },\n        { 'ctrl+bs',     del_word                               },\n        { 'ctrl+w',      del_word                               },\n        { 'ctrl+del',    del_next_word                          },\n        { 'alt+d',       del_next_word                          },\n        { 'kp_dec',      function() handle_char_input('.') end  },\n    }\n\n    for i = 0, 9 do\n        bindings[#bindings + 1] =\n            {'kp' .. i, function() handle_char_input('' .. i) end}\n    end\n\n    return bindings\nend\n\nlocal function text_input(info)\n    if info.key_text and (info.event == \"press\" or info.event == \"down\"\n                          or info.event == \"repeat\")\n    then\n        handle_char_input(info.key_text)\n    end\nend\n\nlocal function define_key_bindings()\n    if #key_bindings > 0 then\n        return\n    end\n    for _, bind in ipairs(get_bindings()) do\n        -- Generate arbitrary name for removing the bindings later.\n        local name = \"_userinput_\" .. bind[1]\n        key_bindings[#key_bindings + 1] = name\n        mp.add_forced_key_binding(bind[1], name, bind[2], {repeatable = true})\n    end\n    mp.add_forced_key_binding(\"any_unicode\", \"_userinput_text\", text_input,\n        {repeatable = true, complex = true})\n    key_bindings[#key_bindings + 1] = \"_userinput_text\"\nend\n\nlocal function undefine_key_bindings()\n    for _, name in ipairs(key_bindings) do\n        mp.remove_key_binding(name)\n    end\n    key_bindings = {}\nend\n\n-- Set the REPL visibility (\"enable\", Esc)\nlocal function set_active(active)\n    if active == repl_active then return end\n    if active then\n        repl_active = true\n        insert_mode = false\n        define_key_bindings()\n    else\n        clear()\n        repl_active = false\n        undefine_key_bindings()\n        collectgarbage()\n    end\n    update()\nend\n\n\nmp.observe_property(\"user-data/osc/margins\", \"native\", function(_, val)\n    if val then\n        global_margins = val\n    else\n        global_margins = { t = 0, b = 0 }\n    end\n    update()\nend)\n\n-- Redraw the REPL when the OSD size changes. This is needed because the\n-- PlayRes of the OSD will need to be adjusted.\nmp.observe_property('osd-width', 'native', update)\nmp.observe_property('osd-height', 'native', update)\nmp.observe_property('display-hidpi-scale', 'native', update)\n\n----------------------------------------------------------------------------------------\n----------------------------------------------------------------------------------------\n----------------------------------------------------------------------------------------\n-------------------------------END ORIGINAL MPV CODE------------------------------------\n\n--[[\n    sends a response to the original script in the form of a json string\n    it is expected that all requests get a response, if the input is nil then err should say why\n    current error codes are:\n        exited          the user closed the input instead of pressing Enter\n        already_queued  a request with the specified id was already in the queue\n        cancelled       a script cancelled the request\n        replace         replaced by another request\n]]\nlocal function send_response(res)\n    if res.source then\n        mp.commandv(\"script-message-to\", res.source, res.response, (utils.format_json(res)))\n    else\n        mp.commandv(\"script-message\", res.response, (utils.format_json(res)))\n    end\nend\n\n-- push new request onto the queue\n-- if a request with the same id already exists and the queueable flag is not enabled then\n-- a nil result will be returned to the function\nfunction push_request(req)\n    if active_ids[req.id] then\n        if req.replace then\n            for i, q_req in ipairs(queue) do\n                if q_req.id == req.id then\n                    send_response{ err = \"replaced\", response = q_req.response, source = q_req.source }\n                    queue[i] = req\n                    if i == 1 then request = req end\n                end\n            end\n            update()\n            return\n        end\n\n        if not req.queueable then\n            send_response{ err = \"already_queued\", response = req.response, source = req.source }\n            return\n        end\n    end\n\n    table.insert(queue, req)\n    active_ids[req.id] = (active_ids[req.id] or 0) + 1\n    if #queue == 1 then coroutine.resume(co) end\n    update()\nend\n\n-- safely removes an item from the queue and updates the set of active requests\nfunction remove_request(index)\n    local req = table.remove(queue, index)\n    active_ids[req.id] = active_ids[req.id] - 1\n\n    if active_ids[req.id] == 0 then active_ids[req.id] = nil end\n    return req\nend\n\n--an infinite loop that moves through the request queue\n--uses a coroutine to handle asynchronous operations\nlocal function driver()\n    while (true) do\n        while queue[1] do\n            request = queue[1]\n            line = request.default_input\n            cursor = request.cursor_pos\n\n            if repl_active then update()\n            else set_active(true) end\n\n            res = coroutine.yield()\n            if res then\n                res.source, res.response = request.source, request.response\n                send_response(res)\n                remove_request(1)\n            end\n        end\n\n        set_active(false)\n        coroutine.yield()\n    end\nend\n\nco = coroutine.create(driver)\n\n--cancels any input request that returns true for the given predicate function\nlocal function cancel_input_request(pred)\n    for i = #queue, 1, -1 do\n        if pred(i) then\n            req = remove_request(i)\n            send_response{ err = \"cancelled\", response = req.response, source = req.source }\n\n            --if we're removing the first item then that means the coroutine is waiting for a response\n            --we will need to tell the coroutine to resume, upon which it will move to the next request\n            --if there is something in the buffer then save it to the history before erasing it\n            if i == 1 then\n                local old_line = line\n                if old_line ~= \"\" then table.insert(histories[req.id].list, old_line) end\n                clear()\n                coroutine.resume(co)\n            end\n        end\n    end\nend\n\nmp.register_script_message(\"cancel-user-input/uid\", function(uid)\n    cancel_input_request(function(i) return queue[i].response == uid end)\nend)\n\n-- removes all requests with the specified id from the queue\nmp.register_script_message(\"cancel-user-input/id\", function(id)\n    cancel_input_request(function(i) return queue[i].id == id end)\nend)\n\n-- ensures a request has the correct fields and is correctly formatted\nlocal function format_request_fields(req)\n    assert(req.version, \"input requests require an API version string\")\n    if not string.find(req.version, API_MAJOR_MINOR, 1, true) then\n        error((\"input request has invalid version: expected %s.x, got %s\"):format(API_MAJOR_MINOR, req.version))\n    end\n\n    assert(req.response, \"input requests require a response string\")\n    assert(req.id, \"input requests require an id string\")\n\n    req.text = ass_escape(req.request_text or \"\")\n    req.default_input = req.default_input or \"\"\n    req.cursor_pos = tonumber(req.cursor_pos) or 1\n    req.id = req.id or \"mpv\"\n\n    if req.cursor_pos ~= 1 then\n        if req.cursor_pos  < 1 then req.cursor_pos  = 1\n        elseif req.cursor_pos  > #req.default_input then req.cursor_pos  = #req.default_input + 1 end\n    end\n\n    if not histories[req.id] then histories[req.id] = {pos = 1, list = {}} end\n    req.history = histories[req.id]\n    return req\nend\n\n-- updates the fields of a specific request\nmp.register_script_message(\"update-user-input/uid\", function(uid, req_opts)\n    req_opts = utils.parse_json(req_opts)\n    req_opts.response = uid\n    for i, req in ipairs(queue) do\n        if req.response == uid then\n            local success, result = pcall(format_request_fields, req_opts)\n            if not success then return msg.error(result) end\n\n            queue[i] = result\n            if i == 1 then request = queue[1] end\n            update()\n            return\n        end\n    end\nend)\n\n--the function that parses the input requests\nlocal function input_request(req)\n    req = format_request_fields(req)\n    push_request(req)\nend\n\n-- script message to recieve input requests, get-user-input.lua acts as an interface to call this script message\nmp.register_script_message(\"request-user-input\", function(req)\n    msg.debug(req)\n    req = utils.parse_json(req)\n    local success, err = pcall(input_request, req)\n    if not success then\n        send_response{ err = err, response = req.response, source = req.source}\n        msg.error(err)\n    end\nend)\n\n"
  },
  {
    "path": ".config/nano/nanorc",
    "content": "## Sample initialization file for GNU nano.\n##\n## For the options that take parameters, the default value is shown.\n## Other options are unset by default.  To make sure that an option\n## is disabled, you can use \"unset <option>\".\n##\n## Characters that are special in a shell should not be escaped here.\n## Inside string parameters, quotes should not be escaped -- the last\n## double quote on the line will be seen as the closing quote.\n\n## Make 'nextword' (Ctrl+Right) and 'chopwordright' (Ctrl+Delete)\n## stop at word ends instead of at beginnings.\n# set afterends\n\n## When soft line wrapping is enabled, make it wrap lines at blanks\n## (tabs and spaces) instead of always at the edge of the screen.\nset atblanks\n\n## Automatically indent a newly created line to the same number of\n## tabs and/or spaces as the preceding line -- or as the next line\n## if the preceding line is the beginning of a paragraph.\nset autoindent\n\n## Back up files to the current filename plus a tilde.\n# set backup\n\n## The directory to put unique backup files in.\n# set backupdir \"\"\n\n## Use bold text instead of reverse video text.\n# set boldtext\n\n## Treat any line with leading whitespace as the beginning of a paragraph.\n# set bookstyle\n\n## The characters treated as closing brackets when justifying paragraphs.\n## This may not include any blank characters.  Only closing punctuation,\n## optionally followed by these closing brackets, can end sentences.\n# set brackets \"\"')>]}\"\n\n## Automatically hard-wrap the current line when it becomes overlong.\n# set breaklonglines\n\n## Do case-sensitive searches by default.\n# set casesensitive\n\n## Constantly display the cursor position in the status bar or minibar.\n# set constantshow\n\n## Use cut-from-cursor-to-end-of-line by default.\n# set cutfromcursor\n\n## Do not use the line below the title bar, leaving it entirely blank.\n# set emptyline\n\n## Set the target width for automatic hard-wrapping and for justifying\n## paragraphs.  If the specified value is 0 or less, the wrapping point\n## will be the terminal's width minus this number.\n# set fill -8\n\n## Draw a vertical stripe at the given column, to help judge text width.\n## (This option does not have a default value.)\n# set guidestripe 75\n\n## Remember the used search/replace strings for the next session.\nset historylog\n\n## Display a \"scrollbar\" on the righthand side of the edit window.\n# set indicator\n\n## Scroll the buffer contents per half-screen instead of per line.\n# set jumpyscrolling\n\n## Display line numbers to the left (and any anchors in the margin).\nset linenumbers\n\n## Enable vim-style lock-files.  This is just to let a vim user know you\n## are editing a file [s]he is trying to edit and vice versa.  There are\n## no plans to implement vim-style undo state in these files.\nset locking\n\n## Fall back to slow libmagic to try and determine an applicable syntax.\n# set magic\n\n## The opening and closing brackets that are found by a matching-bracket\n## search.  This may not contain blank characters.  The opening brackets\n## must come before the closing ones, and they must be in the same order.\n# set matchbrackets \"(<[{)>]}\"\n\n## Suppress the title bar and show the filename plus a cursor-position\n## percentage in the space of the status bar.\nset minibar\n\n## Enable mouse support, if available for your system.  When enabled,\n## mouse clicks can be used to place the cursor, set the mark (with a\n## double click), and execute shortcuts.  The mouse will work in the\n## X Window System, and on the console when gpm is running.\nset mouse\n\n## Switch on multiple file buffers (inserting a file will put it into\n## a separate buffer).\nset multibuffer\n\n## Don't convert files from DOS/Mac format.\n# set noconvert\n\n## Don't display the helpful shortcut lists at the bottom of the screen.\nset nohelp\n\n## Don't automatically add a newline when a file does not end with one.\n# set nonewlines\n\n## Set operating directory.  nano will not read or write files outside\n## this directory and its subdirectories.  Also, the current directory\n## is changed to here, so any files are inserted from this dir.  A blank\n## string means the operating-directory feature is turned off.\n# set operatingdir \"\"\n\n## Remember the cursor position in each file for the next editing session.\n# set positionlog\n\n## Preserve the XON and XOFF keys (^Q and ^S).\n# set preserve\n\n## The characters treated as closing punctuation when justifying paragraphs.\n## This may not contain blank characters.  Only these closing punctuations,\n## optionally followed by closing brackets, can end sentences.\n# set punct \"!.?\"\n\n## Make status-bar messages disappear after 1 keystroke instead of after 20.\n# set quickblank\n\n## The regular expression that matches quoting characters in email\n## or line-comment introducers in source code.  The default is:\n# set quotestr \"^([ \t]*([!#%:;>|}]|//))+\"\n\n## Try to work around a mismatching terminfo terminal description.\n# set rawsequences\n\n## Fix Backspace/Delete confusion problem.\n# set rebinddelete\n\n## Do regular-expression searches by default.\n## Regular expressions are of the extended type (ERE).\n# set regexp\n\n## Save a changed buffer automatically on exit; don't prompt.\n# set saveonexit\n\n## Put the cursor on the highlighted item in the file browser, and\n## show the cursor in the help viewer; useful for people who use a\n## braille display and people with poor vision.\n# set showcursor\n\n## Make the Home key smarter: when Home is pressed anywhere but at the\n## very beginning of non-whitespace characters on a line, the cursor\n## will jump to that beginning (either forwards or backwards).  If the\n## cursor is already at that position, it will jump to the true start\n## of the line (the left edge).\n# set smarthome\n\n## Spread overlong lines over multiple screen lines.\nset softwrap\n\n## Use this spelling checker instead of the internal one.  This option\n## does not have a default value.\n# set speller \"aspell -x -c\"\n\n## Use the end of the title bar for some state flags: I = auto-indenting,\n## M = mark, L = hard-wrapping long lines, R = recording, S = soft-wrapping.\nset stateflags\n\n## Use this tab size instead of the default; it must be greater than 0.\n# set tabsize 8\n\n## Convert each typed tab to the fitting number of spaces.\n# set tabstospaces\n\n## Snip whitespace at the end of lines when justifying or hard-wrapping.\n# set trimblanks\n\n## Save files by default in Unix format (also when they were DOS or Mac).\n# set unix\n\n## The two single-column characters used to display the first characters\n## of tabs and spaces.  187 in ISO 8859-1 (0000BB in Unicode) and 183 in\n## ISO-8859-1 (0000B7 in Unicode) seem to be good values for these.\n## The default when in a UTF-8 locale:\n# set whitespace \"»·\"\n## The default otherwise:\n# set whitespace \">.\"\n\n## Detect word boundaries differently by treating punctuation\n## characters as parts of words.\n# set wordbounds\n\n## The characters (besides alphanumeric ones) that should be considered\n## as parts of words.  This option does not have a default value.  When\n## set, it overrides option 'set wordbounds'.\n# set wordchars \"<_>.\"\n\n## Let an unmodified Backspace or Delete erase the marked region (instead\n## of a single character, and without affecting the cutbuffer).\n# set zap\n\n## Hide the bars plus help lines and use the whole terminal as edit area.\n# set zero\n\n\n## Paint the interface elements of nano.  These are examples; there are\n## no colors by default, except for errorcolor and spotlightcolor.\n# set titlecolor bold,white,blue\n# set promptcolor lightwhite,grey\n# set statuscolor bold,white,green\n# set errorcolor bold,white,red\n# set spotlightcolor black,lightyellow\n# set selectedcolor lightwhite,magenta\n# set stripecolor ,yellow\n# set scrollercolor cyan\n# set numbercolor cyan\n# set keycolor cyan\n# set functioncolor green\n\n## In root's .nanorc you might want to use:\n# set titlecolor bold,white,magenta\n# set promptcolor black,yellow\n# set statuscolor bold,white,magenta\n# set errorcolor bold,white,red\n# set spotlightcolor black,orange\n# set selectedcolor lightwhite,cyan\n# set stripecolor ,yellow\n# set scrollercolor magenta\n# set numbercolor magenta\n# set keycolor lightmagenta\n# set functioncolor magenta\n\n\n## === Syntax coloring ===\n## For all details, see 'man nanorc', section SYNTAX HIGHLIGHTING.\n\n## To include most of the existing syntax definitions, you can do:\ninclude \"/usr/share/nano/*.nanorc\"\n\n## Or you can select just the ones you need.  For example:\n# include \"/usr/share/nano/html.nanorc\"\n# include \"/usr/share/nano/python.nanorc\"\n# include \"/usr/share/nano/sh.nanorc\"\n\n## In /usr/share/nano/extra/ you can find some syntaxes that are\n## specific for certain distros or for some less common languages.\n\n\n## If <Tab> should always produce four spaces when editing a Python file,\n## independent of the settings of 'tabsize' and 'tabstospaces':\n# extendsyntax python tabgives \"    \"\n\n## If <Tab> should always produce an actual TAB when editing a Makefile:\n# extendsyntax makefile tabgives \"\t\"\n\n\n## === Key bindings ===\n## For all details, see 'man nanorc', section REBINDING KEYS.\n\n## If you want to suspend nano with one keystroke (instead of with ^T^Z):\n# bind ^Z suspend main\n\n## The <Ctrl+Delete> keystroke deletes the word to the right of the cursor.\n## On some terminals the <Ctrl+Backspace> keystroke produces ^H, which is\n## the ASCII character for backspace, so it is bound by default to the\n## backspace function.  The <Backspace> key itself produces a different\n## keycode, which is hard-bound to the backspace function.  So, if you\n## normally use <Backspace> for backspacing and not ^H, you can make\n## <Ctrl+Backspace> delete the word to the left of the cursor with:\n# bind ^H chopwordleft main\n\n## For a more mnemonic Comment keystroke (overriding Cut-from-cursor):\n# bind M-K comment main\n\n## If you want ^L to just refresh the screen and not center the cursor:\n# bind ^L refresh main\n\n## When you sometimes type M-J instead of M-K, or M-T instead of M-R:\n# unbind M-J main\n# unbind M-T main\n## (Those functions are still accessible through ^T^J and ^T^V.)\n\n## For quickly uppercasing or lowercasing the word under or after the cursor.\n## (These effectively select a word and pipe it through a sed command.)\n# bind Sh-M-U \"\u001bOc\u001b[1;6D\u0014|sed 's/.*/\\U&/'\n# bind Sh-M-L \"\u001bOc\u001b[1;6D\u0014|sed 's/.*/\\L&/'\n\n## For copying a marked region to the system clipboard:\n# bind Sh-M-T \"{execute}|xsel -ib{enter}{undo}\" main\n\n## For snipping trailing blanks when you save a file:\n# bind ^S \"{execute}| sed 's/\\s\\+$//' {enter}{savefile}\" main\n# bind Sh-M-T \"\u0014|xsel -ib\n\n## If you would like nano to have keybindings that are more \"usual\",\n## such as ^O for Open, ^F for Find, ^H for Help, and ^Q for Quit,\n## then uncomment these:\n#bind ^X cut main\nbind ^C copy main\nbind ^V paste all\n#bind ^Q exit all\nbind ^S savefile main\nbind ^W writeout main\n#bind ^O insert main\n#set multibuffer\n#bind ^H help all\n#bind ^H exit help\nbind ^F whereis all\n#bind ^G findnext all\n#bind ^B wherewas all\n#bind ^D findprevious all\n#bind ^R replace main\n#unbind ^U all\n#unbind ^N main\n#unbind ^Y all\n#unbind M-J main\n#unbind M-T main\n#bind ^A mark main\n#bind ^P location main\n#bind ^T gotoline main\n#bind ^T gotodir browser\n#bind ^T cutrestoffile execute\n#bind ^L linter execute\n#bind ^E execute main\n#bind ^K \"{mark}{end}{zap}\" main\n#bind ^U \"{mark}{home}{zap}\" main\nbind ^Z undo main\nbind ^Y redo main\n"
  },
  {
    "path": ".config/niri/config.kdl",
    "content": "prefer-no-csd\n\n// Includes\ninclude \"outputs.kdl\"\ninclude \"layout.kdl\"\ninclude \"dms.kdl\"\ninclude \"keybinds.kdl\"\ninclude \"rules.kdl\"\n\n// Input & Cursor (core, stay inline)\ninput {\n    keyboard {\n        xkb {\n            layout \"us,fr\"\n            options \"grp:rctrl_rshift_toggle,numpad:mac,compose:ralt\"\n        }\n    }\n    touchpad {\n        tap\n        accel-speed 0.2\n        accel-profile \"adaptive\"\n        scroll-method \"two-finger\"\n    }\n    mouse {\n        accel-profile \"flat\"\n    }\n    tablet {\n        map-to-output \"DP-2\"\n    }\n}\n\ncursor {\n    xcursor-theme \"Kaela-Kovalskia-v2\"\n    xcursor-size 24\n}\n\n// Core spawns & globals\nspawn-at-startup \"xwayland-satellite\"\n    environment {\n        DISPLAY \":0\"\n    }\n\nspawn-at-startup \"~/.config/autostart/autostart\"\nscreenshot-path \"~/Pictures/grim/%Y-%m-%d %H-%M-%S.png\"\n\nhotkey-overlay {\n    skip-at-startup\n}\nconfig-notification {\n    disable-failed\n}\ndebug {\n    honor-xdg-activation-with-invalid-serial\n}\n"
  },
  {
    "path": ".config/niri/dms.kdl",
    "content": "spawn-at-startup \"dms\" \"run\"\n\nbinds {\n    Mod+D hotkey-overlay-title=\"Application Launcher\" {\n        spawn \"dms\" \"ipc\" \"call\" \"spotlight\" \"toggle\"\n    }\n    Mod+comma hotkey-overlay-title=\"Clipboard Manager\" {\n        spawn \"dms\" \"ipc\" \"call\" \"clipboard\" \"toggle\"\n    }\n    Mod+M hotkey-overlay-title=\"Task Manager\" {\n        spawn \"dms\" \"ipc\" \"call\" \"processlist\" \"toggle\"\n    }\n    Mod+N hotkey-overlay-title=\"Notification Center\" {\n        spawn \"dms\" \"ipc\" \"call\" \"notifications\" \"toggle\"\n    }\n    Mod+P hotkey-overlay-title=\"Notepad\" {\n        spawn \"dms\" \"ipc\" \"call\" \"notepad\" \"toggle\"\n    }\n    Super+Alt+L hotkey-overlay-title=\"Lock Screen\" {\n        spawn \"dms\" \"ipc\" \"call\" \"lock\" \"lock\"\n    }\n    Mod+X hotkey-overlay-title=\"Power Menu\" {\n        spawn \"dms\" \"ipc\" \"call\" \"powermenu\" \"toggle\"\n    }\n    Mod+Y hotkey-overlay-title=\"Browse Wallpapers\" {\n        spawn \"dms\" \"ipc\" \"call\" \"dankdash\" \"wallpaper\"\n    }\n    XF86AudioRaiseVolume allow-when-locked=true {\n        spawn \"dms\" \"ipc\" \"call\" \"audio\" \"increment\" \"3\"\n    }\n    XF86AudioLowerVolume allow-when-locked=true {\n        spawn \"dms\" \"ipc\" \"call\" \"audio\" \"decrement\" \"3\"\n    }\n    XF86AudioMute allow-when-locked=true {\n        spawn \"dms\" \"ipc\" \"call\" \"audio\" \"mute\"\n    }\n    XF86AudioMicMute allow-when-locked=true {\n        spawn \"dms\" \"ipc\" \"call\" \"audio\" \"micmute\"\n    }\n    XF86MonBrightnessUp allow-when-locked=true {\n        spawn \"dms\" \"ipc\" \"call\" \"brightness\" \"increment\" \"5\" \"\"\n    }\n    XF86MonBrightnessDown allow-when-locked=true {\n        spawn \"dms\" \"ipc\" \"call\" \"brightness\" \"decrement\" \"5\" \"\"\n    }\n    Mod+Shift+N allow-when-locked=true {\n        spawn \"dms\" \"ipc\" \"call\" \"night\" \"toggle\"\n    }\n}\n"
  },
  {
    "path": ".config/niri/keybinds.kdl",
    "content": "binds {\n    // Personal\n    Mod+Return { spawn \"alacritty\"; }\n    F10 { spawn \"~/.config/niri/scripts/obs-replay\"; }\n\n    // Niri Actions\n    Mod+Shift+Q { close-window; }\n    Mod+Tab { toggle-overview; }\n    Mod+Shift+Slash { show-hotkey-overlay; }\n    Mod+T { toggle-column-tabbed-display; }\n    Mod+Shift+E { quit; }\n    Ctrl+Alt+Delete { quit; }\n    Mod+Shift+P { power-off-monitors; }\n\n    // Float\n    Mod+V { toggle-window-floating; }\n    Mod+Shift+V { switch-focus-between-floating-and-tiling; }\n\n    // Focus - Window/Columns\n    Mod+Left  { focus-column-left; }\n    Mod+Down  { focus-window-down; }\n    Mod+Up    { focus-window-up; }\n    Mod+Right { focus-column-right; }\n    Mod+H     { focus-column-left; }\n    Mod+J     { focus-window-down; }\n    Mod+K     { focus-window-up; }\n    Mod+L     { focus-column-right; }\n    Mod+Home  { focus-column-first; }\n    Mod+End   { focus-column-last; }\n\n    // Focus - Workspace\n    Mod+1 { focus-workspace 1; }\n    Mod+2 { focus-workspace 2; }\n    Mod+3 { focus-workspace 3; }\n    Mod+4 { focus-workspace 4; }\n    Mod+5 { focus-workspace 5; }\n    Mod+6 { focus-workspace 6; }\n    Mod+7 { focus-workspace 7; }\n    Mod+8 { focus-workspace 8; }\n    Mod+9 { focus-workspace 9; }\n    Mod+Page_Down { focus-workspace-down; }\n    Mod+Page_Up   { focus-workspace-up; }\n\n    // Focus - Monitor\n    Ctrl+Left  { focus-monitor-left; }\n    Ctrl+Down  { focus-monitor-down; }\n    Ctrl+Up    { focus-monitor-up; }\n    Ctrl+Right { focus-monitor-right; }\n\n    // Move - Window/Column\n    Mod+Shift+Left  { move-column-left; }\n    Mod+Shift+Down  { move-window-down; }\n    Mod+Shift+Up    { move-window-up; }\n    Mod+Shift+Right { move-column-right; }\n    Mod+Shift+H     { move-column-left; }\n    Mod+Shift+J     { move-window-down; }\n    Mod+Shift+K     { move-window-up; }\n    Mod+Shift+L     { move-column-right; }\n    Mod+Ctrl+Home   { move-column-to-first; }\n    Mod+Ctrl+End    { move-column-to-last; }\n\n    // Move - Workspace\n    Mod+Shift+1 { move-column-to-workspace 1; }\n    Mod+Shift+2 { move-column-to-workspace 2; }\n    Mod+Shift+3 { move-column-to-workspace 3; }\n    Mod+Shift+4 { move-column-to-workspace 4; }\n    Mod+Shift+5 { move-column-to-workspace 5; }\n    Mod+Shift+6 { move-column-to-workspace 6; }\n    Mod+Shift+7 { move-column-to-workspace 7; }\n    Mod+Shift+8 { move-column-to-workspace 8; }\n    Mod+Shift+9 { move-column-to-workspace 9; }\n    Alt+Up   { move-column-to-workspace-up; }\n    Alt+Down { move-column-to-workspace-down; }\n    Alt+Left { consume-or-expel-window-left; }\n    Alt+Right { consume-or-expel-window-right; }\n\n    // Move - Monitor\n    Shift+Ctrl+Left  { move-column-to-monitor-left; }\n    Shift+Ctrl+Down  { move-column-to-monitor-down; }\n    Shift+Ctrl+Up    { move-column-to-monitor-up; }\n    Shift+Ctrl+Right { move-column-to-monitor-right; }\n\n    // Consume/Expel\n    Mod+BracketLeft  { consume-window-into-column; }\n    Mod+BracketRight { expel-window-from-column; }\n\n    // Size\n    Mod+F      { maximize-column; }\n    Mod+Shift+F { fullscreen-window; }\n    Mod+Ctrl+F { expand-column-to-available-width; }\n    Mod+Alt+F  { toggle-windowed-fullscreen; }\n    Mod+R      { switch-preset-column-width; }\n    Mod+Shift+R { switch-preset-window-height; }\n    Mod+Ctrl+R { reset-window-height; }\n    Mod+C      { center-column; }\n    Mod+Minus  { set-column-width \"-10%\"; }\n    Mod+Equal  { set-column-width \"+10%\"; }\n    Mod+Shift+Minus { set-window-height \"-10%\"; }\n    Mod+Shift+Equal { set-window-height \"+10%\"; }\n\n    // Mouse\n    Mod+Alt+WheelScrollDown cooldown-ms=150 { move-column-to-workspace-down; }\n    Mod+Alt+WheelScrollUp   cooldown-ms=150 { move-column-to-workspace-up; }\n    Mod+WheelScrollRight    { focus-column-right; }\n    Mod+WheelScrollLeft     { focus-column-left; }\n    Mod+Shift+WheelScrollRight { move-column-right; }\n    Mod+Shift+WheelScrollLeft  { move-column-left; }\n    Mod+WheelScrollDown     { focus-column-right; }\n    Mod+WheelScrollUp       { focus-column-left; }\n    Mod+Shift+WheelScrollDown { move-column-right; }\n    Mod+Shift+WheelScrollUp { move-column-left; }\n\n    // Screenshots\n    Print        { screenshot; }\n    Mod+Shift+S  { screenshot; }\n    Mod+Print    { screenshot-screen; }\n    Alt+Print    { screenshot-window; }\n}\n"
  },
  {
    "path": ".config/niri/layout.kdl",
    "content": "layout {\n    gaps 3.5\n    center-focused-column \"never\"\n    always-center-single-column\n\n    preset-column-widths {\n        proportion 0.33333\n        proportion 0.5\n        proportion 0.66667\n    }\n\n    default-column-width { proportion 0.5; }\n\n    focus-ring {\n        off\n        width 1.5\n        active-color \"#d5c4a1\"\n        inactive-color \"#282828\"\n    }\n\n    border {\n        off\n        width 2\n        active-color \"#d5c4a1\"\n        inactive-color \"#282828\"\n    }\n\n    tab-indicator {\n        hide-when-single-tab\n        place-within-column\n        gap 2\n        width 8\n        length total-proportion=0.5\n        position \"left\"\n        gaps-between-tabs 8\n        corner-radius 5\n        active-color \"#d5c4a1\"\n        inactive-color \"#282828\"\n        urgent-color \"blue\"\n    }\n\n    insert-hint {\n        // off\n        on\n        color \"#ffc87f80\"\n        // gradient from=\"#ffbb6680\" to=\"#ffc88080\" angle=45 relative-to=\"workspace-view\"\n    }\n}\n\noverview {\n    zoom 0.50\n    backdrop-color \"#282828\"\n}\n\nrecent-windows {\n    debounce-ms 750\n    open-delay-ms 50\n    highlight {\n        active-color \"#999999ff\"\n        urgent-color \"#ff9999ff\"\n        padding 30\n        corner-radius 8\n    }\n    previews {\n        max-height 480\n        max-scale 0.5\n    }\n    binds {\n        Alt+Tab { next-window; }\n        Alt+Shift+Tab { previous-window; }\n        Alt+grave { next-window filter=\"app-id\"; }\n        Alt+Shift+grave { previous-window filter=\"app-id\"; }\n    }\n}\n"
  },
  {
    "path": ".config/niri/outputs.kdl",
    "content": "output \"DP-2\" {\n    mode \"1920x1080@120.000\"\n    scale 1.0\n    transform \"normal\"\n    position x=1080 y=840\n    variable-refresh-rate on-demand=true\n    focus-at-startup\n}\n\noutput \"HDMI-A-1\" {\n    mode \"1920x1080@60.000\"\n    scale 1.0\n    transform \"270\"\n    position x=-0 y=0\n    variable-refresh-rate on-demand=true\n}\n\noutput \"eDP-1\" {\n    mode \"1920x1200@60.003\"\n    scale 1.25\n    variable-refresh-rate on-demand=true\n}\n"
  },
  {
    "path": ".config/niri/rules.kdl",
    "content": "window-rule {\n    geometry-corner-radius 8\n    clip-to-geometry true\n    draw-border-with-background false\n}\n\nwindow-rule {\n    match app-id=\"alacritty\"\n    default-column-width {\n        proportion 0.5\n    }\n}\n\nwindow-rule {\n    match app-id=\"chatterino\"\n    match app-id=\"com.chatterino.chatterino\"\n    default-column-width {\n            proportion 0.298\n    }\n}\n\nwindow-rule {\n    match app-id=\"pcmanfm-qt\"\n    match app-id=\"dolphin$\"\n    match app-id=\"librewolf$\"\n    match app-id=\"firefox$\"\n    open-maximized true\n    default-column-width {\n            proportion 1.0;\n    }\n}\n\nwindow-rule {\n    match app-id=\"librewolf$\"\n    match app-id=\"pcmanfm-qt\"\n    match app-id=\"com.chatterino.chatterino\"\n    match app-id=\"spotube\"\n    //opacity 0.95\n}\n\nwindow-rule {\n    match app-id=\"firefox$\" title=\"^Picture-in-Picture$\"\n    match app-id=\"librewolf$\" title=\"^Picture-in-Picture$\"\n    open-floating true\n    default-floating-position x=16 y=16 relative-to=\"bottom-left\"\n}\n\nwindow-rule {\n    match app-id=r#\"xdg-desktop-portal-.*\"#\n    match title=r#\"(?i)dialog\"#\n    match title=r#\"^Extension: \"#\n    match title=r#\"^File Properties\"#\n\n    open-floating true\n    default-column-width {\n        proportion 0.65\n    }\n    default-window-height {\n        proportion 0.35\n    }\n}\n\nwindow-rule {\n    match app-id=r#\"^steam_app_.*$\"#\n    match app-id=\"gamescope\"\n    // This catches Wine/Proton games:\n    match app-id=r#\".*\\.exe$\"#\n\n    match title=r#\"(?i)emulator|yuzu|ryujinx|pcsx2|rpcs3|edin|dolphin|retroarch\"#\n    variable-refresh-rate true\n}\n"
  },
  {
    "path": ".config/niri/scripts/obs-replay",
    "content": "#!/bin/sh\n\n/home/lyes/Videos/rec/pipobs/bin/python3 /home/lyes/Videos/rec/pipobs/replay.py\n"
  },
  {
    "path": ".config/niri/scripts/waybar",
    "content": "#!/bin/sh\nwaybar -c \"$HOME/.config/waybar/stacking-config\" -s \"$HOME/.config/waybar/style.css\" >/dev/null 2>&1 &\n"
  },
  {
    "path": ".config/nvim/init.lua",
    "content": "require(\"speyll.settings\")\nrequire(\"speyll.remap\")\nrequire(\"speyll.commands\")\nrequire(\"speyll.lazy\")\n"
  },
  {
    "path": ".config/nvim/lua/speyll/commands.lua",
    "content": "-- Trim trailing whitespace from the current file\nvim.api.nvim_create_user_command(\n  'TrimWhitespace',\n  function()\n    local save_search = vim.fn.getreg('/')\n    vim.cmd([[%s/\\s\\+$//e]])\n    vim.fn.setreg('/', save_search)\n  end,\n  {}\n)\n\n-- Toggle spell checking in the current buffer\nvim.api.nvim_create_user_command(\n  'ToggleSpell',\n  function()\n    vim.wo.spell = not vim.wo.spell\n  end,\n  {}\n)\n\n-- Toggle text wrapping in the current buffer\nvim.api.nvim_create_user_command(\n  'ToggleWrap',\n  function()\n    vim.wo.wrap = not vim.wo.wrap\n  end,\n  {}\n)\n\n-- Project-wide search without moving from the current buffer\nvim.api.nvim_create_user_command(\n    'PGrep', 'silent grep! <args> | copen', { nargs = 1 }\n)\n\n-- Toggle relative line numbers\nvim.api.nvim_create_user_command(\n  'ToggleRelNum',\n  function()\n    vim.wo.relativenumber = not vim.wo.relativenumber\n  end,\n  {}\n)\n\n-- Replace all occurrences of a term in the document\nvim.api.nvim_create_user_command(\n  'ReplaceAll',\n  function(opts)\n    local search = opts.fargs[1]\n    local replace = opts.fargs[2] or ''\n    vim.cmd(string.format(\"%%s/%s/%s/g\", vim.fn.escape(search, \"/\\\\\"), vim.fn.escape(replace, \"/\\\\\")))\n  end,\n  { nargs = '+' }\n)\n\n-- Quick diff view\nvim.api.nvim_create_user_command(\n  'ToggleDiff',\n  function()\n    vim.wo.diff = not vim.wo.diff\n  end,\n  {}\n)\n\n-- Delete all empty lines\nvim.api.nvim_create_user_command(\n  'DelEmptyLines',\n  function()\n    vim.cmd([[%s/^\\n//]])\n  end,\n  {}\n)\n"
  },
  {
    "path": ".config/nvim/lua/speyll/lazy.lua",
    "content": "local lazypath = vim.fn.stdpath(\"data\") .. \"/lazy/lazy.nvim\"\nif not (vim.uv or vim.loop).fs_stat(lazypath) then\n  vim.fn.system({\n    \"git\",\n    \"clone\",\n    \"--filter=blob:none\",\n    \"https://github.com/folke/lazy.nvim.git\",\n    \"--branch=stable\", -- latest stable release\n    lazypath,\n  })\nend\nvim.opt.rtp:prepend(lazypath)\n\nrequire(\"lazy\").setup(\"speyll.plugins\")\n"
  },
  {
    "path": ".config/nvim/lua/speyll/plugins/autopairs.lua",
    "content": "return {\n    \"windwp/nvim-autopairs\",\n    event = \"InsertEnter\",\n    config = function()\n        require(\"nvim-autopairs\").setup({\n            disable_filetype = { \"TelescopePrompt\", \"vim\" },\n        })\n    end,\n}\n"
  },
  {
    "path": ".config/nvim/lua/speyll/plugins/cmp.lua",
    "content": "return {\n    \"hrsh7th/nvim-cmp\",\n    event = \"InsertEnter\",\n    dependencies = {\n        \"hrsh7th/cmp-buffer\", -- source for text in buffer\n        \"hrsh7th/cmp-path\", -- source for file system paths\n        {\n            \"L3MON4D3/LuaSnip\",\n            version = \"v2.*\",\n            -- install jsregexp (optional!).\n            build = \"make install_jsregexp\",\n        },\n        \"rafamadriz/friendly-snippets\",\n        \"onsails/lspkind.nvim\", -- vs-code like pictograms\n    },\n    config = function()\n        local cmp = require(\"cmp\")\n        local lspkind = require(\"lspkind\")\n        local luasnip = require(\"luasnip\")\n\n        require(\"luasnip.loaders.from_vscode\").lazy_load()\n\n        cmp.setup({\n            snippet = {\n                expand = function(args)\n                    luasnip.lsp_expand(args.body)\n                end,\n            },\n            mapping = cmp.mapping.preset.insert({\n                [\"<C-d>\"] = cmp.mapping.scroll_docs(-4),\n                [\"<C-f>\"] = cmp.mapping.scroll_docs(4),\n                [\"<C-Space>\"] = cmp.mapping.complete(),\n                [\"<C-e>\"] = cmp.mapping.close(),\n                [\"<CR>\"] = cmp.mapping.confirm({\n                    behavior = cmp.ConfirmBehavior.Replace,\n                    select = true,\n                }),\n            }),\n            sources = cmp.config.sources({\n                { name = \"nvim_lsp\" },\n                { name = \"luasnip\" },\n                { name = \"buffer\" },\n                { name = \"path\" },\n            }),\n        })\n\n        vim.cmd([[\n      set completeopt=menuone,noinsert,noselect\n      highlight! default link CmpItemKind CmpItemMenuDefault\n    ]])\n    end,\n}\n"
  },
  {
    "path": ".config/nvim/lua/speyll/plugins/colorscheme.lua",
    "content": "return {\n    'RRethy/nvim-base16',\n    config = function()\n        require('base16-colorscheme').setup({\n            -- Start flavours\n            base00 = \"none\", base01 = \"#3c3836\", base02 = \"#504945\", base03 = \"#665c54\",\n            base04 = \"#bdae93\", base05 = \"#d5c4a1\", base06 = \"#ebdbb2\", base07 = \"#fbf1c7\",\n            base08 = \"#fb4934\", base09 = \"#fe8019\", base0A = \"#fabd2f\", base0B = \"#b8bb26\",\n            base0C = \"#8ec07c\", base0D = \"#83a598\", base0E = \"#d3869b\", base0F = \"#d65d0e\"\n            -- End flavours\n        })\n        -- Ensure that Normal background is set to transparent\n        vim.cmd(\"highlight Normal guibg=none\")\n    end\n}\n"
  },
  {
    "path": ".config/nvim/lua/speyll/plugins/nvim-hardline.lua",
    "content": "return {\n    'ojroques/nvim-hardline',\n    config = function()\n        require('hardline').setup {\n            bufferline = false,  -- disable bufferline\n            bufferline_settings = {\n                exclude_terminal = false,  -- don't show terminal buffers in bufferline\n                show_index = false,        -- show buffer indexes (not the actual buffer numbers) in bufferline\n            },\n            theme = 'custom',\n            -- Start flavours\n            custom_theme = {\n                text = {gui = \"#282828\", cterm = \"235\", cterm16 = \"0\"},\n                normal = {gui = \"#83a598\", cterm = \"109\", cterm16 = \"6\"},\n                insert = {gui = \"#b8bb26\", cterm = \"142\", cterm16 = \"2\"},\n                replace = {gui = \"#fabd2f\", cterm = \"214\", cterm16 = \"3\"},\n                inactive_comment = {gui = \"NONE\", cterm = \"NONE\", cterm16 = \"NONE\"},\n                inactive_cursor = {gui = \"NONE\", cterm = \"NONE\", cterm16 = \"NONE\"},\n                inactive_menu = {gui = \"NONE\", cterm = \"NONE\", cterm16 = \"NONE\"},\n                visual = {gui = \"#8ec07c\", cterm = \"108\", cterm16 = \"6\"},\n                command = {gui = \"#d3869b\", cterm = \"132\", cterm16 = \"5\"},\n                alt_text = {gui = \"#ebdbb2\", cterm = \"223\", cterm16 = \"7\"},\n                warning = {gui = \"#fb4934\", cterm = \"167\", cterm16 = \"1\"},\n            },\n            -- End flavours\n            sections = {         -- define sections\n                {class = 'mode', item = require('hardline.parts.mode').get_item},\n                {class = 'high', item = require('hardline.parts.git').get_item, hide = 100},\n                {class = 'med', item = require('hardline.parts.filename').get_item},\n                '%<',\n                {class = 'med', item = '%='},\n                {class = 'low', item = require('hardline.parts.wordcount').get_item, hide = 100},\n                {class = 'error', item = require('hardline.parts.lsp').get_error},\n                {class = 'warning', item = require('hardline.parts.lsp').get_warning},\n                {class = 'warning', item = require('hardline.parts.whitespace').get_item},\n                {class = 'high', item = require('hardline.parts.filetype').get_item, hide = 60},\n                {class = 'mode', item = require('hardline.parts.line').get_item},\n            },\n        }\n    end\n}\n"
  },
  {
    "path": ".config/nvim/lua/speyll/plugins/nvim-highlight-colors.lua",
    "content": "return {\n    'brenoprata10/nvim-highlight-colors',\n    config = function()\n        require('nvim-highlight-colors').setup {\n            render = 'background', -- Or 'foreground', depending on your preference\n            enable_named_colors = true, -- Enable parsing of named colors\n            enable_tailwind = true, -- Optional: Enable TailwindCSS color classes\n        }\n    end\n}\n\n"
  },
  {
    "path": ".config/nvim/lua/speyll/plugins/telescope.lua",
    "content": "return {\n    'nvim-telescope/telescope.nvim', tag = '0.1.6',\n    dependencies = { 'nvim-lua/plenary.nvim' },\n    config = function()\n        local home = vim.fn.expand(\"~\") -- Expands the home directory\n\n        require('telescope').setup{\n            defaults = {\n                file_ignore_patterns = {\n                    \"%.jpg\", \"%.jpeg\", \"%.png\", \"%.gif\", \"%.bmp\", \"%.tiff\", \"%.webp\", \"%.kra\", -- image formats\n                    \"%.mp4\", \"%.mkv\", \"%.webm\", \"%.avi\", \"%.mov\", \"%.flv\", \"%.wmv\", -- video formats\n                    \"%.mp3\", \"%.wav\", \"%.flac\", \"%.m4a\", -- audio formats\n                }\n            }\n        }\n\n        local builtin = require('telescope.builtin')\n        vim.keymap.set('n', '<leader>pf', builtin.find_files, {})\n        vim.keymap.set('n', '<C-p>', builtin.git_files, {})\n        vim.keymap.set('n', '<leader>pws', function()\n            local word = vim.fn.expand(\"<cword>\")\n            builtin.grep_string({ search = word })\n        end)\n        vim.keymap.set('n', '<leader>pWs', function()\n            local word = vim.fn.expand(\"<cWORD>\")\n            builtin.grep_string({ search = word })\n        end)\n        vim.keymap.set('n', '<leader>ps', function()\n            builtin.grep_string({ search = vim.fn.input(\"Grep > \") })\n        end)\n        vim.keymap.set('n', '<leader>vh', builtin.help_tags, {})\n    end\n}\n\n"
  },
  {
    "path": ".config/nvim/lua/speyll/plugins/treesitter.lua",
    "content": "return {\n    \"nvim-treesitter/nvim-treesitter\",\n    branch = \"main\", -- The new rewrite branch\n    build = \":TSUpdate\",\n    event = { \"BufReadPre\", \"BufNewFile\" },\n    -- Configuration now happens directly in 'opts'\n    opts = {\n        ensure_installed = {\n            \"json\", \"javascript\", \"typescript\", \"tsx\", \"yaml\",\n            \"html\", \"css\", \"markdown\", \"markdown_inline\", \"bash\",\n            \"lua\", \"vim\", \"dockerfile\", \"gitignore\", \"c\", \"rust\",\n        },\n        highlight = { enable = true },\n        indent = { enable = true },\n    },\n    config = function(_, opts)\n        -- In the 'main' branch, use the core module directly\n        require(\"nvim-treesitter\").setup(opts)\n    end,\n}\n"
  },
  {
    "path": ".config/nvim/lua/speyll/plugins/undotree.lua",
    "content": "return {\n    \"mbbill/undotree\",\n\n    config = function() \n        vim.keymap.set(\"n\", \"<leader>u\", vim.cmd.UndotreeToggle)\n    end\n}\n"
  },
  {
    "path": ".config/nvim/lua/speyll/remap.lua",
    "content": "vim.g.mapleader = \" \"\nvim.keymap.set(\"n\", \"<leader>pv\", vim.cmd.Ex)\n\nvim.keymap.set(\"v\", \"J\", \":m '>+1<CR>gv=gv\")\nvim.keymap.set(\"v\", \"K\", \":m '<-2<CR>gv=gv\")\n\nvim.keymap.set(\"n\", \"J\", \"mzJ`z\")\nvim.keymap.set(\"n\", \"<C-d>\", \"<C-d>zz\")\nvim.keymap.set(\"n\", \"<C-u>\", \"<C-u>zz\")\nvim.keymap.set(\"n\", \"n\", \"nzzzv\")\nvim.keymap.set(\"n\", \"N\", \"Nzzzv\")\n\n-- greatest remap ever\nvim.keymap.set(\"x\", \"<leader>p\", [[\"_dP]])\n\n-- next greatest remap ever : asbjornHaland\nvim.keymap.set({\"n\", \"v\"}, \"<leader>y\", [[\"+y]])\nvim.keymap.set(\"n\", \"<leader>Y\", [[\"+Y]])\n\nvim.keymap.set({\"n\", \"v\"}, \"<leader>d\", [[\"_d]])\n\n-- This is going to get me cancelled\nvim.keymap.set(\"i\", \"<C-c>\", \"<Esc>\")\n\nvim.keymap.set(\"n\", \"Q\", \"<nop>\")\nvim.keymap.set(\"n\", \"<C-f>\", \"<cmd>silent !tmux neww tmux-sessionizer<CR>\")\nvim.keymap.set(\"n\", \"<leader>f\", vim.lsp.buf.format)\n\nvim.keymap.set(\"n\", \"<C-k>\", \"<cmd>cnext<CR>zz\")\nvim.keymap.set(\"n\", \"<C-j>\", \"<cmd>cprev<CR>zz\")\nvim.keymap.set(\"n\", \"<leader>k\", \"<cmd>lnext<CR>zz\")\nvim.keymap.set(\"n\", \"<leader>j\", \"<cmd>lprev<CR>zz\")\n\nvim.keymap.set(\"n\", \"<leader>s\", [[:%s/\\<<C-r><C-w>\\>/<C-r><C-w>/gI<Left><Left><Left>]])\nvim.keymap.set(\"n\", \"<leader>x\", \"<cmd>!chmod +x %<CR>\", { silent = true })\n\nvim.keymap.set(\n    \"n\",\n    \"<leader>ee\",\n    \"oif err != nil {<CR>}<Esc>Oreturn err<Esc>\"\n)\n\nvim.keymap.set(\"n\", \"<leader><leader>\", function()\n    vim.cmd(\"so\")\nend)\n"
  },
  {
    "path": ".config/nvim/lua/speyll/settings.lua",
    "content": "vim.opt.guicursor = \"\"\nvim.opt.cursorline = false\n\nvim.opt.nu = true\nvim.opt.relativenumber = true\n\nvim.opt.tabstop = 4\nvim.opt.softtabstop = 4\nvim.opt.shiftwidth = 4\nvim.opt.expandtab = true\n\nvim.opt.smartindent = true\n\nvim.opt.wrap = true\n\nvim.opt.swapfile = false\nvim.opt.backup = false\nvim.opt.undodir = os.getenv(\"HOME\") .. \"/.cache/nvim/undodir\"\nvim.opt.undofile = true\n\nvim.opt.hlsearch = false\nvim.opt.incsearch = true\n\nvim.opt.termguicolors = true\n\nvim.opt.scrolloff = 8\nvim.opt.signcolumn = \"yes\"\nvim.opt.isfname:append(\"@-@\")\n\nvim.opt.updatetime = 50\n\nvim.opt.colorcolumn = \"80\"\n"
  },
  {
    "path": ".config/pcmanfm-qt/default/recent-files.conf",
    "content": "[Recent]\nFiles=@Invalid()\n"
  },
  {
    "path": ".config/pcmanfm-qt/default/settings.conf",
    "content": "[Behavior]\nAutoSelectionDelay=600\nBookmarkOpenMethod=current_tab\nConfirmDelete=true\nConfirmTrash=false\nCtrlRightClick=false\nNoUsbTrash=false\nQuickExec=false\nRecentFilesNumber=0\nSelectNewFiles=false\nSingleClick=false\nSingleWindowMode=false\nUseTrash=true\n\n[Desktop]\nAllSticky=false\nBgColor=#000000\nDesktopCellMargins=@Size(3 1)\nDesktopIconSize=48\nDesktopShortcuts=@Invalid()\nFgColor=#ffffff\nFont=\"Noto Sans,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1\"\nHideItems=false\nLastSlide=\nNoItemTooltip=false\nOpenWithDefaultFileManager=false\nPerScreenWallpaper=false\nShadowColor=#000000\nShowHidden=false\nSlideShowInterval=0\nSortColumn=name\nSortFolderFirst=true\nSortHiddenLast=false\nSortOrder=ascending\nTransformWallpaper=false\nWallpaper=\nWallpaperDialogSize=@Size(700 500)\nWallpaperDialogSplitterPos=200\nWallpaperDirectory=\nWallpaperMode=none\nWallpaperRandomize=false\nWorkAreaMargins=12, 12, 12, 12\n\n[FolderView]\nBackupAsHidden=false\nBigIconSize=48\nCustomColumnWidths=@Invalid()\nFolderViewCellMargins=@Size(3 3)\nHiddenColumns=@Invalid()\nMode=thumbnail\nNoItemTooltip=false\nScrollPerPixel=true\nShadowHidden=true\nShowFilter=false\nShowFullNames=true\nShowHidden=true\nSidePaneIconSize=24\nSmallIconSize=24\nSortCaseSensitive=false\nSortColumn=name\nSortFolderFirst=true\nSortHiddenLast=false\nSortOrder=ascending\nThumbnailIconSize=128\n\n[Places]\nHiddenPlaces=@Invalid()\n\n[Search]\nContentPatterns=@Invalid()\nMaxSearchHistory=0\nNamePatterns=@Invalid()\nsearchContentCaseInsensitive=false\nsearchContentRegexp=true\nsearchNameCaseInsensitive=false\nsearchNameRegexp=true\nsearchRecursive=true\nsearchhHidden=true\n\n[System]\nArchiver=lxqt-archiver\nFallbackIconThemeName=oxygen\nOnlyUserTemplates=false\nSIUnit=false\nSuCommand=lxqt-sudo %s\nTemplateRunApp=false\nTemplateTypeOnce=false\nTerminal=alacritty\n\n[Thumbnail]\nMaxExternalThumbnailFileSize=-1\nMaxThumbnailFileSize=10240\nShowThumbnails=true\nThumbnailLocalFilesOnly=false\n\n[Volume]\nAutoRun=true\nCloseOnUnmount=true\nMountOnStartup=true\nMountRemovable=true\n\n[Window]\nAlwaysShowTabs=true\nFixedHeight=480\nFixedWidth=640\nLastWindowHeight=1072\nLastWindowMaximized=false\nLastWindowWidth=1214\nPathBarButtons=false\nRememberWindowSize=true\nReopenLastTabs=false\nShowMenuBar=true\nShowTabClose=true\nSidePaneMode=places\nSidePaneVisible=true\nSplitView=false\nSplitViewTabsNum=0\nSplitterPos=145\nSwitchToNewTab=false\nTabPaths=@Invalid()\n"
  },
  {
    "path": ".config/pipewire/pipewire-pulse.conf.d/switch-on-connect.conf",
    "content": "pulse.cmd = [\n    { cmd = \"load-module\" args = \"module-always-sink\" flags = [ ] }\n    { cmd = \"load-module\" args = \"module-switch-on-connect\" }\n]\n"
  },
  {
    "path": ".config/pipewire/pipewire.conf",
    "content": "# Daemon config file for PipeWire version \"1.2.5\" #\n#\n# Copy and edit this file in /etc/pipewire for system-wide changes\n# or in ~/.config/pipewire for local changes.\n#\n# It is also possible to place a file with an updated section in\n# /etc/pipewire/pipewire.conf.d/ for system-wide changes or in\n# ~/.config/pipewire/pipewire.conf.d/ for local changes.\n#\n\ncontext.properties = {\n    ## Configure properties in the system.\n    #library.name.system                   = support/libspa-support\n    #context.data-loop.library.name.system = support/libspa-support\n    #support.dbus                          = true\n    #link.max-buffers                      = 64\n    link.max-buffers                       = 16                       # version < 3 clients can't handle more\n    #mem.warn-mlock                        = false\n    #mem.allow-mlock                       = true\n    #mem.mlock-all                         = false\n    #clock.power-of-two-quantum            = true\n    #log.level                             = 2\n    #cpu.zero.denormals                    = false\n\n    #loop.rt-prio = -1            # -1 = use module-rt prio, 0 disable rt\n    #loop.class = data.rt\n    #thread.affinity = [ 0 1 ]    # optional array of CPUs\n    #context.num-data-loops = 1   # -1 = num-cpus, 0 = no data loops\n    #\n    #context.data-loops = [\n    #    {   loop.rt-prio = -1\n    #        loop.class = [ data.rt audio.rt ]\n    #        #library.name.system = support/libspa-support\n    #        thread.name = data-loop.0\n    #        #thread.affinity = [ 0 1 ]    # optional array of CPUs\n    #    }\n    #]\n\n    core.daemon = true              # listening for socket connections\n    core.name   = pipewire-0        # core name and socket name\n\n    ## Properties for the DSP configuration.\n    default.clock.rate = 48000\n    #default.clock.allowed-rates = [ 48000 ]\n    default.clock.quantum = 512\n    default.clock.min-quantum = 128\n    default.clock.max-quantumn = 2048\n    #default.clock.quantum-limit = 8192\n    #default.clock.quantum-floor = 4\n    #default.video.width         = 640\n    #default.video.height        = 480\n    #default.video.rate.num      = 25\n    #default.video.rate.denom    = 1\n    #\n    #settings.check-quantum      = false\n    #settings.check-rate         = false\n\n    # keys checked below to disable module loading\n    module.x11.bell = true\n    # enables autoloading of access module, when disabled an alternative\n    # access module needs to be loaded.\n    module.access = true\n    # enables autoloading of module-jackdbus-detect\n    module.jackdbus-detect = true\n}\n\ncontext.properties.rules = [\n    {   matches = [ { cpu.vm.name = !null } ]\n        actions = {\n            update-props = {\n                # These overrides are only applied when running in a vm.\n                default.clock.min-quantum = 1024\n\t    }\n        }\n    }\n]\n\ncontext.spa-libs = {\n    #<factory-name regex> = <library-name>\n    #\n    # Used to find spa factory names. It maps an spa factory name\n    # regular expression to a library name that should contain\n    # that factory.\n    #\n    audio.convert.* = audioconvert/libspa-audioconvert\n    avb.*           = avb/libspa-avb\n    api.alsa.*      = alsa/libspa-alsa\n    api.v4l2.*      = v4l2/libspa-v4l2\n    api.libcamera.* = libcamera/libspa-libcamera\n    api.bluez5.*    = bluez5/libspa-bluez5\n    api.vulkan.*    = vulkan/libspa-vulkan\n    api.jack.*      = jack/libspa-jack\n    support.*       = support/libspa-support\n    video.convert.* = videoconvert/libspa-videoconvert\n    #videotestsrc   = videotestsrc/libspa-videotestsrc\n    #audiotestsrc   = audiotestsrc/libspa-audiotestsrc\n}\n\ncontext.modules = [\n    #{ name = <module-name>\n    #    ( args  = { <key> = <value> ... } )\n    #    ( flags = [ ( ifexists ) ( nofail ) ] )\n    #    ( condition = [ { <key> = <value> ... } ... ] )\n    #}\n    #\n    # Loads a module with the given parameters.\n    # If ifexists is given, the module is ignored when it is not found.\n    # If nofail is given, module initialization failures are ignored.\n    # If condition is given, the module is loaded only when the context\n    # properties all match the match rules.\n    #\n\n    # Uses realtime scheduling to boost the audio thread priorities. This uses\n    # RTKit if the user doesn't have permission to use regular realtime\n    # scheduling. You can also clamp utilisation values to improve scheduling\n    # on embedded and heterogeneous systems, e.g. Arm big.LITTLE devices.\n    { name = libpipewire-module-rt\n        args = {\n            nice.level    = -11\n            rt.prio       = 88\n            #rt.time.soft = -1\n            #rt.time.hard = -1\n            #uclamp.min = 0\n            #uclamp.max = 1024\n        }\n        flags = [ ifexists nofail ]\n    }\n\n    # The native communication protocol.\n    { name = libpipewire-module-protocol-native\n        args = {\n            # List of server Unix sockets, and optionally permissions\n            #sockets = [ { name = \"pipewire-0\" }, { name = \"pipewire-0-manager\" } ]\n        }\n    }\n\n    # The profile module. Allows application to access profiler\n    # and performance data. It provides an interface that is used\n    # by pw-top and pw-profiler.\n    { name = libpipewire-module-profiler }\n\n    # Allows applications to create metadata objects. It creates\n    # a factory for Metadata objects.\n    { name = libpipewire-module-metadata }\n\n    # Creates a factory for making devices that run in the\n    # context of the PipeWire server.\n    { name = libpipewire-module-spa-device-factory }\n\n    # Creates a factory for making nodes that run in the\n    # context of the PipeWire server.\n    { name = libpipewire-module-spa-node-factory }\n\n    # Allows creating nodes that run in the context of the\n    # client. Is used by all clients that want to provide\n    # data to PipeWire.\n    { name = libpipewire-module-client-node }\n\n    # Allows creating devices that run in the context of the\n    # client. Is used by the session manager.\n    { name = libpipewire-module-client-device }\n\n    # The portal module monitors the PID of the portal process\n    # and tags connections with the same PID as portal\n    # connections.\n    { name = libpipewire-module-portal\n        flags = [ ifexists nofail ]\n    }\n\n    # The access module can perform access checks and block\n    # new clients.\n    { name = libpipewire-module-access\n        args = {\n            # Socket-specific access permissions\n            #access.socket = { pipewire-0 = \"default\", pipewire-0-manager = \"unrestricted\" }\n\n            # Deprecated legacy mode (not socket-based),\n            # for now enabled by default if access.socket is not specified\n            #access.legacy = true\n        }\n        condition = [ { module.access = true } ]\n    }\n\n    # Makes a factory for wrapping nodes in an adapter with a\n    # converter and resampler.\n    { name = libpipewire-module-adapter }\n\n    # Makes a factory for creating links between ports.\n    { name = libpipewire-module-link-factory }\n\n    # Provides factories to make session manager objects.\n    { name = libpipewire-module-session-manager }\n\n    # Use libcanberra to play X11 Bell\n    { name = libpipewire-module-x11-bell\n        args = {\n            #sink.name = \"@DEFAULT_SINK@\"\n            #sample.name = \"bell-window-system\"\n            #x11.display = null\n            #x11.xauthority = null\n        }\n        flags = [ ifexists nofail ]\n        condition = [ { module.x11.bell = true } ]\n    }\n    { name = libpipewire-module-jackdbus-detect\n        args = {\n            #jack.library     = libjack.so.0\n            #jack.server      = null\n            #jack.client-name = PipeWire\n            #jack.connect     = true\n            #tunnel.mode      = duplex  # source|sink|duplex\n            source.props = {\n                #audio.channels = 2\n\t\t#midi.ports = 1\n                #audio.position = [ FL FR ]\n                # extra sink properties\n            }\n            sink.props = {\n                #audio.channels = 2\n\t\t#midi.ports = 1\n                #audio.position = [ FL FR ]\n                # extra sink properties\n            }\n        }\n        flags = [ ifexists nofail ]\n        condition = [ { module.jackdbus-detect = true } ]\n    }\n]\n\ncontext.objects = [\n    #{ factory = <factory-name>\n    #    ( args  = { <key> = <value> ... } )\n    #    ( flags = [ ( nofail ) ] )\n    #    ( condition = [ { <key> = <value> ... } ... ] )\n    #}\n    #\n    # Creates an object from a PipeWire factory with the given parameters.\n    # If nofail is given, errors are ignored (and no object is created).\n    # If condition is given, the object is created only when the context properties\n    # all match the match rules.\n    #\n    #{ factory = spa-node-factory   args = { factory.name = videotestsrc node.name = videotestsrc node.description = videotestsrc \"Spa:Pod:Object:Param:Props:patternType\" = 1 } }\n    #{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = [ nofail ] }\n    #{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } }\n    #{ factory = spa-node-factory   args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } }\n    #{ factory = adapter            args = { factory.name = audiotestsrc node.name = my-test node.description = audiotestsrc } }\n    #{ factory = spa-node-factory   args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } }\n\n    # A default dummy driver. This handles nodes marked with the \"node.always-process\"\n    # property when no other driver is currently active. JACK clients need this.\n    { factory = spa-node-factory\n        args = {\n            factory.name    = support.node.driver\n            node.name       = Dummy-Driver\n            node.group      = pipewire.dummy\n            node.sync-group  = sync.dummy\n            priority.driver = 200000\n            #clock.id       = monotonic # realtime | tai | monotonic-raw | boottime\n            #clock.name     = \"clock.system.monotonic\"\n        }\n    }\n    { factory = spa-node-factory\n        args = {\n            factory.name    = support.node.driver\n            node.name       = Freewheel-Driver\n            priority.driver = 190000\n            node.group      = pipewire.freewheel\n            node.sync-group  = sync.dummy\n            node.freewheel  = true\n            #freewheel.wait = 10\n        }\n    }\n\n    # This creates a new Source node. It will have input ports\n    # that you can link, to provide audio for this source.\n    #{ factory = adapter\n    #    args = {\n    #        factory.name     = support.null-audio-sink\n    #        node.name        = \"my-mic\"\n    #        node.description = \"Microphone\"\n    #        media.class      = \"Audio/Source/Virtual\"\n    #        audio.position   = \"FL,FR\"\n    #        monitor.passthrough = true\n    #    }\n    #}\n\n    # This creates a single PCM source device for the given\n    # alsa device path hw:0. You can change source to sink\n    # to make a sink in the same way.\n    #{ factory = adapter\n    #    args = {\n    #        factory.name           = api.alsa.pcm.source\n    #        node.name              = \"alsa-source\"\n    #        node.description       = \"PCM Source\"\n    #        media.class            = \"Audio/Source\"\n    #        api.alsa.path          = \"hw:0\"\n    #        api.alsa.period-size   = 1024\n    #        api.alsa.headroom      = 0\n    #        api.alsa.disable-mmap  = false\n    #        api.alsa.disable-batch = false\n    #        audio.format           = \"S16LE\"\n    #        audio.rate             = 48000\n    #        audio.channels         = 2\n    #        audio.position         = \"FL,FR\"\n    #    }\n    #}\n\n    # Use the metadata factory to create metadata and some default values.\n    #{ factory = metadata\n    #    args = {\n    #        metadata.name = my-metadata\n    #        metadata.values = [\n    #            { key = default.audio.sink   value = { name = somesink } }\n    #            { key = default.audio.source value = { name = somesource } }\n    #        ]\n    #    }\n    #}\n]\n\ncontext.exec = [\n    #{   path = <program-name>\n    #    ( args = \"<arguments>\" | [ <arg1> <arg2> ... ] )\n    #    ( condition = [ { <key> = <value> ... } ... ] )\n    #}\n    #\n    # Execute the given program with arguments.\n    # If condition is given, the program is executed only when the context\n    # properties all match the match rules.\n    #\n    # You can optionally start the session manager here,\n    # but it is better to start it as a systemd service.\n    # Run the session manager with -h for options.\n    #\n    #{ path = \"/usr/bin/pipewire-media-session\" args = \"\"\n    #  condition = [ { exec.session-manager = null } { exec.session-manager = true } ] }\n    #\n    # You can optionally start the pulseaudio-server here as well\n    # but it is better to start it as a systemd service.\n    # It can be interesting to start another daemon here that listens\n    # on another address with the -a option (eg. -a tcp:4713).\n    #\n    #{ path = \"/usr/bin/pipewire\" args = [ \"-c\" \"pipewire-pulse.conf\" ]\n    #  condition = [ { exec.pipewire-pulse = null } { exec.pipewire-pulse = true } ] }\n]\n"
  },
  {
    "path": ".config/qt5ct/qt5ct.conf",
    "content": "[Appearance]\ncolor_scheme_path=/usr/share/qt5ct/colors/darker.conf\ncustom_palette=false\nicon_theme=breeze\nstandard_dialogs=default\nstyle=Fusion\n\n[Fonts]\nfixed=\"Noto Sans,12,-1,5,50,0,0,0,0,0\"\ngeneral=\"Noto Sans,12,-1,5,50,0,0,0,0,0\"\n\n[Interface]\nactivate_item_on_single_click=1\nbuttonbox_layout=0\ncursor_flash_time=1000\ndialog_buttons_have_icons=1\ndouble_click_interval=400\ngui_effects=@Invalid()\nkeyboard_scheme=4\nmenus_have_icons=true\nshow_shortcuts_in_context_menus=true\nstylesheets=@Invalid()\ntoolbutton_style=4\nunderline_shortcut=1\nwheel_scroll_lines=3\n\n[SettingsWindow]\ngeometry=\"@ByteArray(\\x1\\xd9\\xd0\\xcb\\0\\x3\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\x3,\\0\\0\\x3!\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\x3,\\0\\0\\x3!\\0\\0\\0\\0\\0\\0\\0\\0\\a\\x80\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\x3,\\0\\0\\x3!)\"\n\n[Troubleshooting]\nforce_raster_widgets=1\nignored_applications=@Invalid()\n"
  },
  {
    "path": ".config/qt6ct/qt6ct.conf",
    "content": "[Appearance]\ncolor_scheme_path=/usr/share/color-schemes/BreezeDark.colors\ncustom_palette=true\nicon_theme=breeze\nstandard_dialogs=xdgdesktopportal\nstyle=Breeze\n\n[Fonts]\nfixed=\"Noto Sans,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1\"\ngeneral=\"Noto Sans,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1\"\n\n[Interface]\nactivate_item_on_single_click=1\nbuttonbox_layout=0\ncursor_flash_time=1000\ndialog_buttons_have_icons=1\ndouble_click_interval=400\ngui_effects=@Invalid()\nkeyboard_scheme=2\nmenus_have_icons=true\nshow_shortcuts_in_context_menus=true\nstylesheets=/usr/share/qt6ct/qss/fusion-fixes.qss, /usr/share/qt6ct/qss/scrollbar-simple.qss, /usr/share/qt6ct/qss/sliders-simple.qss, /usr/share/qt6ct/qss/tooltip-simple.qss, /usr/share/qt6ct/qss/traynotification-simple.qss\ntoolbutton_style=4\nunderline_shortcut=1\nwheel_scroll_lines=3\n\n[QSSEditor]\ngeometry=@ByteArray(\\x1\\xd9\\xd0\\xcb\\0\\x3\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\x2\\x82\\0\\0\\x1\\xf2\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\x2\\x82\\0\\0\\x1\\xf2\\0\\0\\0\\0\\0\\0\\0\\0\\a\\x80\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\x2\\x82\\0\\0\\x1\\xf2)\n\n[SettingsWindow]\ngeometry=@ByteArray(\\x1\\xd9\\xd0\\xcb\\0\\x3\\0\\0\\xff\\xff\\xfb\\xc8\\xff\\xff\\xfc\\xb8\\xff\\xff\\xfe\\xa6\\0\\0\\x4\\v\\xff\\xff\\xfb\\xc8\\xff\\xff\\xfc\\xb8\\xff\\xff\\xfe\\xa6\\0\\0\\x4\\v\\0\\0\\0\\0\\0\\0\\0\\0\\x4\\x38\\xff\\xff\\xfb\\xc8\\xff\\xff\\xfc\\xb8\\xff\\xff\\xfe\\xa6\\0\\0\\x4\\v)\n\n[Troubleshooting]\nforce_raster_widgets=1\nignored_applications=@Invalid()\n"
  },
  {
    "path": ".config/qt6ct/style-colors.conf",
    "content": "[ColorScheme]\nactive_colors=#ffffffff, #ff494949, #ff626262, #ff555555, #ff171717, #ff3c3c3c, #ffffffff, #ffffffff, #ffffffff, #ff2e2e2e, #ff3d3d3e, #ff000000, #ff737373, #ffffffff, #ff2eb8e6, #ffff6666, #ff383838, #ffffffff, #ff000000, #ffffffff, #80ffffff, #ff3daee9\ndisabled_colors=#ff808080, #ff424245, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ff808080, #ffffffff, #ff808080, #ff3d3d3d, #ff222020, #ffe7e4e0, #ff12608a, #ff808080, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff3f3f36, #ffffffff, #80ffffff, #ff12608a\ninactive_colors=#ffffffff, #ff494949, #ff626262, #ff555555, #ff171717, #ff3c3c3c, #ffffffff, #ffffffff, #ffffffff, #ff2e2e2e, #ff3d3d3e, #ff000000, #ff737373, #ffffffff, #ff2eb8e6, #ffff6666, #ff383838, #ffffffff, #ff000000, #ffffffff, #80ffffff, #ff3daee9\n"
  },
  {
    "path": ".config/swayimg/config",
    "content": "# vim: filetype=dosini\n\n[general]\nmode = viewer\nposition = auto\noverlay = no\ndecoration = no\nsize = 800,800\nsigusr1 = reload\nsigusr2 = next_file\napp_id = swayimg\n\n# Start flavours\n[viewer]\nwindow = 282828\ntransparency = grid\nscale = optimal\nantialiasing = mks13\nhistory = 1\npreload = 1\n\n[slideshow]\ntime = 5\nwindow = auto\ntransparency = grid\nscale = optimal\nposition = center\nantialiasing = mks13\n\n[gallery]\nsize = 200\ncache = 100\nfill = yes\nantialiasing = none\nwindow = 282828\nbackground = 282828\nselect = ebdbb2\nborder = 8ec07c\nshadow = 665c54\n\n[list]\norder = alpha\nrecursive = no\nall = yes\n\n[font]\nname = monospace\nsize = 14\ncolor = ebdbb2\nshadow = 665c54\n# End flavours\n\n[info]\nshow = no\ninfo_timeout = 5\nstatus_timeout = 3\n\n[info.viewer]\ntop_left = +name,+format,+filesize,+imagesize,+exif\ntop_right = index\nbottom_left = scale,frame\nbottom_right = status\n\n[info.gallery]\ntop_left = none\ntop_right = none\nbottom_left = none\nbottom_right = name,status\n\n[keys.viewer]\nF1 = help\nHome = first_file\nEnd = last_file\nPrior = prev_file\nNext = next_file\nSpace = next_file\nShift+d = prev_dir\nd = next_dir\nShift+o = prev_frame\no = next_frame\nc = skip_file\nt = mode slideshow\ns = animation\nf = fullscreen\nReturn = mode\nLeft = prev_file\nRight = next_file\nUp = step_up 10\nDown = step_down 10\nCtrl+Left = step_left 10\nCtrl+Right = step_right 10\nEqual = zoom +10\nPlus = zoom +10\nMinus = zoom -10\nw = zoom width\nShift+w = zoom height\nz = zoom fit\nShift+z = zoom fill\n0 = zoom real\nBackSpace = zoom optimal\nbracketleft = rotate_left\nbracketright = rotate_right\nm = flip_vertical\nShift+m = flip_horizontal\na = antialiasing\nr = reload\ni = info\nShift+Delete = exec rm \"%\"; skip_file\nEscape = exit\nq = exit\nCtrl+w = exec ~/.config/swayimg/set-wall \"%\"\nCtrl+c = exec wl-copy < \"%\"\n\n# Mouse bindings for viewer mode\nScrollLeft = step_right 5\nScrollRight = step_left 5\nScrollUp = zoom +10\nScrollDown = zoom -10\nCtrl+ScrollUp = step_up 5\nCtrl+ScrollDown = step_down 5\nShift+ScrollUp = prev_file\nShift+ScrollDown = next_file\nAlt+ScrollUp = prev_frame\nAlt+ScrollDown = next_frame\n\n[keys.gallery]\nF1 = help\nHome = first_file\nEnd = last_file\nLeft = step_left\nRight = step_right\nUp = step_up\nDown = step_down\nPrior = page_up\nNext = page_down\nc = skip_file\nf = fullscreen\nReturn = mode\na = antialiasing\nr = reload\ni = info\nShift+Delete = exec rm \"%\"; skip_file\nEscape = exit\nq = exit\nCtrl+w = exec ~/.config/swayimg/set-wall \"%\"\nCtrl+c = exec wl-copy < \"%\"\n\n[keys.slideshow]\nF1 = help\nHome = first_file\nEnd = last_file\nPrior = prev_file\nNext = next_file\nSpace = next_file\nShift+d = prev_dir\nd = next_dir\nShift+o = prev_frame\no = next_frame\nc = skip_file\nt = mode slideshow\ns = animation\nf = fullscreen\nReturn = mode\nLeft = prev_file\nRight = next_file\nUp = step_up 10\nDown = step_down 10\nCtrl+Left = step_left 10\nCtrl+Right = step_right 10\nEqual = zoom +10\nPlus = zoom +10\nMinus = zoom -10\nw = zoom width\nShift+w = zoom height\nz = zoom fit\nShift+z = zoom fill\n0 = zoom real\nBackSpace = zoom optimal\nbracketleft = rotate_left\nbracketright = rotate_right\nm = flip_vertical\nShift+m = flip_horizontal\na = antialiasing\nr = reload\ni = info\nShift+Delete = exec rm \"%\"; skip_file\nEscape = exit\nq = exit\nCtrl+w = exec ~/.config/swayimg/set-wall \"%\"\nCtrl+c = exec wl-copy < \"%\"\n\n# Mouse bindings for gallery mode\nScrollLeft = step_right\nScrollRight = step_left\nScrollUp = step_up\nScrollDown = step_down\n"
  },
  {
    "path": ".config/swayimg/set-wall",
    "content": "#!/bin/sh\nselected_image=\"$1\"\n\n# Check if an image is provided and valid\nif [ -n \"$selected_image\" ] && [ -f \"$selected_image\" ]; then\n    # Kill any existing swaybg instances\n    pkill swaybg\n\n    # Set the selected image as the wallpaper with swaybg\n    swaybg -i \"$selected_image\" -m fill &\n    echo \"Wallpaper set to: $selected_image\"\nelse\n    echo \"No valid image provided.\"\nfi\n"
  },
  {
    "path": ".config/tmux/tmux.conf",
    "content": "# Reload Configuration\nbind-key r source-file $HOME/.config/tmux/tmux.conf\n\n# Human Numbering\nset -g base-index 1\nsetw -g pane-base-index 1 # Make pane numbering consistent with windows\nset -g set-titles on\nset-option -g set-titles-string '#{pane_current_command}'\nset-option -g history-limit 5000\nset-option -g visual-activity on\n\n# UTF-8 Support\nset -q -g status-utf8 on # Expect UTF-8 (tmux < 2.2)\nsetw -q -g utf8 on\n\n# Activity Monitoring\nset -g monitor-activity on\nset -g visual-activity off\nsetw -g window-status-activity-style none\n\n# Terminal Settings\nset -g default-terminal \"xterm-256color\"\nif 'infocmp -x tmux-256color > /dev/null 2>&1' 'set -g default-terminal \"tmux-256color\"'\nset -g bell-action none\nsetw -g clock-mode-colour brightcyan\n\n# Mouse and Escape Time\nset-option -g mouse on\nset -sg escape-time 0\n\n# Clear Pane History\nbind-key -n C-k clear-history\n\n# Pane Creation\nbind-key s split-window -h\nbind-key v split-window -v\n\n# Pane Management\nbind-key < resize-pane -L 5\nbind-key > resize-pane -R 5\nbind-key + resize-pane -U 5\nbind-key - resize-pane -D 5\nbind-key = select-layout even-vertical\nbind-key | select-layout even-horizontal\n\n# Movement Bindings (vi-like)\nbind-key -r k select-pane -U\nbind-key -r j select-pane -D\nbind-key -r h select-pane -L\nbind-key -r l select-pane -R\n\n# Movement Bindings (normal)\nbind-key Up select-pane -U\nbind-key Down select-pane -D\nbind-key Left select-pane -L\nbind-key Right select-pane -R\n\n# Copy Mode (requires xclip)\nbind-key -T copy-mode-vi 'v' send -X begin-selection\nbind-key -T copy-mode-vi 'y' send -X copy-pipe \"wl-copy\"\n\n# Status Bar Configuration\nset -g status on\nset -g status-position bottom\nset -g status-interval 1\nset -g status-justify left\nset -g status-style fg=brightwhite\nsetw -g window-status-current-style fg=green,bg=default\nset -g status-left-length 100\nset -g status-left-style default\nset -g status-left \"#[fg=black]#[bg=orange] #S #[fg=default]#[bg=default] \"\nset -g status-right-length 100\nset -g status-right-style default\nset -g status-right \"#[fg=brightblue]#[bg=default] #(ip addr | grep -e 'state UP' -A 2 | awk '/inet /{printf $2}') #[fg=black]#[bg=brightblue] #(date +'%H:%M') #[fg=default]#[bg=default]\"\n\n# Smart Pane Switching with Vim Awareness\nis_vim=\"ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\\\\S+\\\\/)?g?(view|n?vim?x?)(diff)?$'\"\nbind-key -n C-h if-shell \"$is_vim\" \"send-keys C-h\"  \"select-pane -L\"\nbind-key -n C-j if-shell \"$is_vim\" \"send-keys C-j\"  \"select-pane -D\"\nbind-key -n C-k if-shell \"$is_vim\" \"send-keys C-k\"  \"select-pane -U\"\nbind-key -n C-l if-shell \"$is_vim\" \"send-keys C-l\"  \"select-pane -R\"\n\n# Tmux Version Compatibility\ntmux_version='$(tmux -V | sed -En \"s/^tmux ([0-9]+(.[0-9]+)?).*/\\1/p\")'\nif-shell -b '[ \"$(echo \"$tmux_version < 3.0\" | bc)\" = 1 ]' \\\n  \"bind-key -n 'C-\\\\' if-shell \\\"$is_vim\\\" 'send-keys C-\\\\'  'select-pane -l'\"\nif-shell -b '[ \"$(echo \"$tmux_version >= 3.0\" | bc)\" = 1 ]' \\\n  \"bind-key -n 'C-\\\\' if-shell \\\"$is_vim\\\" 'send-keys C-\\\\\\\\'  'select-pane -l'\"\n\n# Copy Mode Pane Movement\nbind-key -T copy-mode-vi C-h select-pane -L\nbind-key -T copy-mode-vi C-j select-pane -D\nbind-key -T copy-mode-vi C-k select-pane -U\nbind-key -T copy-mode-vi C-l select-pane -R\nbind-key -T copy-mode-vi C-\\\\ select-pane -l\n"
  },
  {
    "path": ".config/user-dirs.dirs",
    "content": "# This file is written by xdg-user-dirs-update\n# If you want to change or add directories, just edit the line you're\n# interested in. All local changes will be retained on the next run.\n# Format is XDG_xxx_DIR=\"$HOME/yyy\", where yyy is a shell-escaped\n# homedir-relative path, or XDG_xxx_DIR=\"/yyy\", where /yyy is an\n# absolute path. No other format is supported.\n#\nXDG_DESKTOP_DIR=\"$HOME/\"\nXDG_DOCUMENTS_DIR=\"$HOME/Documents/\"\nXDG_DOWNLOAD_DIR=\"$HOME/Downloads\"\nXDG_MUSIC_DIR=\"$HOME/Music\"\nXDG_PICTURES_DIR=\"$HOME/Pictures\"\nXDG_VIDEOS_DIR=\"$HOME/Videos\"\nXDG_RECORDINGS_DIR=\"$HOME/Videos/rec\"\nXDG_GAMES_DIR=\"$HOME/Games\"\nXDG_TEMPLATES_DIR=\"$HOME/Templates\"\nXDG_PUBLICSHARE_DIR=\"$HOME/Public\"\n"
  },
  {
    "path": ".config/user-dirs.locale",
    "content": "en_US"
  },
  {
    "path": ".config/wireplumber/wireplumber.conf.d/51-disable-suspension.conf",
    "content": "monitor.alsa.rules = [\n  {\n    matches = [\n      {\n        # Matches all sources\n        node.name = \"~alsa_input.*\"\n      },\n      {\n        # Matches all sinks\n        node.name = \"~alsa_output.*\"\n      }\n    ]\n    actions = {\n      update-props = {\n        session.suspend-timeout-seconds = 0\n        dither.method = \"wannamaker3\", # add dither of desired shape\n        dither.noise = 2, # add additional bits of noise\n      }\n    }\n  }\n]\n# bluetooth devices\nmonitor.bluez.rules = [\n  {\n    matches = [\n      {\n        # Matches all sources\n        node.name = \"~bluez_input.*\"\n      },\n      {\n        # Matches all sinks\n        node.name = \"~bluez_output.*\"\n      }\n    ]\n    actions = {\n      update-props = {\n        session.suspend-timeout-seconds = 0\n      }\n    }\n  }\n]\n"
  },
  {
    "path": ".config/xdg-desktop-portal/kde-portals.conf",
    "content": "[preferred]\ndefault=kde\norg.freedesktop.impl.portal.FileChooser=kde;\norg.freedesktop.impl.portal.Screenshot=kde;\norg.freedesktop.impl.portal.ScreenCast=kde;\norg.freedesktop.impl.portal.RemoteDesktop=kde;\n"
  },
  {
    "path": ".config/xdg-desktop-portal/niri-portals.conf",
    "content": "[preferred]\ndefault=wlr;gtk;gnome\norg.freedesktop.impl.portal.FileChooser=gtk;\norg.freedesktop.impl.portal.ScreenCast=wlr;\norg.freedesktop.impl.portal.Screenshot=wlr;\norg.freedesktop.impl.portal.RemoteDesktop=wlr;\n"
  },
  {
    "path": ".config/xdg-desktop-portal/portals.conf",
    "content": "[preferred]\ndefault=gtk\norg.freedesktop.impl.portal.FileChooser=gtk;\norg.freedesktop.impl.portal.ScreenCast=wlr;\norg.freedesktop.impl.portal.Screenshot=wlr;\norg.freedesktop.impl.portal.RemoteDesktop=wlr;\n"
  },
  {
    "path": ".config/xsettingsd/xsettingsd.conf",
    "content": "Gdk/WindowScalingFactor 1\nNet/ThemeName \"FlatColor\"\nNet/IconThemeName \"breeze-dark\"\nGtk/ButtonImages 1\nGtk/CursorThemeSize 24\nGtk/CursorThemeName \"Kaela-Kovalskia-v2\"\nNet/EnableEventSounds 1\nEnableInputFeedbackSounds 0\nXft/Antialias 1\nXft/Hinting 1\nXft/HintStyle \"hintmedium\"\nXft/RGBA \"rgb\"\n"
  },
  {
    "path": ".inputrc",
    "content": "$include /etc/inputrc\n"
  },
  {
    "path": ".local/bin/archive",
    "content": "#!/bin/sh\n# A combined script for extraction and compression with enhanced features\n# Usage:\n#   - To extract: script_name -x [-c] [-v] archive1 [archive2 ...]\n#   - To compress: script_name -z -f FORMAT -l LEVEL [-v] [-o OUTPUT] DIR_TO_COMPRESS\n\nformat=\"zip\"\nlevel=5\nverbose=false\nextracthere=false\noutput=\"\"\nmode=\"\"\n\nexit_err() {\n  echo \"$1\" >&2\n  exit 1\n}\n\nshow_help() {\n  echo \"Usage: $0 [options] file_or_dir ...\"\n  echo \"Options for extraction:\"\n  echo \"  -x           Extract archive(s)\"\n  echo \"  -c           Extract into the current directory\"\n  echo \"  -v           Verbose output\"\n  echo \"Options for compression:\"\n  echo \"  -z           Compress a file/directory\"\n  echo \"  -f FORMAT    Choose format: zip,7z,tar.gz,tar.bz2,tar.xz,tar.zst (default: zip)\"\n  echo \"  -l LEVEL     Compression level (0-9, default: 5)\"\n  echo \"  -o OUTPUT    Custom output filename\"\n  echo \"  -v           Verbose output\"\n  echo \"  -h           Show this help\"\n  exit 0\n}\n\ncheck_dependency() {\n  if ! command -v \"$1\" >/dev/null; then\n    exit_err \"Error: Required command '$1' not found. Please install it.\"\n  fi\n}\n\nsanitize_name() {\n  echo \"$1\" | sed -e 's/[^[:alnum:].*-]/*/g'\n}\n\nsanitize_dir_contents() {\n  find . -depth \\( -name '*[[:space:]]*' -o -name '*[^[:alnum:].\\_-]*' \\) | while IFS= read -r path; do\n    dir=$(dirname \"$path\")\n    name=$(basename \"$path\")\n    newname=$(echo \"$name\" | sed -e 's/[[:space:]]/*/g' -e 's/[^[:alnum:].*-]/_/g')\n    [ \"$name\" != \"$newname\" ] && mv -- \"$path\" \"$dir/$newname\"\n  done\n}\n\nwhile getopts \"xczf:l:hvo:\" opt; do\n  case \"$opt\" in\n    x) mode=\"extract\" ;;\n    z) mode=\"compress\" ;;\n    c) extracthere=true ;;\n    f) format=$OPTARG ;;\n    l)\n      if ! [ \"$OPTARG\" -eq \"$OPTARG\" ] 2>/dev/null || [ \"$OPTARG\" -lt 0 ] || [ \"$OPTARG\" -gt 9 ]; then\n        exit_err \"Error: Compression level must be 0-9.\"\n      fi\n      level=$OPTARG\n      ;;\n    o) output=$OPTARG ;;\n    v) verbose=true ;;\n    h) show_help ;;\n    *) exit_err \"Invalid option\" ;;\n  esac\ndone\nshift $((OPTIND - 1))\n\nif [ -z \"$mode\" ]; then\n  exit_err \"Error: Specify either -x (extract) or -z (compress).\"\nfi\n\nextract() {\n  [ \"$#\" -gt 0 ] || exit_err \"Error: No files specified for extraction.\"\n\n  for archive_path in \"$@\"; do\n    [ -f \"$archive_path\" ] || { echo \"Warning: File '$archive_path' not found, skipping.\" >&2; continue; }\n\n    archive=\"$(cd \"$(dirname \"$archive_path\")\" && pwd)/$(basename \"$archive_path\")\"\n    original_name=$(basename \"$archive\")\n    safe_name=$(sanitize_name \"$original_name\")\n\n    if [ \"$original_name\" != \"$safe_name\" ]; then\n      mv \"$archive\" \"${archive%/*}/$safe_name\" || exit_err \"Failed to sanitize filename.\"\n      archive=\"${archive%/*}/$safe_name\"\n      trap 'mv \"$archive\" \"${archive%/*}/$original_name\"' EXIT\n    fi\n\n    if ! $extracthere; then\n      dir=\"${archive%.*}\"\n      mkdir -p \"$dir\" && cd \"$dir\" || exit_err \"Failed to create directory.\"\n    fi\n\n    case \"$archive\" in\n      *.tar.bz2|*.tbz2)\n        check_dependency tar\n        tar xjf \"$archive\" $([ \"$verbose\" = true ] && echo \"v\") || exit_err \"Extraction failed.\"\n        ;;\n      *.tar.xz)\n        check_dependency tar\n        tar xf \"$archive\" $([ \"$verbose\" = true ] && echo \"v\") || exit_err \"Extraction failed.\"\n        ;;\n      *.tar.gz|*.tgz)\n        check_dependency tar\n        tar xzf \"$archive\" $([ \"$verbose\" = true ] && echo \"v\") || exit_err \"Extraction failed.\"\n        ;;\n      *.tar.zst)\n        check_dependency tar\n        check_dependency zstd\n        tar -I zstd -xf \"$archive\" $([ \"$verbose\" = true ] && echo \"v\") || exit_err \"Extraction failed.\"\n        ;;\n      *.lzma)\n        check_dependency unlzma\n        unlzma \"$archive\" || exit_err \"Extraction failed.\"\n        ;;\n      *.bz2)\n        check_dependency bunzip2\n        bunzip2 \"$archive\" || exit_err \"Extraction failed.\"\n        ;;\n      *.rar)\n        check_dependency unrar\n        unrar x -ad \"$archive\" $([ \"$verbose\" = true ] && echo \"-or\") || exit_err \"Extraction failed.\"\n        ;;\n      *.gz)\n        check_dependency gunzip\n        gunzip \"$archive\" || exit_err \"Extraction failed.\"\n        ;;\n      *.tar)\n        check_dependency tar\n        tar xf \"$archive\" $([ \"$verbose\" = true ] && echo \"v\") || exit_err \"Extraction failed.\"\n        ;;\n      *.zip)\n        check_dependency unzip\n        if $verbose; then\n          unzip \"$archive\" -v || exit_err \"Extraction failed.\"\n        else\n          unzip \"$archive\" || exit_err \"Extraction failed.\"\n        fi\n        ;;\n      *.Z)\n        check_dependency uncompress\n        uncompress \"$archive\" || exit_err \"Extraction failed.\"\n        ;;\n      *.7z)\n        check_dependency 7z\n        7z x \"$archive\" $([ \"$verbose\" = true ] && echo \"\" || echo \"-bso0\") || exit_err \"Extraction failed.\"\n        ;;\n      *.xz)\n        check_dependency unxz\n        unxz \"$archive\" || exit_err \"Extraction failed.\"\n        ;;\n      *.exe)\n        check_dependency cabextract\n        cabextract \"$archive\" || exit_err \"Extraction failed.\"\n        ;;\n      *)\n        echo \"Warning: Unsupported archive format: $archive, skipping.\" >&2\n        ;;\n    esac\n\n    sanitize_dir_contents\n\n    [ \"$original_name\" != \"$safe_name\" ] && mv \"$archive\" \"${archive%/*}/$original_name\"\n    trap - EXIT\n\n    if ! $extracthere; then\n      cd - >/dev/null || exit_err \"Failed to return to original directory.\"\n    fi\n  done\n}\n\ncompress() {\n  [ -e \"$input\" ] || exit_err \"Error: Input '$input' not found.\"\n  [ -z \"$output\" ] && output=\"$(basename \"$input\").$format\"\n\n  case $format in\n    zip)\n      check_dependency zip\n      zip -r -\"$level\" $([ \"$verbose\" = true ] && echo \"\" || echo \"-q\") \"$output\" \"$input\" || exit_err \"Compression failed.\"\n      ;;\n    7z)\n      check_dependency 7z\n      7z a -mx=\"$level\" $([ \"$verbose\" = true ] && echo \"\" || echo \"-bso0\") \"$output\" \"$input\" || exit_err \"Compression failed.\"\n      ;;\n    tar.gz|tgz)\n      check_dependency tar\n      check_dependency gzip\n      GZIP=-\"$level\" tar czf $([ \"$verbose\" = true ] && echo \"v\" || echo \"\") \"$output\" \"$input\" || exit_err \"Compression failed.\"\n      ;;\n    tar.bz2)\n      check_dependency tar\n      check_dependency bzip2\n      BZIP2=-\"$level\" tar cjf $([ \"$verbose\" = true ] && echo \"v\" || echo \"\") \"$output\" \"$input\" || exit_err \"Compression failed.\"\n      ;;\n    tar.xz)\n      check_dependency tar\n      check_dependency xz\n      XZ_OPT=-\"$level\" tar cJf $([ \"$verbose\" = true ] && echo \"v\" || echo \"\") \"$output\" \"$input\" || exit_err \"Compression failed.\"\n      ;;\n    tar.zst)\n      check_dependency tar\n      check_dependency zstd\n      tar cf - \"$input\" | zstd -\"$level\" -o \"$output\" || exit_err \"Compression failed.\"\n      ;;\n    *)\n      exit_err \"Error: Unsupported format '$format'\"\n      ;;\n  esac\n\n  echo \"Created archive: $(readlink -f \"$output\")\"\n}\n\ncase $mode in\n  extract) extract \"$@\" ;;\n  compress)\n    input=\"$1\"\n    [ -z \"$input\" ] && exit_err \"Error: Please specify a file/directory to compress.\"\n    compress\n    ;;\nesac\n"
  },
  {
    "path": ".local/bin/aria2-grabber",
    "content": "#!/bin/sh\n\n# Set the path for your text file\nTEXT_FILE=\"$HOME/downloads/links.txt\"\n\n# Set the path for the downloaded links file\nDOWNLOADED_FILE=\"$HOME/downloads/downloaded_links.txt\"\n\n# Set the download directory\nDOWNLOAD_DIR=\"/media/BX200/pron/dump/0toEncode\"\n\n# Create an empty links.txt file if it doesn't exist\n: > \"$TEXT_FILE\"\n\n# Create an empty downloaded links file if it doesn't exist\n: > \"$DOWNLOADED_FILE\"\n\n# Function to check if a link is already downloaded\nis_link_downloaded() {\n    grep -qF \"$1\" \"$DOWNLOADED_FILE\"\n}\n\n# Function to add a link to the text file and start download\nadd_link_and_download() {\n    link=\"$1\"\n    if ! is_link_downloaded \"$link\"; then\n        echo \"$link\" >> \"$TEXT_FILE\"\n        notify-send --expire-time=5000 \"Link Added\" \"$link\"\n        aria2c --dir=\"$DOWNLOAD_DIR\" --input-file=\"$TEXT_FILE\" -j3\n        cat \"$TEXT_FILE\" >> \"$DOWNLOADED_FILE\"\n        : > \"$TEXT_FILE\"  # Clear the text file after processing\n    else\n        notify-send --expire-time=5000 \"Link Already Downloaded\" \"$link\"\n    fi\n}\n\n# Main loop to listen to the clipboard and add links\nold_link=\"\"\nwhile true; do\n    new_link=$(wl-paste -n)\n    if [ \"$new_link\" != \"$old_link\" ] && [ \"${new_link#http://}\" != \"$new_link\" ] || [ \"${new_link#https://}\" != \"$new_link\" ]; then\n        add_link_and_download \"$new_link\"\n        old_link=\"$new_link\"\n    fi\n    sleep 1\ndone\n"
  },
  {
    "path": ".local/bin/aria2-lynx-downloader",
    "content": "#!/bin/sh\n\n# Prompt user for URL\nprintf \"Enter the URL: \"\nread url\n\n# Prompt user for pattern to grep\nprintf \"Enter the pattern to grep: \"\nread pattern\n\n# Use lynx to extract links from the URL, grep for the pattern, and pass the result to aria2c\nlynx --dump --listonly --nonumbers --hiddenlinks=ignore \"$url\" | grep -E \"$pattern\" | aria2c -i - -c -x 16 -j 4\n\n"
  },
  {
    "path": ".local/bin/bemoji",
    "content": "#!/bin/sh\n\n# Version and configuration\nVERSION=\"0.4.1\"\nDB_DIR=\"${BEMOJI_DB_LOCATION:-${XDG_DATA_HOME:-$HOME/.local/share}/bemoji}\"\nHISTORY_FILE=\"${BEMOJI_HISTORY_LOCATION:-${XDG_STATE_HOME:-$HOME/.local/state}/bemoji-history.txt}\"\n\n# Default settings\nPRIVATE_MODE=${BEMOJI_PRIVATE_MODE:-false}\nECHO_NEWLINE=${BEMOJI_ECHO_NEWLINE:-false}\nDEFAULT_CMD=${BEMOJI_DEFAULT_CMD:-}\n\n# Command lists\nCMDS=\"\"\n\n# Picker command order\nPICKERS=\"fuzzel bemenu wofi rofi dmenu ilia\"\n\nusage() {\n    cat >&2 <<EOF\nUsage: ${0##*/} [OPTIONS]\nEmoji picker with clipboard and typing support.\n\nOptions:\n  -t, --type          Type selected emoji\n  -c, --clip          Copy to clipboard (default)\n  -e, --echo          Output emoji only\n  -n, --newline       Add newline after output\n  -p, --private       Disable history tracking\n  -P NUM              Limit history display\n  -f FILE             Custom emoji file/URL\n  -D TYPES            Download lists (all,emoji,math,nerd)\n  -v, --version       Show version\n  -h, --help          Show this help\nEOF\n    exit $1\n}\n\nversion() {\n    echo \"bemoji v$VERSION\"\n    echo \"Database: $DB_DIR\"\n    echo \"History: $HISTORY_FILE\"\n    exit 0\n}\n\nmsg() { echo \"$@\" >&2; }\n\nprepare_db() {\n    [ -d \"$DB_DIR\" ] || mkdir -p \"$DB_DIR\"\n\n    if [ -n \"$BEMOJI_DOWNLOAD_LIST\" ]; then\n        if echo \"$BEMOJI_DOWNLOAD_LIST\" | grep -q 'none'; then return; fi\n\n        for type in $(echo \"$BEMOJI_DOWNLOAD_LIST\" | tr ',' ' '); do\n            case $type in\n                all) download_emoji; download_math; download_nerd ;;\n                emoji) download_emoji ;;\n                math) download_math ;;\n                nerd) download_nerd ;;\n            esac\n        done\n    elif [ -z \"$(ls -A \"$DB_DIR\" 2>/dev/null)\" ]; then\n        download_emoji\n    fi\n}\n\ndownload_emoji() {\n    curl -sSL \"https://unicode.org/Public/emoji/latest/emoji-test.txt\" |\n    sed -nE 's/^.*; fully-qualified.*# (.[^ ]*) E[0-9.]+ (.*)$/\\1 \\2/p' > \"$DB_DIR/emojis.txt\"\n}\n\ndownload_math() {\n    curl -sSL \"https://unicode.org/Public/math/latest/MathClassEx-15.txt\" |\n    awk -F';' '/^[^#]/{print $3 \" \" $7}' > \"$DB_DIR/math.txt\"\n}\n\ndownload_nerd() {\n    curl -sSL \"https://raw.githubusercontent.com/ryanoasis/nerd-fonts/master/css/nerd-fonts-generated.css\" |\n    sed -nE '/\\.nf-/ {N;s/\\.nf-(.*):before.*content: \"\\\\?(.*)\";/\\2 \\1/p}' > \"$DB_DIR/nerd.txt\"\n}\n\nget_history() {\n    [ -f \"$HISTORY_FILE\" ] || return\n    limit=${1:-0}\n    [ \"$limit\" -gt 0 ] || limit=$(wc -l < \"$HISTORY_FILE\")\n\n    sort \"$HISTORY_FILE\" | uniq -c | sort -nr |\n    sed -E 's/^ +[0-9]+ //' | head -n \"$limit\"\n}\n\nselect_emoji() {\n    emoji_data=$(get_history \"$bm_limit_recent\")\n    [ -n \"$BEMOJI_CUSTOM_LIST\" ] && {\n        if [ -f \"$BEMOJI_CUSTOM_LIST\" ]; then\n            emoji_data=\"$emoji_data$(cat \"$BEMOJI_CUSTOM_LIST\")\"\n        else\n            emoji_data=\"$emoji_data$(curl -sSL \"$BEMOJI_CUSTOM_LIST\")\"\n        fi\n    } || emoji_data=\"$emoji_data$(cat \"$DB_DIR\"/*.txt)\"\n\n    printf \"%s\" \"$emoji_data\" | sort -u | picker_command\n}\n\npicker_command() {\n    for cmd in $PICKERS; do\n        if command -v \"$cmd\" >/dev/null; then\n            case $cmd in\n                bemenu) exec bemenu -p 🔍 -i -l 20 ;;\n                wofi) exec wofi -p 🔍 -i --show dmenu ;;\n                rofi) exec rofi -p 🔍 -i -dmenu ;;\n                dmenu) exec dmenu -p 🔍 -i -l 20 ;;\n                ilia) exec ilia -n -p textlist -l Emoji ;;\n                fuzzel) exec fuzzel -d -f 'monospace:size=14' -w 30 -l 10 -a bottom-right --x-margin 8 --y-margin 8 ;;\n            esac\n        fi\n    done\n    msg \"No suitable picker found\" && exit 1\n}\n\nclipboard() {\n    if [ -n \"$WAYLAND_DISPLAY\" ]; then\n        wl-copy\n    elif [ -n \"$DISPLAY\" ]; then\n        xclip -selection clipboard\n    else\n        msg \"No clipboard support\" && exit 1\n    fi\n}\n\ntyper() {\n    input=$(cat)\n    [ -n \"$WAYLAND_DISPLAY\" ] && wtype -s 30 \"$input\" ||\n    xdotool type --delay 30 \"$input\"\n}\n\nhandle_selection() {\n    selection=$(echo \"$1\" | awk '{print $1}')\n\n    $PRIVATE_MODE || echo \"$selection\" >> \"$HISTORY_FILE\"\n\n    for cmd in $CMDS; do\n        case $cmd in\n            clip) printf \"%s\" \"$selection\" | clipboard ;;\n            type) printf \"%s\" \"$selection\" | typer ;;\n            echo) $ECHO_NEWLINE && echo \"$selection\" || printf \"%s\" \"$selection\" ;;\n        esac\n    done\n\n    [ -z \"$CMDS\" ] && printf \"%s\" \"$selection\" | clipboard\n}\n\n# Parse arguments\nwhile [ $# -gt 0 ]; do\n    case $1 in\n        -t|--type) CMDS=\"$CMDS type\" ;;\n        -c|--clip) CMDS=\"$CMDS clip\" ;;\n        -e|--echo) CMDS=\"$CMDS echo\" ;;\n        -n|--newline) ECHO_NEWLINE=true ;;\n        -p|--private) PRIVATE_MODE=true ;;\n        -P) bm_limit_recent=$2; shift ;;\n        -f|--file) BEMOJI_CUSTOM_LIST=$2; shift ;;\n        -D) BEMOJI_DOWNLOAD_LIST=$2; shift ;;\n        -v|--version) version ;;\n        -h|--help) usage 0 ;;\n        *) msg \"Invalid option: $1\"; usage 1 ;;\n    esac\n    shift\ndone\n\n# Main flow\nprepare_db\nselection=$(select_emoji) || exit $?\n[ -z \"$selection\" ] && exit 0\n\nhandle_selection \"$selection\"\n"
  },
  {
    "path": ".local/bin/clip-manager",
    "content": "#!/bin/sh\ncliphist list | fuzzel -d -f monospace:size=14 -w 30 -l 10 -a bottom-right --x-margin 8 --y-margin 8 | cliphist decode | wl-copy\n"
  },
  {
    "path": ".local/bin/dircomp",
    "content": "#!/bin/sh\n\n# Check if directories are provided\nif [ -z \"$1\" ] || [ -z \"$2\" ]; then\n    echo \"Usage: $0 <dir1> <dir2>\"\n    exit 1\nfi\n\ndir1=\"$1\"\ndir2=\"$2\"\n\n# Ensure both directories exist\nif [ ! -d \"$dir1\" ] || [ ! -d \"$dir2\" ]; then\n    echo \"Error: One or both directories do not exist.\"\n    exit 1\nfi\n\n# Create named pipes\nmkfifo fifo1 fifo2\n\n# List files in the top-level of both directories, sort, and write to named pipes\n(find \"$dir1\" -maxdepth 1 -type f -exec basename {} \\; | sort > fifo1) &\n(find \"$dir2\" -maxdepth 1 -type f -exec basename {} \\; | sort > fifo2) &\n\n# Compare file lists using comm\ncomm -23 fifo1 fifo2\n\n# Clean up named pipes\nrm fifo1 fifo2\n"
  },
  {
    "path": ".local/bin/exefind",
    "content": "#!/bin/bash\n\n# Expanded noise list\nIGNORE=\"librewolf|vesktop|alacritty|swaybg|gvfs|xdg|pipewire|wireplumber|lsfg-vk-ui|Isolated|Web Content|niri|Xwayland|bash|grep|stat|cat|basename|readlink|tr|head\"\n\nfor pid_path in /proc/[0-9]*; do\n    pid=$(basename \"$pid_path\")\n\n    # Quick check for ownership to avoid permission errors\n    [[ ! -O \"$pid_path\" ]] && continue\n    owner=$(stat -c %U \"$pid_path\" 2>/dev/null)\n\n    if [[ \"$owner\" == \"$USER\" ]]; then\n        # Check for GPU driver usage\n        if grep -qiE 'vulkan|amdvlk|radv|nvidia' \"$pid_path/maps\" 2>/dev/null; then\n            procname=$(cat \"$pid_path/comm\" 2>/dev/null)\n            [[ \"$procname\" =~ $IGNORE ]] && continue\n\n            # 1. Try to find the Windows .exe in cmdline\n            # Changed 'steam\\.exe' to '^steam\\.exe$' or specific patterns to avoid nuking games with 'steam' in the name\n            wine_exe=$(tr '\\0' '\\n' < \"$pid_path/cmdline\" 2>/dev/null | \\\n                grep -i '\\.exe' | \\\n                grep -ivE 'reaper\\.exe|/steam\\.exe|^steam\\.exe$|explorer\\.exe|services\\.exe|svchost\\.exe' | \\\n                head -n1 | \\\n                sed 's/.*[\\/ \\\\]//' | \\\n                sed 's/\\.exe.*/.exe/i')\n\n            # 2. Better Fallback: Use the actual binary path if wine_exe is empty\n            # This avoids the \"main\" or \"python\" names found in /proc/pid/comm\n            if [[ -z \"$wine_exe\" ]]; then\n                real_exe=$(readlink -f \"$pid_path/exe\" 2>/dev/null)\n                lsfg_name=$(basename \"$real_exe\")\n            else\n                lsfg_name=\"$wine_exe\"\n            fi\n\n            # Final check: if we are still stuck with 'main' or empty, use the comm name\n            [[ \"$lsfg_name\" == \"main\" || -z \"$lsfg_name\" ]] && lsfg_name=\"$procname\"\n\n            printf \"PID %-6s | Name: %-15s | LSFG Profile Name: %s\\n\" \"$pid\" \"$procname\" \"$lsfg_name\"\n        fi\n    fi\ndone\n"
  },
  {
    "path": ".local/bin/ff-concat",
    "content": "#!/bin/bash\n\n# Check if there are video files in the directory\ntmpfile=$(mktemp)\n\n# Loop through video files (mp4, mov, avi, mkv, flv, webm)\nfor f in *.{mp4,mov,avi,mkv,flv,webm}; do\n    if [ -f \"$f\" ]; then\n        echo \"file '$PWD/$f'\" >> \"$tmpfile\"\n    fi\ndone\n\n# Check if we have any files listed\nif [ -s \"$tmpfile\" ]; then\n    echo \"Found video files. Concatenating...\"\n    sleep 1  # Ensure temporary file is written\n\n    # Concatenate videos using ffmpeg\n    ffmpeg -f concat -safe 0 -i \"$tmpfile\" -c copy output.mp4\n\n    # Clean up the temporary file\n    rm \"$tmpfile\"\n    echo \"Concatenation completed, output saved as output.mp4.\"\nelse\n    echo \"No video files found in the current directory.\"\n    rm \"$tmpfile\"\nfi\n"
  },
  {
    "path": ".local/bin/ff-crop",
    "content": "#!/bin/bash\n\nif [ -z \"$1\" ]; then\n  echo \"Usage: ff-crop <aspect_ratio>\"\n  echo \"Example: ff-crop 0.75:1\"\n  exit 1\nfi\n\n# Parse aspect ratio input, e.g. \"0.75:1\"\naspect_ratio_input=$1\nwidth_ratio=$(echo $aspect_ratio_input | cut -d':' -f1)\nheight_ratio=$(echo $aspect_ratio_input | cut -d':' -f2)\n\nfor f in *.{mp4,mkv,avi}; do\n  [ -e \"$f\" ] || continue\n  echo \"Cropping $f to aspect ratio $aspect_ratio_input\"\n  ffmpeg -i \"$f\" -vf \"crop='if(gt(a,${width_ratio}/${height_ratio}),ih*${width_ratio}/${height_ratio},iw)':'if(gt(a,${width_ratio}/${height_ratio}),ih,iw*${height_ratio}/${width_ratio})'\" -c:a copy \"cropped_$f\"\ndone\n"
  },
  {
    "path": ".local/bin/ff-diff",
    "content": "#!/bin/sh\nset -eu\n\nsrc_dir=\".\"\nout_dir=\"encVids\"\n\n[ -d \"$out_dir\" ] || { echo \"Output dir '$out_dir' not found\"; exit 1; }\n\necho \"Analyzing cleanup candidates...\"\necho\n\ndeleted=0\nkept=0\n\nfor src_file in \"$src_dir\"/*; do\n    [ -f \"$src_file\" ] || continue\n\n    ext=\"${src_file##*.}\"\n    case \"$ext\" in\n        mp4|mkv|ts|mov|avi|webm|gif) ;;\n        *) continue ;;\n    esac\n\n    base_name=$(basename -- \"$src_file\")\n    prefix=$(echo \"$base_name\" | iconv -f UTF-8 -t ASCII//TRANSLIT | tr -cd '[:alnum:]')\n    hash=$(echo -n \"$base_name\" | sha1sum | cut -c1-6)\n    clean_name=\"${prefix}_${hash}\"\n\n    out_file=\"$out_dir/${clean_name}.mp4\"\n\n    if [ -f \"$out_file\" ]; then\n        echo \"Encoded found: $out_file\"\n        echo \"  -> Deleting original: $src_file\"\n        rm -f -- \"$src_file\"\n        deleted=$((deleted+1))\n    else\n        echo \"Not encoded yet: $src_file\"\n        kept=$((kept+1))\n    fi\ndone\n\necho\necho \"Cleanup summary:\"\necho \"  Originals ready for deletion : $deleted\"\necho \"  Originals kept (not encoded) : $kept\"\n"
  },
  {
    "path": ".local/bin/ff-enc",
    "content": "#!/bin/sh\nset -eu\n\n### CONFIGURATION ###\nvideo_output_dir=\"encVids\"\naudio_output_dir=\"extAudios\"\noptimized_audio_dir=\"optAudios\"\n\ntarget_height=900\ntarget_fps=30\ncrf=26\npreset=\"medium\"\naudio_bitrate=\"128k\"\ncover_timestamp=\"00:10:00\"\n\nvideo_extensions=\"mp4 mkv ts mov avi webm gif m4v\"\naudio_extensions=\"mp4 mkv avi mov webm flv wmv mpg mpeg\"\naudio_file_extensions=\"mp3 wav flac aac m4a opus\"\n\n### UTILITY FUNCTIONS ###\ndie() {\n    echo \"Error: $1\" >&2\n    exit 1\n}\n\nfind_media_files() {\n    case \"$1\" in\n        video) exts=\"$video_extensions\" ;;\n        audio) exts=\"$audio_extensions\" ;;\n        audio_files) exts=\"$audio_file_extensions\" ;;\n        *) die \"Invalid media type: $1\" ;;\n    esac\n\n    for ext in $exts; do\n        find . -maxdepth 1 -type f -iname \"*.$ext\"\n    done\n}\n\nprogress_bar() {\n    awk '\n        /out_time_ms/ {\n            gsub(\"out_time_ms=\", \"\", $0)\n            ms=$0\n            sec=int(ms/1000000)\n            min=int(sec/60)\n            sec=sec%60\n            printf \"\\r    Progress: %02d:%02d elapsed\", min, sec\n            fflush()\n        }\n        END { print \"\" }\n    '\n}\n\n### PROCESSING LOOP WITHOUT CHECKPOINT ###\nprocess_files_serial() {\n    cmd=\"$1\"\n    filelist=\"$2\"\n\n    total_files=$(wc -l < \"$filelist\" | tr -d ' ')\n    processed_files=0\n\n    while IFS= read -r file || [ -n \"$file\" ]; do\n        if \"$cmd\" \"$file\"; then\n            :\n        else\n            echo \"Error processing: $file\" >&2\n        fi\n\n        processed_files=$((processed_files + 1))\n        echo \"Progress: $processed_files / $total_files\"\n    done < \"$filelist\"\n}\n\n### VIDEO ENCODING ###\nencode_video_file() {\n    file=\"$1\"\n    base_name=$(basename -- \"$file\")\n    prefix=$(echo \"$base_name\" | iconv -f UTF-8 -t ASCII//TRANSLIT | tr -cd '[:alnum:]')\n    hash=$(echo -n \"$base_name\" | sha1sum | cut -c1-6)\n    clean_name=\"${prefix}_${hash}\"\n    output_file=\"$video_output_dir/${clean_name}.mp4\"\n\n    if [ -f \"$output_file\" ]; then\n        echo \"[$(date '+%H:%M:%S')] Skipping: $base_name (already exists)\"\n        return 0\n    fi\n\n    height=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=p=0 \"$file\")\n    fps=$(ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of csv=p=0 \"$file\" | awk -F/ '{if ($2==\"\"||$2==0) print $1; else printf \"%.3f\", $1/$2;}')\n    fps_int=${fps%.*}\n\n    if [ \"$height\" -gt \"$target_height\" ]; then\n        vf_arg=\"scale=-2:$target_height\"\n    else\n        vf_arg=\"scale=iw:ih\"\n    fi\n\n    if [ \"$fps_int\" -gt 30 ]; then\n        vf_arg=\"$vf_arg,fps=$target_fps\"\n    fi\n\n    echo \"[$(date '+%H:%M:%S')] Processing: $base_name\"\n    ionice -c3 2>/dev/null || true\n    nice -n 19 ffmpeg -nostdin -y -hide_banner \\\n        -i \"$file\" \\\n        -c:v libx265 -preset \"$preset\" -crf \"$crf\" -x265-params no-sao=1:bframes=8 \\\n        -vf \"$vf_arg\" \\\n        -c:a libopus -b:a \"$audio_bitrate\" -vbr on \\\n        -movflags +faststart -tag:v hvc1 \\\n        -map_metadata 0 -map_chapters 0 \\\n        \"$output_file\" >/dev/null 2>&1\n    echo \"[$(date '+%H:%M:%S')] Done: $base_name\"\n}\n\nencode_videos() {\n    mkdir -p \"$video_output_dir\"\n    tmpfile=$(mktemp) || die \"Failed to create temp file\"\n    trap 'rm -f \"$tmpfile\"' EXIT\n\n    find_media_files video | sort > \"$tmpfile\"\n    process_files_serial encode_video_file \"$tmpfile\"\n    rm -f \"$tmpfile\"\n    trap - EXIT\n}\n\n### AUDIO EXTRACTION ###\nextract_audio_file() {\n    file=\"$1\"\n    base_name=$(basename -- \"$file\")\n    prefix=$(echo \"$base_name\" | iconv -f UTF-8 -t ASCII//TRANSLIT | tr -cd '[:alnum:]')\n    hash=$(echo -n \"$base_name\" | sha1sum | cut -c1-6)\n    clean_name=\"${prefix}_${hash}\"\n    output_file=\"$audio_output_dir/${clean_name}.m4a\"\n    cover_art=\"/tmp/${clean_name}_cover.jpg\"\n\n    if [ -f \"$output_file\" ]; then\n        echo \"[$(date '+%H:%M:%S')] Skipping audio: $base_name (already exists)\"\n        return 0\n    fi\n\n    echo \"[$(date '+%H:%M:%S')] Extracting audio: $base_name\"\n    # Generate cover art snapshot safely, ignoring errors.\n    ffmpeg -nostdin -y -ss \"$cover_timestamp\" -i \"$file\" -vframes 1 \"$cover_art\" 2>/dev/null || true\n\n    if ! ffmpeg -nostdin -y -i \"$file\" -vn -c:a copy -strict -2 \"$output_file\" 2>/dev/null; then\n        ionice -c3 2>/dev/null || true\n        nice -n 19 ffmpeg -nostdin -y -i \"$file\" -vn -c:a aac -b:a 192k \"$output_file\"\n    fi\n\n    if [ -f \"$cover_art\" ]; then\n        ffmpeg -nostdin -y -i \"$output_file\" -i \"$cover_art\" \\\n            -map 0:a -map 1 -c copy -disposition:v:0 attached_pic \\\n            -metadata:s:v title=\"Album cover\" \\\n            -metadata:s:v comment=\"Cover (front)\" \\\n            \"${output_file%.m4a}_cover.m4a\"\n        mv \"${output_file%.m4a}_cover.m4a\" \"$output_file\"\n        rm -f \"$cover_art\"\n    fi\n\n    echo \"[$(date '+%H:%M:%S')] Done audio: $base_name\"\n}\n\nextract_audios() {\n    mkdir -p \"$audio_output_dir\"\n    tmpfile=$(mktemp) || die \"Failed to create temp file\"\n    trap 'rm -f \"$tmpfile\"' EXIT\n\n    find_media_files audio | sort > \"$tmpfile\"\n    process_files_serial extract_audio_file \"$tmpfile\"\n    rm -f \"$tmpfile\"\n    trap - EXIT\n}\n\n### AUDIO OPTIMIZATION ###\noptimize_audio_file() {\n    file=\"$1\"\n    base_name=$(basename -- \"$file\")\n    clean_name=$(echo \"${base_name%.*}\" | tr -cd '[:alnum:]._-')\n    output_file=\"$optimized_audio_dir/${clean_name}.opus\"\n\n    if [ -f \"$output_file\" ]; then\n        echo \"[$(date '+%H:%M:%S')] Skipping audio: $base_name (already exists)\"\n        return 0\n    fi\n\n    echo \"[$(date '+%H:%M:%S')] Optimizing audio: $base_name\"\n    ionice -c3 2>/dev/null || true\n    nice -n 19 ffmpeg -nostdin -y -hide_banner -progress pipe:1 \\\n        -i \"$file\" \\\n        -c:a libopus -b:a \"$audio_bitrate\" -vbr on \\\n        \"$output_file\" 2>&1 | progress_bar\n    echo \"[$(date '+%H:%M:%S')] Done audio: $base_name\"\n}\n\noptimize_audios() {\n    mkdir -p \"$optimized_audio_dir\"\n    tmpfile=$(mktemp) || die \"Failed to create temp file\"\n    trap 'rm -f \"$tmpfile\"' EXIT\n\n    find_media_files audio_files | sort > \"$tmpfile\"\n    process_files_serial optimize_audio_file \"$tmpfile\"\n    rm -f \"$tmpfile\"\n    trap - EXIT\n}\n\n### MAIN MENU ###\nshow_help() {\ncat <<EOF\nBatch Media Processor - Serial Processing\n\nUsage: $0 [option]\nOptions:\n  -v, --video       Batch encode videos to 900p H.265/Opus\n  -x, --extract     Batch extract audio from videos (with cover art)\n  -a, --audio       Batch optimize audio files to Opus\n  -h, --help        Show this help\n\nFile existence in output directories is used to skip processed files.\nEOF\n}\n\ncase \"${1:-}\" in\n    -v|--video)   encode_videos ;;\n    -x|--extract) extract_audios ;;\n    -a|--audio)   optimize_audios ;;\n    -h|--help|\"\") show_help ;;\n    *) die \"Unknown option: $1\" ;;\nesac\n\necho \"All tasks complete.\"\n"
  },
  {
    "path": ".local/bin/font-char-list",
    "content": "#!/bin/bash -\n\nUsage() { echo \"$0 FontFile\"; exit 1; }\nSayError() { local error=$1; shift; echo \"$0: $@\"; exit \"$error\"; }\n\n[ \"$#\" -ne 1 ] && Usage\n\nwidth=150\nfontfile=\"$1\"\n\n[ -f \"$fontfile\" ] || SayError 4 'File not found'\n\nlist=$(fc-query --format='%{charset}\\n' \"$fontfile\")\n\nfor    range in $list\ndo     IFS=- read start end <<<\"$range\"\n       if    [ \"$end\" ]\n       then\n             start=$((16#$start))\n         end=$((16#$end))\n         for((i=start;i<=end;i++)); do\n         printf -v char '\\\\U%x' \"$i\"\n         printf '%b' \"$char\"\n         done\n       else\n         printf '%b' \"\\\\U$start\"\n       fi\ndone | grep -oP '.{'\"$width\"'}'\n"
  },
  {
    "path": ".local/bin/font-unicode",
    "content": "#!/bin/sh\nfor CODE in $@; do\n\t/usr/bin/printf \"%s - \\u$CODE\\n\" $CODE\ndone\n\nexit $?"
  },
  {
    "path": ".local/bin/fuzz-launcher",
    "content": "#!/bin/sh\n\n# Global Settings\nFONT=\"monospace:size=14\"\nALIGN=\"center\"\nFUZZEL_CMD=\"fuzzel -d -f $FONT -a $ALIGN\"\n\n# Function to display a menu and return the selected choice\nshow_menu() {\n    echo \"$1\" | $FUZZEL_CMD -w \"$2\" -l \"$3\"\n}\n\n# Function to launch an application if available\nlaunch_app() {\n    if command -v \"$1\" >/dev/null 2>&1; then\n        exec \"$@\"\n    else\n        echo \"$1 not found\" >&2\n        exit 1\n    fi\n}\n\n# Function to handle utilities menu\nhandle_utils_menu() {\n    choice=$(show_menu \"$utils_menu\" 13 5)\n    case \"$choice\" in\n        \"⚙️ Run\") exec_fuzzel_run ;;\n        \"💻 Streaming\") exec_fuzzel_streaming ;;\n        \"🔢 Calc\") exec_fuzzel_calc ;;\n        \"📑 Todo\") exec_fuzzel_todo ;;\n        \"⌨️ Keyboard\") toggle_keyboard ;;\n        *) echo \"Invalid choice: $choice\" >&2; exit 1 ;;\n    esac\n}\n\n# Function to handle power menu\nhandle_power_menu() {\n    choice=$(show_menu \"$power_menu\" 11 4)\n    case \"$choice\" in\n        \" Shutdown\") sudo poweroff ;;\n        \" Suspend\") sudo halt ;;\n        \" Reboot\") sudo reboot ;;\n        \" Lock\") swaylock -c 000000 ;;\n        *) echo \"Invalid choice: $choice\" >&2; exit 1 ;;\n    esac\n}\n\n# Function to handle streaming menu\nexec_fuzzel_streaming() {\n    platform_choice=$(show_menu \"$streaming_menu\" 9 2)\n    case \"$platform_choice\" in\n        \" Media\") input_link=$(wl-paste) ;;\n        \" Twitch\")\n            channel_name=$(echo \"\" | fuzzel -d -p \"type twitch name: \" -f \"$FONT\" -w 40 -l 0 -a \"$ALIGN\")\n            input_link=\"https://twitch.tv/$channel_name\"\n            ;;\n        *) echo \"Invalid choice: $platform_choice\" >&2; exit 1 ;;\n    esac\n    media_choice=$(show_menu \"$media_type_menu\" 9 2)\n    case \"$media_choice\" in\n        \" Video\") mpv --pause=no \"$input_link\" ;;\n        \" Audio\") foot -T \"MPV Terminal\" -e mpv --pause=no --no-video --volume=100 \"$input_link\" ;;\n        *) echo \"Invalid choice: $media_choice\" >&2; exit 1 ;;\n    esac\n}\n\n# Function to toggle virtual keyboard\ntoggle_keyboard() {\n    if pgrep -x \"wvkbd-mobintl\" > /dev/null; then\n        pkill wvkbd-mobintl\n    else\n        wvkbd-mobintl -H 50 -R 5 --bg \"#282828\" --fg \"#ffffff\" --fn \"monospace 12\" --alpha 200 &\n    fi\n}\n\n# Function for calculator using fuzzel\nexec_fuzzel_calc() {\n    LAST=\"\"\n    while true; do\n        SPACE=\" \"\n        NEXT=\"$(fuzzel -l 0 --dmenu -p \"${LAST}${SPACE}\")\"\n        [ -z \"$NEXT\" ] && exit 1\n        [ \"$NEXT\" = \"y\" ] && wl-copy \"$LAST\" && exit 0\n        LAST=\"$(echo \"$LAST$NEXT\" | bc -l | sed '/\\./ s/\\.\\{0,1\\}0\\{1,\\}$//')\"\n    done\n}\n\n# Function for to-do manager using fuzzel\nexec_fuzzel_todo() {\n    cache_file=\"$HOME/.cache/todo.cache\"\n    cache_file_2=\"$HOME/.cache/todo2.cache\"\n    cache_contents=\"$(cat \"$cache_file\")\"\n    cache_lines=\"$(echo \"$cache_contents\" | wc -l)\"\n    [ -s \"$cache_file\" ] || cache_lines=0\n    selection=\"$(echo \"$cache_contents\" | fuzzel --dmenu -l \"$cache_lines\" 2>/dev/null)\"\n    [ -z \"$selection\" ] && exit 1\n    if grep -q \"$selection\" \"$cache_file\"; then\n        grep -v \"^${selection}$\" \"$cache_file\" > \"$cache_file_2\"\n        mv \"$cache_file_2\" \"$cache_file\"\n    else\n        echo \"$selection\" >> \"$cache_file\"\n    fi\n}\n\n# Function for application runner\nexec_fuzzel_run() {\n    exec_list=$(printf \"%s\\n\" $(echo \"$PATH\" | tr ':' '\\n' | xargs -I{} find {} -maxdepth 1 -executable -type f -printf \"%f\\n\" 2>/dev/null) | sort -u)\n    selected=$(echo \"$exec_list\" | fuzzel --dmenu)\n    [ -n \"$selected\" ] && exec \"$selected\"\n}\n\n# Menu definitions\nmain_menu=\"🖥️ Terminal\\n🗃️ Explorer\\n🌍 Browser\\n📦 Apps\\n⚙️ Utils\\n🔌 Power\"\nutils_menu=\"📑 Todo\\n💻 Streaming\\n🔢 Calc\\n⚙️ Run\\n⌨️ Keyboard\"\npower_menu=\" Shutdown\\n Suspend\\n Reboot\\n Lock\"\nstreaming_menu=\" Media\\n Twitch\"\nmedia_type_menu=\" Video\\n Audio\"\n\n# Main Menu Logic\nchoice=$(show_menu \"$main_menu\" 12 6)\ncase \"$choice\" in\n    \"🖥️ Terminal\") launch_app foot ;;\n    \"🗃️ Explorer\") launch_app pcmanfm-qt ;;\n    \"🌍 Browser\") launch_app flatpak run io.gitlab.librewolf-community ;;\n    \"📦 Apps\") launch_app fuzzel ;;\n    \"⚙️ Utils\") handle_utils_menu ;;\n    \"🔌 Power\") handle_power_menu ;;\n    *) echo \"Invalid choice: $choice\" >&2; exit 1 ;;\nesac\n"
  },
  {
    "path": ".local/bin/get-steamid",
    "content": "#!/bin/sh\n\nsteamapps=\"$HOME/.var/app/com.valvesoftware.Steam/data/Steam/steamapps\"\n\n# Print header\nprintf \"Looking through %s/compatdata/ ...\\n\" \"$steamapps\"\nprintf \"Proton    App ID      Name\\n\"\n\n# Loop through all directories in compatdata\nfor x in \"$steamapps\"/compatdata/*; do\n    id=$(basename \"$x\")  # Extract the App ID from the directory name\n    # Extract the app name from the .acf file, suppressing errors\n    name=$(sed -n '/^\\s*\"name\"\\s*/ s/.*\"\\(.*\\)\"/\\1/p' \"$steamapps/appmanifest_$id.acf\" 2>/dev/null)\n\n    # Get version or default to \"N/A\"\n    version=$(cat \"$x/version\" 2>/dev/null || echo \"N/A\")\n\n    # Print the information, using a default message if name is empty\n    printf \"%-8s  %-10s  %s\\n\" \"$version\" \"$id\" \"${name:-this is not a Steam app?}\"\ndone\n\n"
  },
  {
    "path": ".local/bin/git-ops",
    "content": "#!/bin/sh\n\n# Function to exit with an error message\nexit_err() {\n  printf '%s\\n' \"$1\" >&2\n  exit 1\n}\n\n# Check if origin remote exists\ncheck_origin() {\n  if ! git config --get remote.origin.url >/dev/null 2>&1; then\n    exit_err \"Remote 'origin' is not configured.\"\n  fi\n}\n\n# Validate there are changes to commit\ncheck_changes() {\n  if git diff --cached --quiet; then\n    exit_err \"No changes to commit.\"\n  fi\n}\n\n# Prompt for commit message\nget_commit_message() {\n  printf \"Commit message: \"\n  read -r commit || exit_err \"Failed to read input.\"\n  [ -z \"$commit\" ] && exit_err \"Commit message cannot be empty.\"\n}\n\n# Standard commit and push\npush_changes() {\n  check_origin\n  git add -A || exit_err \"Failed to stage changes.\"\n  check_changes\n  git commit -m \"$commit\" || exit_err \"Failed to commit changes.\"\n  git push || exit_err \"Failed to push changes.\"\n  printf '%s\\n' \"Changes pushed successfully.\"\n}\n\n# Clean repository history\nclean_repo() {\n  check_origin\n\n  # Safety checks\n  if ! git diff --quiet; then\n    exit_err \"Uncommitted changes detected. Aborting clean operation.\"\n  fi\n\n  temp_branch=\"tmp-$(date +%s)\"\n  git checkout --orphan \"$temp_branch\" || exit_err \"Failed to create orphan branch.\"\n  git add -A || exit_err \"Failed to stage changes.\"\n  git commit --allow-empty -m \"$commit\" || exit_err \"Failed to initial commit.\"\n\n  # Force update main branch\n  if git show-ref --verify --quiet refs/heads/main; then\n    git branch -D main || exit_err \"Failed to remove existing main branch.\"\n  fi\n\n  git branch -m main || exit_err \"Failed to rename temporary branch.\"\n  git push -f origin main || exit_err \"Failed to force push new history.\"\n  git gc --aggressive --prune=now --quiet || exit_err \"Failed to optimize repository.\"\n  printf '%s\\n' \"Repository history cleaned successfully.\"\n}\n\n# Main execution\nget_commit_message\n\ncase \"$1\" in\n  push)\n    push_changes\n    ;;\n  clean)\n    clean_repo\n    ;;\n  *)\n    printf '%s\\n' \"Usage: $0 {push|clean}\"\n    exit 1\n    ;;\nesac\n"
  },
  {
    "path": ".local/bin/grim-print",
    "content": "#!/bin/sh\n\n# Check for required commands\nfor cmd in grim swayimg slurp wl-copy fuzzel; do\n    command -v \"$cmd\" >/dev/null 2>&1 || {\n        printf '%s is required but not installed.\\n' \"$cmd\" >&2\n        exit 1\n    }\ndone\n\n# Avoid multiple concurrent instances\npidof -o %PPID -x \"$0\" >/dev/null && exit 0\n\n# Capture monitors and let user choose one to crop\ncapture_region() {\n    tmp_dp2=$(mktemp --suffix=.png)\n    tmp_hdmi=$(mktemp --suffix=.png)\n    tmp_all=$(mktemp --suffix=.png)\n\n    # Concurrent captures\n    grim -o DP-2 \"$tmp_dp2\" &\n    grim -o HDMI-A-1 \"$tmp_hdmi\" &\n    grim \"$tmp_all\" &\n    wait\n\n    # Menu selection\n    choice=$(printf 'Main\\nSecondary\\nCombined' | \\\n             fuzzel -d -f 'monospace:size=14' -a center -w 11 -l 3 --prompt=\"\")\n\n    case \"$choice\" in\n        Main)      selected=\"$tmp_dp2\" ;;\n        Secondary) selected=\"$tmp_hdmi\" ;;\n        Combined)  selected=\"$tmp_all\" ;;\n        *)         rm -f \"$tmp_dp2\" \"$tmp_hdmi\" \"$tmp_all\"; return 1 ;;\n    esac\n\n    # Show image full screen\n    swayimg -f \"$selected\" &\n    viewer_pid=$!\n    sleep 0.1\n\n    if region=$(slurp); then\n        grim -g \"$region\" - | wl-copy -t image/png\n    fi\n\n    kill \"$viewer_pid\" 2>/dev/null\n    wait \"$viewer_pid\" 2>/dev/null\n    rm -f \"$tmp_dp2\" \"$tmp_hdmi\" \"$tmp_all\"\n\n    [ -n \"$region\" ]\n}\n\n# Copy full screen to clipboard\ncopy_full_screen() {\n    grim - | wl-copy -t image/png\n}\n\n# Argument parsing\ncase \"$1\" in\n    slurp) capture_region ;;\n    copy | *) copy_full_screen ;;\nesac\n"
  },
  {
    "path": ".local/bin/img-dupes",
    "content": "#!/bin/bash\n\n# --- CONFIGURATION ---\nTHRESHOLD=\"98%\"         # 85-90% is ideal for \"near-duplicates\"\nDB_FILE=\"fingerprints.db\"\nDEST_DIR=\"duplicates_backup\"\nmkdir -p \"$DEST_DIR\"\n\n# 1. INITIAL SCAN & DATABASE GENERATION\n# Creating a fingerprint database drastically speeds up subsequent runs\necho \"Step 1: Refreshing fingerprint database ($DB_FILE)...\"\nfind . -type f \\( -iname \"*.jpg\" -o -iname \"*.png\" -o -iname \"*.jpeg\" \\) -print0 | \\\n    findimagedupes -0 -f \"$DB_FILE\" --rescan -\n\n# 2. ACCURACY-FOCUSED COMPARISON\n# We use the -0 flag (null-terminated) to safely handle spaces/quotes in filenames\necho \"Step 2: Comparing images at ${THRESHOLD} similarity...\"\nfindimagedupes -t \"$THRESHOLD\" -f \"$DB_FILE\" . | while read -r line; do\n    # Convert space-separated line into an array safely\n    # Note: findimagedupes output format for sets is 'file1 file2 file3'\n    read -a files <<< \"$line\"\n\n    if [ ${#files[@]} -gt 1 ]; then\n        # Keep the FIRST file, move the rest to backup\n        original=\"${files[0]}\"\n        echo \"Found set: $(basename \"$original\") has ${#files[@]} duplicates\"\n\n        for ((i=1; i<${#files[@]}; i++)); do\n            duplicate=\"${files[$i]}\"\n            if [ -f \"$duplicate\" ]; then\n                # Move to backup without overwriting existing files\n                mv -n \"$duplicate\" \"$DEST_DIR/\"\n                echo \"  [MOVED] -> $(basename \"$duplicate\")\"\n            fi\n        done\n    fi\ndone\n\necho \"Done! Check $DEST_DIR for moved files.\"\n"
  },
  {
    "path": ".local/bin/img-duprestore",
    "content": "#!/bin/bash\nTHRESHOLD=\"70\"\nBACKUP_DIR=\"duplicates_backup\"\nTREE_EXCLUDE=\" -not -path \\\"./$BACKUP_DIR/*\\\"\"\n\necho \"Scanning $BACKUP_DIR/* against tree (${THRESHOLD}%)...\"\n\nfor backup_file in \"$BACKUP_DIR\"/*; do\n    [ -f \"$backup_file\" ] || continue\n\n    # Compare THIS backup file against entire tree\n    matches=$(find . -type f \\( -iname \"*.jpg\" -o -iname \"*.jpeg\" -o -iname \"*.png\" -o -iname \"*.webp\" \\) \\\n        $TREE_EXCLUDE -print0 | findimagedupes -t \"$THRESHOLD\" -0 \"$backup_file\" -- - 2>/dev/null)\n\n    if [ -n \"$matches\" ]; then\n        # Get first tree match as target\n        set -- $matches\n        target_file=\"${files[0]}\"  # First match (tree file)\n        target_dir=$(dirname \"$target_file\")\n        filename=$(basename \"$backup_file\")\n\n        echo \"RESTORE: $filename → $target_dir/\"\n        mv -n \"$backup_file\" \"$target_dir/\"\n    fi\ndone\n\necho \"Done! True uniques remain in $BACKUP_DIR\"\n"
  },
  {
    "path": ".local/bin/img-enc",
    "content": "#!/bin/sh\n\ntarget_format=\"${1:-webp}\"  # Default to webp if not specified\noutput_dir=\"opt_${target_format}\"\nquality=82\nmax_dimension=1920\n\nmkdir -p \"$output_dir\"\n\nfind . -maxdepth 1 -type f \\( -iname \"*.jpg\" -o -iname \"*.jpeg\" -o -iname \"*.png\" -o -iname \"*.webp\" -o -iname \"*.bmp\" -o -iname \"*.tiff\" -o -iname \"*.heic\" -o -iname \"*.avif\" \\) -print | while IFS= read -r file; do\n    [ -e \"$file\" ] || continue\n    base_name=$(basename \"$file\")\n    extension=\"${file##*.}\"\n    clean_name=$(printf \"%s\" \"${base_name%.*}\" | tr -cd '[:alnum:]._-')\n    output_file=\"$output_dir/${clean_name}_${extension}.$target_format\"\n\n    if [ -f \"$output_file\" ]; then\n        printf \"Skipping: %s (output exists)\\n\" \"$base_name\"\n        continue\n    fi\n\n    printf \"Processing: %s -> %s\\n\" \"$base_name\" \"$output_file\"\n\n    geometry=$(magick identify -format \"%wx%h\" \"$file\" 2>/dev/null)\n    if [ -z \"$geometry\" ]; then\n        printf \"Error: Cannot read image file: %s\\n\" \"$file\" >&2\n        continue\n    fi\n    width=$(echo \"$geometry\" | cut -d 'x' -f1)\n    height=$(echo \"$geometry\" | cut -d 'x' -f2)\n\n    resize_arg=\"\"\n    if [ \"$width\" -gt \"$max_dimension\" ] || [ \"$height\" -gt \"$max_dimension\" ]; then\n        resize_arg=\"-resize ${max_dimension}x${max_dimension}\"\n    fi\n\n    # Choose format-specific options\n    case \"$target_format\" in\n        webp)\n            magick \"$file\" -strip $resize_arg -auto-orient -quality \"$quality\" -define webp:method=6,webp:auto-filter=true -colorspace sRGB \"$output_file\"\n            ;;\n        jpg|jpeg)\n            magick \"$file\" -strip $resize_arg -auto-orient -quality \"$quality\" -sampling-factor 4:2:0 -interlace Plane -colorspace sRGB \"$output_file\"\n            ;;\n        png)\n            magick \"$file\" -strip $resize_arg -auto-orient -define png:compression-level=9 -colorspace sRGB \"$output_file\"\n            ;;\n        *)\n            printf \"Unsupported output format: %s\\n\" \"$target_format\" >&2\n            continue\n            ;;\n    esac\n\n    # Preserve timestamp\n    touch -r \"$file\" \"$output_file\"\ndone\n\nprintf \"Processing complete. Results in: %s\\n\" \"$output_dir\"\n"
  },
  {
    "path": ".local/bin/imv-mass",
    "content": "#!/bin/bash\n\n# Set the target directory to the first argument, or use the current directory if no argument is provided\nTARGET_DIR=\"${1:-.}\"\n\n# Use mapfile to read the output of find into an array, handling null terminators\nmapfile -d '' files < <(find \"$TARGET_DIR\" -type f \\( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.gif' -o -iname '*.webp' \\) -print0)\n\n# Check if any files were found\nif [ \"${#files[@]}\" -eq 0 ]; then\n    echo \"No image files found in $TARGET_DIR\"\n    exit 1\nfi\n\n# Shuffle the array using Bash's built-in randomization\nshuffled_files=()\nwhile IFS= read -r -d '' file; do\n    shuffled_files+=(\"$file\")\ndone < <(printf '%s\\0' \"${files[@]}\" | sort -z -R)\n\n# Open the shuffled files with imv\nimv \"${shuffled_files[@]}\"\n"
  },
  {
    "path": ".local/bin/mass-mpv",
    "content": "#!/bin/bash\n\n# Convert TARGET_DIR to an absolute path immediately\nTARGET_DIR=\"$(realpath \"${1:-.}\")\"\n\nTMP_INPUT_CONF=$(mktemp)\nTMP_PLAYLIST=$(mktemp)\n\ntrap 'rm -f \"$TMP_INPUT_CONF\" \"$TMP_PLAYLIST\"' EXIT\n\ncat > \"$TMP_INPUT_CONF\" <<EOF\nLEFT playlist-prev\nRIGHT playlist-next\nKP_PLUS add video-zoom 0.1\nKP_MINUS add video-zoom -0.1\nENTER playlist-next\nBACKSPACE playlist-prev\nEOF\n\n# find will now output absolute paths because $TARGET_DIR is absolute\nfind \"$TARGET_DIR\" -type f \\( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.gif' -o -iname '*.webp' \\) -print0 | shuf -z | tr '\\0' '\\n' > \"$TMP_PLAYLIST\"\n\nif [ ! -s \"$TMP_PLAYLIST\" ]; then\n  echo \"No images found in $TARGET_DIR\" >&2\n  exit 1\nfi\n\nmpv --input-conf=\"$TMP_INPUT_CONF\" \\\n    --playlist=\"$TMP_PLAYLIST\" \\\n    --vo=gpu \\\n    --image-display-duration=5 \\\n    --loop-playlist=inf\n"
  },
  {
    "path": ".local/bin/mem",
    "content": "#!/bin/sh\n\nps -e -o pgid= -o rss= -o comm= | awk '\n{\n    pgid = $1\n    rss = $2\n    cmd = $3\n\n    # Handle kernel threads (bracketed names)\n    if (cmd ~ /^\\[.*\\]$/) {\n        cmd = \"[\" cmd \"]\"\n    }\n\n    # Group by pgid and command\n    key = pgid \"|\" cmd\n    mem[key] += rss\n    cmds[key] = cmd\n}\nEND {\n    for (key in mem) {\n        # Convert to MB and filter out 0MB entries\n        mem_mb = mem[key] / 1024\n        if (mem_mb >= 0.1) {  # Only show processes using at least 0.1 MB\n            printf \"%.2f|%s\\n\", mem_mb, cmds[key]\n        }\n    }\n}' | sort -nr | awk -F'|' '\nBEGIN {\n    print \"Process               RAM Usage\"\n    print \"-------------------  ----------\"\n}\n{\n    printf \"%-20s %9.2f MB\\n\", $2, $1\n    total += $1\n}\nEND {\n    print \"-------------------  ----------\"\n    printf \"%-20s %9.2f MB\\n\", \"Total RAM Usage:\", total\n}'\n"
  },
  {
    "path": ".local/bin/mvToParent",
    "content": "#!/bin/sh\n\nparent_dir=$(pwd)\n\nfind \"$parent_dir\" -mindepth 2 -type f | while IFS= read -r filepath; do\n  relative_path=${filepath#\"$parent_dir\"/}\n  dir_path=$(dirname \"$relative_path\")\n  filename=$(basename \"$filepath\")\n\n  prefix=$(echo \"$dir_path\" | sed 's/\\//_/g')\n  newname=\"${prefix}_$filename\"\n\n  mv \"$filepath\" \"$parent_dir/$newname\"\ndone\n"
  },
  {
    "path": ".local/bin/net-menu",
    "content": "#!/bin/sh\n# POSIX-Compliant Network Manager Script with Wi-Fi and VPN features\n\nLOCKFILE=\"/tmp/network-manager.lock\"\n\n# Cleanup\ncleanup() {\n    rm -f \"$LOCKFILE\"\n    stty echo 2>/dev/null\n    exit 0\n}\ntrap cleanup INT TERM EXIT\n\n# Check for lock\n[ -e \"$LOCKFILE\" ] && printf \"%s\\n\" \"Error: Already running.\" >&2 && exit 1\ntouch \"$LOCKFILE\"\n\n# Check required tools\ncommand -v nmcli >/dev/null 2>&1 || { printf \"%s\\n\" \"nmcli not found.\" >&2; exit 1; }\ncommand -v fzf >/dev/null 2>&1 || { printf \"%s\\n\" \"fzf not found.\" >&2; exit 1; }\n\n# Optional sudo fallback\nrun_privileged() {\n    if command -v sudo >/dev/null 2>&1; then\n        sudo \"$@\"\n    else\n        \"$@\"\n    fi\n}\n\n# Show network status\nshow_status() {\n    printf \"\\n%s\\n\" \"--- Network Status ---\"\n    wifi=$(nmcli -t -f active,ssid dev wifi | awk -F: '$1==\"yes\"{print $2}')\n    [ -n \"$wifi\" ] && printf \"%s\\n\" \"Wi-Fi: $wifi\" || printf \"%s\\n\" \"Wi-Fi: Disconnected\"\n    vpn=$(nmcli -t -f NAME,TYPE connection show --active | awk -F: '$2==\"vpn\" || $2==\"wireguard\"{print $1}')\n    [ -n \"$vpn\" ] && printf \"%s\\n\" \"VPN: $vpn\" || printf \"%s\\n\" \"VPN: Disconnected\"\n}\n\n# Get Wi-Fi list\nwifi_list() {\n    [ \"$1\" = \"yes\" ] && nmcli device wifi rescan >/dev/null 2>&1\n    nmcli -t -f SSID,SIGNAL,SECURITY device wifi list --rescan no | awk -F: '!seen[$1]++' | sort -t: -k2 -nr\n}\n\nconnect_wifi() {\n    printf \"\\n%s\\n\" \"--- Available Networks ---\"\n    list=$(wifi_list)\n    [ -z \"$list\" ] && printf \"%s\\n\" \"No networks found.\" && return\n    sel=$(printf \"%s\\n\" \"$list\" | fzf)\n    [ -z \"$sel\" ] && return\n\n    ssid=$(printf \"%s\" \"$sel\" | cut -d: -f1)\n    sec=$(printf \"%s\" \"$sel\" | cut -d: -f3)\n\n    if [ \"$ssid\" = \"<Hidden>\" ]; then\n        printf \"%s\" \"Enter SSID: \" ; read -r ssid\n        hidden=\"yes\"\n    else\n        hidden=\"\"\n    fi\n\n    saved_conn=$(get_saved_connection \"$ssid\")\n\n    if [ -n \"$saved_conn\" ]; then\n        if ! has_password \"$saved_conn\"; then\n            printf \"%s\" \"Password for saved network '$ssid': \"\n            stty -echo ; read -r pw ; stty echo ; echo\n            run_privileged nmcli connection modify \"$saved_conn\" 802-11-wireless-security.psk \"$pw\"\n        fi\n        run_privileged nmcli connection up \"$saved_conn\" && printf \"%s\\n\" \"Connected to $ssid\" || printf \"%s\\n\" \"Failed to connect.\"\n    else\n        if [ \"$sec\" = \"--\" ] || [ -z \"$sec\" ]; then\n            if [ -n \"$hidden\" ]; then\n                nmcli device wifi connect \"$ssid\" hidden yes && printf \"%s\\n\" \"Connected to $ssid\" || printf \"%s\\n\" \"Failed to connect.\"\n            else\n                nmcli device wifi connect \"$ssid\" && printf \"%s\\n\" \"Connected to $ssid\" || printf \"%s\\n\" \"Failed to connect.\"\n            fi\n        else\n            printf \"%s\" \"Password: \"\n            stty -echo ; read -r pw ; stty echo ; echo\n            if [ -n \"$hidden\" ]; then\n                nmcli device wifi connect \"$ssid\" password \"$pw\" hidden yes && printf \"%s\\n\" \"Connected to $ssid\" || printf \"%s\\n\" \"Failed to connect.\"\n            else\n                nmcli device wifi connect \"$ssid\" password \"$pw\" && printf \"%s\\n\" \"Connected to $ssid\" || printf \"%s\\n\" \"Failed to connect.\"\n            fi\n        fi\n    fi\n}\n\ndisconnect_wifi() {\n    dev=$(nmcli -t -f DEVICE,TYPE device | awk -F: '$2==\"wifi\"{print $1}')\n    conn=$(nmcli -t -f NAME,DEVICE connection show --active | awk -F: -v d=\"$dev\" '$2==d{print $1}')\n    [ -n \"$conn\" ] && nmcli connection down \"$conn\" && printf \"%s\\n\" \"Disconnected $conn\" || printf \"%s\\n\" \"No Wi-Fi connection.\"\n}\n\nforget_network() {\n    saved=$(nmcli -t -f NAME,TYPE connection show | awk -F: '$2==\"802-11-wireless\"{print $1}')\n    [ -z \"$saved\" ] && printf \"%s\\n\" \"No saved networks.\" && return\n    sel=$(printf \"%s\\n\" \"$saved\" | fzf)\n    [ -n \"$sel\" ] && nmcli connection delete \"$sel\" && printf \"%s\\n\" \"Removed $sel\"\n}\n\nrescan_wifi() {\n    printf \"%s\\n\" \"Rescanning...\"\n    wifi_list yes > /dev/null && printf \"%s\\n\" \"Scan complete.\"\n}\n\nimport_vpn() {\n    printf \"\\n%s\\n\" \"--- Import VPN ---\"\n    printf \"1) OpenVPN\\n2) WireGuard\\n\"\n    printf \"Choice (1-2): \" ; read -r type\n    [ \"$type\" = \"1\" ] && proto=\"openvpn\" && def=\"protonvpn\"\n    [ \"$type\" = \"2\" ] && proto=\"wireguard\" && def=\"spevpn\"\n    [ -z \"$proto\" ] && return\n\n    printf \"%s\" \"Path to .conf: \" ; read -r conf\n    [ ! -f \"$conf\" ] && printf \"%s\\n\" \"File not found.\" && return\n    printf \"Name (default: %s): \" \"$def\" ; read -r name\n    name=${name:-$def}\n\n    run_privileged nmcli connection import type \"$proto\" file \"$conf\"\n    run_privileged nmcli connection modify \"$(basename \"$conf\" .conf)\" connection.id \"$name\"\n    printf \"%s\\n\" \"VPN '$name' imported.\"\n}\n\ntoggle_vpn() {\n    list=$(nmcli -t -f NAME,TYPE connection show | awk -F: '$2==\"vpn\" || $2==\"wireguard\"{print $1}')\n    [ -z \"$list\" ] && printf \"%s\\n\" \"No VPNs.\" && return\n    sel=$(printf \"%s\\n\" \"$list\" | fzf)\n    [ -z \"$sel\" ] && return\n    if nmcli connection show --active | grep -q \"$sel\"; then\n        run_privileged nmcli connection down \"$sel\" && printf \"%s\\n\" \"Disconnected $sel\"\n    else\n        run_privileged nmcli connection up \"$sel\" && printf \"%s\\n\" \"Connected $sel\"\n    fi\n}\n\nremove_vpn() {\n    list=$(nmcli -t -f NAME,TYPE connection show | awk -F: '$2==\"vpn\" || $2==\"wireguard\"{print $1}')\n    [ -z \"$list\" ] && printf \"%s\\n\" \"No VPNs.\" && return\n    sel=$(printf \"%s\\n\" \"$list\" | fzf)\n    [ -n \"$sel\" ] && run_privileged nmcli connection delete \"$sel\" && printf \"%s\\n\" \"Deleted $sel\"\n}\n\nvpn_menu() {\n    while :; do\n        show_status\n        printf \"\\n%s\\n\" \"--- VPN Menu ---\"\n        printf \"1) Toggle VPN\\n2) Import VPN\\n3) Remove VPN\\n4) Back\\n\"\n        printf \"Choice: \" ; read -r choice\n        case \"$choice\" in\n            1) toggle_vpn ;;\n            2) import_vpn ;;\n            3) remove_vpn ;;\n            4) break ;;\n        esac\n    done\n}\n\nmain_menu() {\n    while :; do\n        show_status\n        printf \"\\n%s\\n\" \"--- Menu ---\"\n        printf \"1) Connect Wi-Fi\\n2) Disconnect Wi-Fi\\n3) VPN Menu\\n4) Rescan Wi-Fi\\n5) Forget Wi-Fi\\n6) Exit\\n\"\n        printf \"Choice: \" ; read -r choice\n        case \"$choice\" in\n            1) connect_wifi ;;\n            2) disconnect_wifi ;;\n            3) vpn_menu ;;\n            4) rescan_wifi ;;\n            5) forget_network ;;\n            6) break ;;\n        esac\n    done\n}\n\nmain_menu\ncleanup\n"
  },
  {
    "path": ".local/bin/reload-wall",
    "content": "#!/bin/sh\n\n# Cache file lists sorted alphabetically\nIMG_FILES=$(find \"$HOME/pictures/walls\" -type f \\( -name \"*.jpg\" -o -name \"*.jpeg\" -o -name \"*.png\" -o -name \"*.bmp\" \\) | sort)\nVID_FILES=$(find \"$HOME/pictures/walls\" -type f \\( -name \"*.mp4\" -o -name \"*.mkv\" -o -name \"*.webm\" \\) | sort)\n\n# Kill previous instance of the currently running background process\nkill_bg() {\n    if pgrep swaybg > /dev/null; then\n        pkill swaybg\n    elif pgrep mpvpaper > /dev/null; then\n        pkill mpvpaper\n    fi\n}\n\n# Function to set background using swaybg and generate/apply Flavours theme\nset_swaybg() {\n    selected_image=\"$1\"\n    nohup swaybg -i \"$selected_image\" -m fill > /dev/null 2>&1 &\n    if [ \"$THEME_UPDATE\" = \"yes\" ]; then\n        flavours generate dark \"$selected_image\" >/dev/null 2>&1\n        flavours apply generated >/dev/null 2>&1 &\n    fi\n}\n\n# Function to set wallpaper using mpvpaper\nset_mpvpaper() {\n    selected_video=\"$1\"\n    nohup mpvpaper -vsp -o \"no-audio pause=no --loop --ytdl-format='bestvideo[height<=1080]+bestaudio/best'\" '*' \"$selected_video\" > /dev/null 2>&1 &\n}\n\n# Prompt for exact file selection or random mode\necho \"(1) Random background | (2) Choose specific file\"\nread -r mode_choice\n\n# If mode is specific selection, display files and get user choice\nif [ \"$mode_choice\" = \"2\" ]; then\n    echo \"Available files:\"\n    all_files=$(printf \"%s\\n%s\" \"$IMG_FILES\" \"$VID_FILES\" | sort | nl)\n    echo \"$all_files\"\n    echo \"Select a file number:\"\n    read -r file_choice\n    selected_file=$(printf \"%s\\n%s\" \"$IMG_FILES\" \"$VID_FILES\" | sort | sed -n \"${file_choice}p\")\n\n    if [ -z \"$selected_file\" ]; then\n        echo \"Invalid selection.\"\n        exit 1\n    fi\n\n    # Determine whether selected file is image or video\n    if echo \"$selected_file\" | grep -Eq \"\\.(jpg|jpeg|png|bmp)$\"; then\n        # Prompt for theme update only for swaybg\n        echo \"Enable Flavours theme update on image change? (y/n)\"\n        read -r theme_choice\n        THEME_UPDATE=$( [ \"$theme_choice\" = \"y\" ] && echo \"yes\" || echo \"no\" )\n        set_swaybg \"$selected_file\"\n    elif echo \"$selected_file\" | grep -Eq \"\\.(mp4|mkv|webm)$\"; then\n        set_mpvpaper \"$selected_file\"\n    fi\n\n    echo \"Background set with selected file.\"\n    exit 0\nfi\n\n# Prompt user for choice: random swaybg or mpvpaper\necho \"(1) swaybg (random image) | (2) mpvpaper (random video)\"\nread -r choice\n\n# Prompt for theme update preference for swaybg\nif [ \"$choice\" = \"1\" ]; then\n    echo \"Enable Flavours theme update on image change? (y/n)\"\n    read -r theme_choice\n    THEME_UPDATE=$( [ \"$theme_choice\" = \"y\" ] && echo \"yes\" || echo \"no\" )\nfi\n\n# Main loop for reloading or confirming\nwhile true; do\n    # Kill only the active background process\n    kill_bg\n\n    # Set background based on initial choice\n    case \"$choice\" in\n        1)\n            set_swaybg \"$(echo \"$IMG_FILES\" | shuf -n 1)\"\n            ;;\n        2)\n            set_mpvpaper \"$(echo \"$VID_FILES\" | shuf -n 1)\"\n            ;;\n        *)\n            echo \"Invalid choice.\"\n            exit 1\n            ;;\n    esac\n\n    # Ask for reload or confirm, no need to press Enter\n    echo \"(r)eload or (y)es to confirm\"\n    stty -echo -icanon time 0 min 0\n    while :; do\n        action=$(dd bs=1 count=1 2>/dev/null)\n        if [ \"$action\" = \"r\" ]; then\n            echo \"Reloading...\"\n            break\n        elif [ \"$action\" = \"y\" ]; then\n            echo \"Background confirmed.\"\n            stty sane\n            exit 0\n        fi\n    done\ndone\n"
  },
  {
    "path": ".local/bin/spefetch",
    "content": "#!/bin/sh\n#\n# spefetch - precise system info display\n\n# Configuration\n: \"${USE_NERD_FONTS:=1}\"  # Set to 0 for emoji fallback\n\n# ANSI color variables\nreset=$(printf '\\033[0m')\nred=$(printf '\\033[31m')\ngreen=$(printf '\\033[32m')\nyellow=$(printf '\\033[33m')\nblue=$(printf '\\033[34m')\nmagenta=$(printf '\\033[35m')\ncyan=$(printf '\\033[36m')\nwhite=$(printf '\\033[37m')\n\n# Symbol configuration with automatic fallback\nif [ \"$USE_NERD_FONTS\" -eq 1 ]; then\n    os_icon=\"󰍹\" ker_icon=\"󰌢\" up_icon=\"󰔟\" pkg_icon=\"󰏖\"\n    sh_icon=\"󰆍\" de_icon=\"󰖲\" inst_icon=\"󰄾\"\nelse\n    os_icon=\"🏠\" ker_icon=\"💫\" up_icon=\"⏳\" pkg_icon=\"📦\"\n    sh_icon=\"🐚\" de_icon=\"🎨\" inst_icon=\"📅\"\nfi\n\n# System info detection (with lowercase OS)\nget_hostname() {\n    (hostname -f || uname -n) 2>/dev/null | cut -d'.' -f1 | tr -d ' ' | head -c 15\n}\n\nuser=$(id -un | tr '[:upper:]' '[:lower:]')\nhost=$(get_hostname | tr '[:upper:]' '[:lower:]')\nos=$( ( . /etc/os-release && echo \"${PRETTY_NAME:-$NAME}\" || uname -o || uname -s ) | tr '[:upper:]' '[:lower:]')\nkernel=$(uname -sr | tr '[:upper:]' '[:lower:]')\nuptime=$(uptime -p 2>/dev/null | sed 's/up //;s/ days\\?/d/;s/ hours\\?/h/;s/ minutes\\?/m/' | tr -d ',')\nshell=$(basename \"${SHELL:-unknown}\" | tr '[:upper:]' '[:lower:]')\n\n# Estimate installation age using /lost+found directory\ninstall_days=\"unknown\"\nif [ -d /lost+found ]; then\n    install_date=$(stat -c %W /lost+found 2>/dev/null)\n    if [ \"$install_date\" -gt 0 ] 2>/dev/null; then\n        install_days=$(( ( $(date +%s) - install_date ) / 86400 ))\n    fi\nfi\n\n# Enhanced package detection\ndetect_pkgs() {\n    if command -v xbps-query >/dev/null; then       # Void\n        xbps-query -l | wc -l\n    elif command -v dpkg >/dev/null; then          # Debian\n        dpkg -l | grep -c '^ii'\n    elif command -v pacman >/dev/null; then        # Arch\n        pacman -Qq | wc -l\n    elif command -v rpm >/dev/null; then           # RPM\n        rpm -qa | wc -l\n    elif command -v dnf >/dev/null; then           # Fedora\n        dnf list installed | wc -l\n    elif command -v zypper >/dev/null; then        # openSUSE\n        zypper se -i | wc -l\n    elif command -v apk >/dev/null; then           # Alpine\n        apk info | wc -l\n    else\n        echo 0\n    fi\n}\n\n# Fixed package manager detection\ndetect_pkg_manager() {\n    for cmd in xbps-query dpkg pacman rpm dnf zypper apk; do\n        if command -v $cmd >/dev/null; then\n            case $cmd in\n                \"xbps-query\") echo \"xbps\" ;;\n                *) echo \"${cmd}\" ;;\n            esac\n            return\n        fi\n    done\n    echo \"unknown\"\n}\n\npkg_count=$(detect_pkgs)\npkg_manager=$(detect_pkg_manager)\nnix_pkgs=$(\n    (nix-store -q --references /run/current-system/sw 2>/dev/null\n     nix-store -q --references ~/.nix-profile 2>/dev/null\n    ) | sort -u | wc -l\n)\nflat_pkgs=$(flatpak list --columns=app 2>/dev/null | tail -n +1 | wc -l)\nsnap_pkgs=$(snap list 2>/dev/null | tail -n +2 | wc -l)\n\n# DE/WM detection\nui=$(echo \"${XDG_CURRENT_DESKTOP:-$DESKTOP_SESSION}\" | tr '[:upper:]' '[:lower:]')\n\n# Fixed color package string builder (blue count)\nbuild_pkg_string() {\n    printf \"%s  %s%s (%s) %s%s (flatpak) %s%s (nix) %s%s (snap)\" \\\n        \"${magenta}${pkg_icon}\" \\\n        \"${blue}\" \"${pkg_count}\" \"${blue}${pkg_manager}\" \\\n        \"${cyan}\" \"${flat_pkgs}\" \\\n        \"${green}\" \"${nix_pkgs}\" \\\n        \"${red}\" \"${snap_pkgs}\"\n}\n\n# Perfectly aligned output\ncat <<EOF\n${reset}\n${cyan}     /\\_/\\     ${green}${user}${yellow}@${magenta}${host}\n${cyan}    / ${white}o${blue} ${white}o${cyan} \\    ${red}${os_icon}  ${white}${os}\n${cyan}    \\   ^ /    ${yellow}${ker_icon}  ${white}${kernel}\n${cyan}     './ \\     ${green}${up_icon} ${white} ${uptime} ${magenta}${inst_icon} ${white}${install_days}d\n${cyan}      |||      $(build_pkg_string)\n${cyan}     /   \\     ${blue}${sh_icon}  ${white}${shell}\n${cyan}               ${yellow}${de_icon}  ${white}${ui:-unknown}\n${reset}\nEOF\n"
  },
  {
    "path": ".local/bin/start-comp",
    "content": "#!/bin/sh\n# Unified compositor launcher with optional PipeWire support\n\n# --- Parse Arguments ---\nSTART_PIPEWIRE=false\nCOMPOSITOR=\"\"\n\nwhile [ $# -gt 0 ]; do\n  case \"$1\" in\n    -p) START_PIPEWIRE=true ;;\n    -*) echo \"Unknown option: $1\" >&2; exit 1 ;;\n    *) COMPOSITOR=\"$1\" ;;\n  esac\n  shift\ndone\n\n[ -z \"$COMPOSITOR\" ] && {\n  echo \"Usage: $(basename \"$0\") [-p] <compositor>\" >&2\n  exit 1\n}\n\n# --- Setup Logging ---\nmkdir -p \"$HOME/.cache\"\nLOGFILE=\"$HOME/.cache/wsession-errors\"\necho \"$COMPOSITOR session started: $(date)\" >> \"$LOGFILE\"\nexec >> \"$LOGFILE\" 2>&1\n\n# --- Environment Variables ---\nexport QT_QPA_PLATFORM=wayland\nexport QT_QPA_PLATFORMTHEME_QT6=wayland\nexport QT_QPA_PLATFORMTHEME=qt6ct\nexport QT_QPA_PLATFORMTHEME_QT6=qt6ct\nexport QT_WAYLAND_DISABLE_WINDOWDECORATION=1\nexport ELM_DISPLAY=wl\nexport SDL_VIDEODRIVER=wayland\nexport GTK_USE_PORTAL=1\nexport MOZ_ENABLE_WAYLAND=1\nexport XCURSOR_THEME=Kaela-Kovalskia-v2\nexport XCURSOR_SIZE=24\nexport XDG_SESSION_TYPE=wayland\nexport XDG_SESSION_DESKTOP=\"$COMPOSITOR\"\nexport XDG_CURRENT_DESKTOP=\"$COMPOSITOR\"\nexport XDG_DATA_DIRS=\"$HOME/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share\"\nexport NO_AT_BRIDGE=1\nexport XKB_DEFAULT_LAYOUT=us,fr\nexport XKB_DEFAULT_OPTIONS=grp:rctrl_rshift_toggle\n\n# --- D-Bus Session ---\nif [ -z \"$DBUS_SESSION_BUS_ADDRESS\" ]; then\n  eval \"$(/usr/bin/dbus-launch --exit-with-session --sh-syntax)\"\nfi\n\n# Ensure desktop services see the updated environment\ndbus-update-activation-environment --all &\n\n# --- Clean Previous Session ---\nrm -f \"$HOME\"/.cache/*.wob\n\n# --- PipeWire Stack ---\nif [ \"$START_PIPEWIRE\" = true ]; then\n  echo \"Launching PipeWire stack...\"\n\n  if ! pgrep -x pipewire >/dev/null; then\n    pipewire &\n    sleep 1\n  fi\n\n  if ! pgrep -x wireplumber >/dev/null; then\n    wireplumber &\n  fi\n\n  if ! pgrep -x pipewire-pulse >/dev/null; then\n    pipewire-pulse &\n  fi\nfi\n\n# --- Launch Compositor ---\ncommand -v \"$COMPOSITOR\" >/dev/null 2>&1 || {\n  echo \"Compositor not found: $COMPOSITOR\" >&2\n  exit 1\n}\n\nexec \"$COMPOSITOR\"\n"
  },
  {
    "path": ".local/bin/updtscan",
    "content": "#!/bin/sh\n\n# Configuration\nCHECK_INTERVAL=14400  # 4 hours in seconds\nNOTIFY_TIMEOUT=14400000  # Notification timeout in milliseconds\nLOCKFILE=\"/tmp/update-checker.lock\"\n\n# Create lock file and cleanup on exit\nif [ -e \"$LOCKFILE\" ]; then\n    echo \"Error: Another instance is already running!\" >&2\n    exit 1\nfi\ntouch \"$LOCKFILE\"\ntrap 'rm -f \"$LOCKFILE\"; exit' INT TERM EXIT\n\n# Function to check for command availability\ncommand_exists() {\n    command -v \"$1\" >/dev/null 2>&1\n}\n\n# Function to execute commands with elevated privileges (simplified for sudoers config)\nrun_with_privileges() {\n    if command_exists sudo; then\n        sudo \"$@\"\n        return $?\n    elif command_exists pkexec; then\n        pkexec \"$@\"\n        return $?\n    else\n        echo \"Error: No privilege escalation tool found!\" >&2\n        return 1\n    fi\n}\n\n# Package manager checks (optimized for sudoers configuration)\ncheck_xbps() {\n    # xbps-install -Sy needs sudo for system-wide update, xbps-install -un might not, but for consistency use sudo\n    if run_with_privileges xbps-install -Sy >/dev/null 2>&1; then\n        run_with_privileges xbps-install -un 2>/dev/null | wc -l\n    else\n        echo 0\n    fi\n}\n\ncheck_pacman() {\n    # pacman -Sy needs sudo, pacman -Quq should not\n    if run_with_privileges pacman -Sy >/dev/null 2>&1; then\n        pacman -Quq 2>/dev/null | wc -l # pacman -Quq does not need sudo\n    else\n        echo 0\n    fi\n}\n\ncheck_apt() {\n    # apt update needs sudo, apt list --upgradable should not\n    if run_with_privileges apt update -qq >/dev/null 2>&1; then\n        apt list --upgradable 2>/dev/null | grep -c \"upgradable\" # apt list --upgradable doesn't need sudo\n    else\n        echo 0\n    fi\n}\n\ncheck_dnf() {\n    # dnf check-update might need sudo depending on configuration, dnf list updates might also\n    run_with_privileges dnf check-update -q >/dev/null\n    case $? in\n        0|100) dnf list updates -q 2>/dev/null | grep -c '^[a-zA-Z]' ;;\n        *) echo 0 ;;\n    esac\n}\n\ncheck_zypper() {\n    # zypper refresh needs sudo, zypper list-updates should also\n    if run_with_privileges zypper refresh -q >/dev/null 2>&1; then\n        run_with_privileges zypper -q list-updates -t package 2>/dev/null | wc -l\n    else\n        echo 0\n    fi\n}\n\ncheck_flatpak() {\n    # flatpak operations usually do not need sudo\n    flatpak remote-ls --updates 2>/dev/null | wc -l # flatpak doesn't need sudo\n}\n\n# Main update check function\ncheck_updates() {\n    total_updates=0\n    flatpak_updates=0\n\n    # System package managers\n    command_exists xbps-install && total_updates=$((total_updates + $(check_xbps)))\n    command_exists pacman && total_updates=$((total_updates + $(check_pacman)))\n    command_exists apt && total_updates=$((total_updates + $(check_apt)))\n    command_exists dnf && total_updates=$((total_updates + $(check_dnf)))\n    command_exists zypper && total_updates=$((total_updates + $(check_zypper)))\n\n    # Flatpak\n    command_exists flatpak && flatpak_updates=$(check_flatpak)\n\n    # Send notification if updates are available\n    if [ \"$total_updates\" -gt 0 ] || [ \"$flatpak_updates\" -gt 0 ]; then\n        notify-send -t \"$NOTIFY_TIMEOUT\" \"System Updates Available\" \\\n            \"Packages: $total_updates\\nFlatpaks: $flatpak_updates\"\n    fi\n}\n\n# Initial check\ncheck_updates\n\n# Periodic checks\n#while true; do\n#    sleep \"$CHECK_INTERVAL\"\n#    check_updates\n#done\n"
  },
  {
    "path": ".local/bin/usb-mnt",
    "content": "#!/bin/sh\n\n# Modified USB Mount Script with RW Access\n# Shows mount path and mounts read-write\n\nMOUNT_BASE=\"/tmp/usb-$(id -u)\"\n\nif [ -t 1 ]; then\n    GREEN='\\033[0;32m'\n    RED='\\033[0;31m'\n    YELLOW='\\033[0;33m'\n    NC='\\033[0m'\nelse\n    GREEN=''; RED=''; YELLOW=''; NC=''\nfi\n\ndie() {\n    printf \"${RED}%s${NC}\\n\" \"$1\" >&2\n    exit 1\n}\n\nfind_mountable() {\n    for dev in /dev/sd*; do\n        [ -e \"$dev\" ] || continue\n        [ \"$(lsblk -d -rno RM,TYPE \"$dev\")\" = \"1 disk\" ] && {\n            part=$(lsblk -rno NAME \"$dev\" | awk 'NR==2 {print $0}')\n            [ -n \"$part\" ] && echo \"/dev/$part\" || echo \"$dev\"\n        }\n    done | sort | uniq\n}\n\nmount_workflow() {\n    devices=$(find_mountable)\n    [ -z \"$devices\" ] && die \"No mountable USB devices found\"\n\n    printf \"${GREEN}Available USB devices:${NC}\\n\"\n    n=1\n    echo \"$devices\" | while IFS= read -r dev; do\n        model=$(lsblk -rno MODEL \"$dev\" | head -1)\n        size=$(lsblk -rno SIZE \"$dev\" | head -1)\n        printf \"%2d) %s (%s %s)${NC}\\n\" \"$n\" \"$dev\" \"${model:-Unknown}\" \"$size\"\n        n=$((n+1))\n    done\n\n    printf \"Select device (1-%d): \" \"$(echo \"$devices\" | wc -l)\"\n    read -r choice\n    device=$(echo \"$devices\" | sed -n \"${choice}p\")\n    [ -z \"$device\" ] && die \"Invalid selection\"\n\n    # Create mount point\n    mount_point=$(mkdir -p \"$MOUNT_BASE\" && mktemp -d -p \"$MOUNT_BASE\" usb-XXXXXX) ||\n        die \"Failed to create mount point\"\n\n    # Mount with read-write access\n    printf \"Mounting %s to ${GREEN}%s${NC}...\\n\" \"$device\" \"$mount_point\"\n    if ! sudo mount -o rw,nosuid,nodev,noexec \"$device\" \"$mount_point\" 2>/dev/null; then\n        fstype=$(blkid -o value -s TYPE \"$device\" 2>/dev/null)\n        [ -n \"$fstype\" ] && sudo mount -t \"$fstype\" -o rw,nosuid,nodev,noexec \"$device\" \"$mount_point\" ||\n            die \"Failed to mount:\\n- Check filesystem: sudo fsck $device\"\n    fi\n\n    printf \"${GREEN}Mounted successfully at: %s${NC}\\n\" \"$mount_point\"\n    printf \"${YELLOW}Press Enter to unmount...${NC}\"\n    read -r _\n\n    sudo umount \"$mount_point\" && rmdir \"$mount_point\" &&\n        printf \"${GREEN}Unmounted successfully!${NC}\\n\" ||\n        die \"Failed to unmount - try manual: sudo umount $mount_point\"\n}\n\ncleanup() {\n    [ -d \"$MOUNT_BASE\" ] && find \"$MOUNT_BASE\" -type d -empty -delete 2>/dev/null\n}\ntrap cleanup EXIT\n\nmount_workflow\n"
  },
  {
    "path": ".local/bin/vertsearch-lf",
    "content": "#!/bin/bash\n\n# Path to the directory you want to search in\ndirectory=\"$1\"\ncache_dir=\"$HOME/.cache/vertical_videos\"\nprocessed_file=\"$cache_dir/processed_files.txt\"\nnon_vertical_file=\"$cache_dir/non_vertical_files.txt\"\n\n# Check if directory is provided and exists\nif [[ -z \"$directory\" || ! -d \"$directory\" ]]; then\n    echo \"Please provide a valid directory.\"\n    exit 1\nfi\n\n# Create a temporary directory for symlinks\nmkdir -p \"$cache_dir\"\n\n# Initialize the processed and non-vertical files list if they don't exist\ntouch \"$processed_file\"\ntouch \"$non_vertical_file\"\n\n# Load processed files into an array for faster lookups\nmapfile -t processed_files < \"$processed_file\"\nmapfile -t non_vertical_files < \"$non_vertical_file\"\n\n# Find video files that have not been processed yet and are not symlinked in the cache directory\nfind \"$directory\" -type f \\( -name \"*.mp4\" -o -name \"*.mkv\" -o -name \"*.avi\" \\) | while read -r file; do\n    # Check if the file has already been processed using the absolute path\n    absolute_path=$(realpath \"$file\")\n    \n    # Ensure proper quoting for comparison\n    if [[ ! \" ${processed_files[@]} \" =~ \" ${absolute_path} \" && ! \" ${non_vertical_files[@]} \" =~ \" ${absolute_path} \" ]]; then\n        # Skip files that have already been symlinked in the cache directory\n        if ! [[ -e \"$cache_dir/$(basename \"$file\")\" ]]; then\n            echo \"Processing: $file\"\n            width=$(ffprobe -v error -select_streams v:0 -show_entries stream=width -of default=noprint_wrappers=1:nokey=1 \"$file\")\n            height=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of default=noprint_wrappers=1:nokey=1 \"$file\")\n            \n            if (( height > width )); then\n                ln -s \"$file\" \"$cache_dir/$(basename \"$file\")\"\n                echo \"Linked vertical video: $(basename \"$file\")\"\n                echo \"$absolute_path\" >> \"$processed_file\"\n            else\n                echo \"Not vertical, adding to non-vertical list: $file\"\n                echo \"$absolute_path\" >> \"$non_vertical_file\"\n            fi\n        else\n            echo \"Already linked (skipping): $file\"\n        fi\n    else\n        if [[ \" ${non_vertical_files[@]} \" =~ \" ${absolute_path} \" ]]; then\n            echo \"Already checked and found non-vertical (skipping): $file\"\n        else\n            echo \"Already processed (skipping): $file\"\n        fi\n    fi\ndone\n\n# Open lf in the temporary directory containing symlinks to vertical videos\nyazi \"$cache_dir\"\n\n"
  },
  {
    "path": ".local/bin/yt-search",
    "content": "#!/bin/sh\n\nif [ -z \"$1\" ]; then\n  printf \"search query: \"\n  read -r query\nelse\n  query=\"$1\"\nfi\n\nquery=$(echo \"$query\" | sed 's/ /+/g')\necho \"$query\"\n\n# yt_api_key location\nhome=\"$HOME\"  # Define home variable\nyt_api_key=\"$(cat \"${home}/.local/share/apis/YT_API_KEY\")\"\nurlstring=\"https://www.googleapis.com/youtube/v3/search?part=snippet&q=${query}&type=video&maxResults=20&key=${yt_api_key}\"\n\n# Using a temporary file to hold the output\ntempfile=$(mktemp) || exit 1\n\n# Fetching data and processing it\ncurl -s \"${urlstring}\" | \\\n  jq -r '.items[] | select(.id.videoId != null) | \"\\(.snippet.channelTitle) => \\(.snippet.title) https://youtu.be/\\(.id.videoId)\"' > \"$tempfile\"\n\n# Using fzf to select a video\nselected_video=$(fzf --with-nth='1..-2' +m < \"$tempfile\")\n\n# Clean up temporary file\nrm -f \"$tempfile\"\n\n# Extracting the last field for the URL\nif [ -n \"$selected_video\" ]; then\n  video_url=$(echo \"$selected_video\" | awk '{print $NF}' | sed 's/[[:space:]]*//g')  # Remove any trailing spaces\n  mpv \"$video_url\"\nelse\n  echo \"No video selected.\"\nfi\n"
  },
  {
    "path": ".local/share/applications/browser.desktop",
    "content": "[Desktop Entry]\nName=Web Browser\nIcon=internet-web-browser\nExec=flatpak run io.gitlab.librewolf-community -new-tab %U\nTerminal=false\nType=Application\nStartupWMClass=librewolf\nCategories=Network;\n"
  },
  {
    "path": ".local/share/applications/file.desktop",
    "content": "[Desktop Entry]\nType=Application\nName=File manager\nComment=File manager\nIcon=folder\nExec=pcmanfm-qt\nTerminal=false\nMimeType=inode/directory;\nCategories=System;FileTools;FileManager;ConsoleOnly;\nKeywords=File;Manager;Management;Explorer;Launcher;\n"
  },
  {
    "path": ".local/share/applications/img.desktop",
    "content": "[Desktop Entry]\nName=Image viewer\nGenericName=Image viewer\nGenericName[en_US]=Image viewer\nComment=Fast Image Viewer\nExec=swayimg %F\nTerminal=false\nType=Application\nCategories=Graphics;2DGraphics;Viewer;\nMimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/x-bmp;image/x-pcx;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-tga;image/x-xbitmap;image/heif;image/webp\nIcon=gwenview\nKeywords=photo;picture;image;view;gif;webm\n"
  },
  {
    "path": ".local/share/applications/text.desktop",
    "content": "[Desktop Entry]\nType=Application\nName=Text editor\nIcon=nvim\nTryExec=nvim\nExec=nvim %F\nTerminal=true\nCategories=Utility;TextEditor;\nStartupNotify=false\nMimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;\n"
  },
  {
    "path": ".local/share/applications/video.desktop",
    "content": "[Desktop Entry]\nType=Application\nName=Media Player\nGenericName=Multimedia player\nIcon=mpv\nTryExec=mpv\nExec=mpv --player-operation-mode=pseudo-gui -- %U\nTerminal=false\nCategories=AudioVideo;Audio;Video;Player;TV;\nMimeType=application/ogg;application/x-ogg;application/mxf;application/sdp;application/smil;application/x-smil;application/streamingmedia;application/x-streamingmedia;application/vnd.rn-realmedia;application/vnd.rn-realmedia-vbr;audio/aac;audio/x-aac;audio/vnd.dolby.heaac.1;audio/vnd.dolby.heaac.2;audio/aiff;audio/x-aiff;audio/m4a;audio/x-m4a;application/x-extension-m4a;audio/mp1;audio/x-mp1;audio/mp2;audio/x-mp2;audio/mp3;audio/x-mp3;audio/mpeg;audio/mpeg2;audio/mpeg3;audio/mpegurl;audio/x-mpegurl;audio/mpg;audio/x-mpg;audio/rn-mpeg;audio/musepack;audio/x-musepack;audio/ogg;audio/scpls;audio/x-scpls;audio/vnd.rn-realaudio;audio/wav;audio/x-pn-wav;audio/x-pn-windows-pcm;audio/x-realaudio;audio/x-pn-realaudio;audio/x-ms-wma;audio/x-pls;audio/x-wav;video/mpeg;video/x-mpeg2;video/x-mpeg3;video/mp4v-es;video/x-m4v;video/mp4;application/x-extension-mp4;video/divx;video/vnd.divx;video/msvideo;video/x-msvideo;video/ogg;video/quicktime;video/vnd.rn-realvideo;video/x-ms-afs;video/x-ms-asf;audio/x-ms-asf;application/vnd.ms-asf;video/x-ms-wmv;video/x-ms-wmx;video/x-ms-wvxvideo;video/x-avi;video/avi;video/x-flic;video/fli;video/x-flc;video/flv;video/x-flv;video/x-theora;video/x-theora+ogg;video/x-matroska;video/mkv;audio/x-matroska;application/x-matroska;video/webm;audio/webm;audio/vorbis;audio/x-vorbis;audio/x-vorbis+ogg;video/x-ogm;video/x-ogm+ogg;application/x-ogm;application/x-ogm-audio;application/x-ogm-video;application/x-shorten;audio/x-shorten;audio/x-ape;audio/x-wavpack;audio/x-tta;audio/AMR;audio/ac3;audio/eac3;audio/amr-wb;video/mp2t;audio/flac;audio/mp4;application/x-mpegurl;video/vnd.mpegurl;application/vnd.apple.mpegurl;audio/x-pn-au;video/3gp;video/3gpp;video/3gpp2;audio/3gpp;audio/3gpp2;video/dv;audio/dv;audio/opus;audio/vnd.dts;audio/vnd.dts.hd;audio/x-adpcm;application/x-cue;audio/m3u;\nX-KDE-Protocols=ftp,http,https,mms,rtmp,rtsp,sftp,smb,srt,rist,webdav,webdavs\nStartupWMClass=mpv\n"
  },
  {
    "path": ".local/share/fonts/git-fonts.sh",
    "content": "#!/bin/sh\n\n# Define the repository URL and the fonts directory\nREPO_URL=\"https://github.com/Speyll/fonts.git\"\nFONT_DIR=\"$HOME/.local/share/fonts/fonts_repo\" # Temporary directory for cloning\n\n# Clone or update the fonts repository\nif [ -d \"$FONT_DIR\" ]; then\n    # If the directory exists, pull the latest changes\n    cd \"$FONT_DIR\"\n    git pull\nelse\n    # Clone the repository if it doesn't exist\n    git clone \"$REPO_URL\" \"$FONT_DIR\"\nfi\n\n# Move fonts to the main fonts directory\nmv \"$FONT_DIR/\"* \"$HOME/.local/share/fonts/\"\n# Optionally remove the temporary directory\nrm -rf \"$FONT_DIR\"\n\n# Update font cache\nfc-cache -f -v\n\necho \"Fonts installed/updated successfully!\"\n"
  },
  {
    "path": ".local/share/icons/git-cursors.sh",
    "content": "#!/bin/sh\n\n# Define the repository URL and the fonts directory\nREPO_URL=\"https://github.com/Speyll/cursors.git\"\nCUR_DIR=\"$HOME/.local/share/fonts/cursors_repo\" # Temporary directory for cloning\n\n# Clone or update the cursors repository\nif [ -d \"$CUR_DIR\" ]; then\n    # If the directory exists, pull the latest changes\n    cd \"$CUR_DIR\"\n    git pull\nelse\n    # Clone the repository if it doesn't exist\n    git clone \"$REPO_URL\" \"$CUR_DIR\"\nfi\n\n# Move cursors to the main fonts directory\nmv \"$CUR_DIR/\"* \"$HOME/.local/share/icons/\"\n# Optionally remove the temporary directory\nrm -rf \"$CUR_DIR\"\n\necho \"cursors installed/updated successfully!\"\n"
  },
  {
    "path": ".local/share/themes/Base16/openbox-3/bullet.xbm",
    "content": "#define bullet_width 10\n#define bullet_height 10\nstatic unsigned char bullet_bits[] = {\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00,\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\n"
  },
  {
    "path": ".local/share/themes/Base16/openbox-3/close.xbm",
    "content": "#define desk_width 6\n#define desk_height 6\nstatic unsigned char desk_bits[] = {\n   0x33, 0x33, 0x00, 0x00, 0x33, 0x33 };\n"
  },
  {
    "path": ".local/share/themes/Base16/openbox-3/desk.xbm",
    "content": "#define desk_width 6\n#define desk_height 6\nstatic unsigned char desk_bits[] = {\n   0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f };\n"
  },
  {
    "path": ".local/share/themes/Base16/openbox-3/desk_toggled.xbm",
    "content": "#define desk_width 6\n#define desk_height 6\nstatic unsigned char desk_bits[] = {\n   0x3f, 0x3f, 0x33, 0x33, 0x3f, 0x3f };\n"
  },
  {
    "path": ".local/share/themes/Base16/openbox-3/iconify.xbm",
    "content": "#define iconify_width 6\n#define iconify_height 6\nstatic unsigned char iconify_bits[] = {\n   0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c };\n"
  },
  {
    "path": ".local/share/themes/Base16/openbox-3/max.xbm",
    "content": "#define max7_width 6\n#define max7_height 6\nstatic unsigned char max7_bits[] = {\n   0x33, 0x33, 0x00, 0x00, 0x30, 0x30 };\n"
  },
  {
    "path": ".local/share/themes/Base16/openbox-3/max_disabled.xbm",
    "content": "#define max_disabled_width 6\n#define max_disabled_height 6\nstatic unsigned char max_disabled_bits[] = {\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\n"
  },
  {
    "path": ".local/share/themes/Base16/openbox-3/max_toggled.xbm",
    "content": "#define iconify2_width 6\n#define iconify2_height 6\nstatic unsigned char iconify2_bits[] = {\n   0x03, 0x03, 0x00, 0x00, 0x33, 0x33 };\n"
  },
  {
    "path": ".local/share/themes/Base16/openbox-3/menu.xbm",
    "content": "#define iconify2_width 6\n#define iconify2_height 6\nstatic unsigned char iconify2_bits[] = {\n   0x03, 0x03, 0x00, 0x00, 0x33, 0x33 };\n"
  },
  {
    "path": ".local/share/themes/Base16/openbox-3/shade.xbm",
    "content": "#define shade_width 6\n#define shade_height 6\nstatic unsigned char shade_bits[] = {\n   0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00 };\n"
  },
  {
    "path": ".local/share/themes/Base16/openbox-3/themerc",
    "content": "!! Colors\n!! Start flavours\n!! Window colors\nwindow.active.title.bg.color: #d5c4a1\nwindow.inactive.title.bg.color: #282828\nwindow.active.label.text.color: #282828\nwindow.inactive.label.text.color: #d5c4a1\nwindow.active.border.color: #d5c4a1\nwindow.inactive.border.color: #282828\nwindow.active.button.iconify.pressed.image.color: #282828\nwindow.active.button.iconify.disabled.image.color: #83a598\nwindow.active.button.iconify.unpressed.image.color: #282828\nwindow.active.button.iconify.toggled.pressed.image.color: #282828\nwindow.active.button.iconify.toggled.unpressed.image.color: #282828\nwindow.active.button.max.pressed.image.color: #282828\nwindow.active.button.max.disabled.image.color: #83a598\nwindow.active.button.max.unpressed.image.color: #282828\nwindow.active.button.max.toggled.pressed.image.color: #282828\nwindow.active.button.max.toggled.unpressed.image.color: #282828\nwindow.active.button.close.pressed.image.color: #282828\nwindow.active.button.close.disabled.image.color: #83a598\nwindow.active.button.close.unpressed.image.color: #282828\nwindow.active.button.close.toggled.pressed.image.color: #282828\nwindow.active.button.close.toggled.unpressed.image.color: #282828\nwindow.active.button.menu.pressed.image.color: #282828\nwindow.active.button.menu.disabled.image.color: #83a598\nwindow.active.button.menu.unpressed.image.color: #282828\nwindow.active.button.menu.toggled.pressed.image.color: #282828\nwindow.active.button.menu.toggled.unpressed.image.color: #282828\nwindow.inactive.button.iconify.pressed.image.color: #665c54\nwindow.inactive.button.iconify.disabled.image.color: #83a598\nwindow.inactive.button.iconify.unpressed.image.color: #665c54\nwindow.inactive.button.iconify.toggled.pressed.image.color: #665c54\nwindow.inactive.button.iconify.toggled.unpressed.image.color: #665c54\nwindow.inactive.button.max.pressed.image.color: #665c54\nwindow.inactive.button.max.disabled.image.color: #83a598\nwindow.inactive.button.max.unpressed.image.color: #665c54\nwindow.inactive.button.max.toggled.pressed.image.color: #ebdbb2\nwindow.inactive.button.max.toggled.unpressed.image.color: #ebdbb2\nwindow.inactive.button.close.pressed.image.color: #665c54\nwindow.inactive.button.close.disabled.image.color: #83a598\nwindow.inactive.button.close.unpressed.image.color: #665c54\nwindow.inactive.button.close.toggled.pressed.image.color: #665c54\nwindow.inactive.button.close.toggled.unpressed.image.color: #665c54\nwindow.inactive.button.menu.pressed.image.color: #665c54\nwindow.inactive.button.menu.disabled.image.color: #83a598\nwindow.inactive.button.menu.unpressed.image.color: #665c54\nwindow.inactive.button.menu.toggled.pressed.image.color: #665c54\nwindow.inactive.button.menu.toggled.unpressed.image.color: #665c54\n\n!! Menu colors\nmenu.items.bg.color: #282828\nmenu.items.text.color: #d5c4a1\nmenu.items.disabled.text.color: #665c54\nmenu.items.active.bg.color: #d5c4a1\nmenu.items.active.text.color: #282828\nmenu.separator.color: #d5c4a1\nmenu.border.color: #d5c4a1\nmenu.title.bg.color: #d5c4a1\nmenu.title.text.color: #282828\n\n!! OSD colors\nosd.border.color: #d5c4a1\nosd.label.text.color: #d5c4a1\nosd.bg.color: #282828\n!! End flavours\n\n!! Title bar\nwindow.button.height: 22\nwindow.titlebar.padding.width: 0\nwindow.titlebar.padding.height: 0\nwindow.button.spacing: 0\n\n!! Menu Background\nmenu.items.bg: flat\nmenu.overlap.x: 0\nmenu.overlap.y: 0\n\n!! Menu Separator\nmenu.separator.width: 0\nmenu.separator.padding.width: 4\nmenu.separator.padding.height: 2\n\n!! Menu Headers\nmenu.title.bg: flat\nmenu.title.text.justify: center\n\n!! Menu Border\nmenu.border.width: 0\n\n!! OSD\nosd.bg: flat\nosd.border.width: 1\nosd.window-switcher.width: 500\nosd.window-switcher.padding: 14\nosd.window-switcher.item.padding.x: 4\nosd.window-switcher.item.padding.y: 4\nosd.window-switcher.item.active.border.width: 2\nosd.workspace-switcher.boxes.width: 16\nosd.workspace-switcher.boxes.height: 16\n"
  },
  {
    "path": ".profile",
    "content": "# ~/.profile: executed by login shells\n\n# Source .bashrc if available\n[ -n \"$BASH_VERSION\" ] && [ -f \"$HOME/.bashrc\" ] && . \"$HOME/.bashrc\"\n\n# Add directories to PATH without duplicates\npath_prepend() {\n    [ -d \"$1\" ] && [[ \":$PATH:\" != *\":$1:\"* ]] && PATH=\"$1:$PATH\"\n}\n\n# User binaries and Nix paths (priority order)\npath_prepend \"$HOME/.nix-profile/bin\"      # Nix user packages\npath_prepend \"$HOME/.nix-profile/sbin\"     # Nix user system utilities\npath_prepend \"/nix/var/nix/profiles/default/bin\"  # Default Nix profile\npath_prepend \"$HOME/bin\"                   # Personal scripts\npath_prepend \"$HOME/.local/bin\"            # Local user binaries\nexport PATH\n\n# Core terminal environment\nexport TERMINAL=\"alacritty\"\nexport TERM=\"xterm-256color\"\nexport CLICOLOR=1\nexport EDITOR=\"nvim\"\nexport PAGER=\"less\"\nexport FILE=\"nnn\"\n\n# XDG Base Directory Specification\nexport XDG_CONFIG_HOME=\"$HOME/.config\"\nexport XDG_DATA_HOME=\"$HOME/.local/share\"\nexport XDG_CACHE_HOME=\"$HOME/.cache\"\nexport XDG_RUNTIME_DIR=\"/run/user/$(id -u)\"\n\n# XDG-compliant application settings\nexport NOTMUCH_CONFIG=\"$XDG_CONFIG_HOME/notmuch-config\"\nexport GTK2_RC_FILES=\"$XDG_CONFIG_HOME/gtk-2.0/gtkrc-2.0\"\nexport WGETRC=\"$XDG_CONFIG_HOME/wget/wgetrc\"\nexport WINEPREFIX=\"$XDG_DATA_HOME/wineprefixes/default\"\nexport KODI_DATA=\"$XDG_DATA_HOME/kodi\"\nexport PASSWORD_STORE_DIR=\"$XDG_DATA_HOME/password-store\"\nexport ANDROID_SDK_HOME=\"$XDG_CONFIG_HOME/android\"\nexport CARGO_HOME=\"$XDG_DATA_HOME/cargo\"\nexport GOPATH=\"$XDG_DATA_HOME/go\"\nexport ANSIBLE_CONFIG=\"$XDG_CONFIG_HOME/ansible/ansible.cfg\"\nexport WEECHAT_HOME=\"$XDG_CONFIG_HOME/weechat\"\nexport MBSYNCRC=\"$XDG_CONFIG_HOME/mbsync/config\"\nexport ELECTRUMDIR=\"$XDG_DATA_HOME/electrum\"\nexport NPM_CONFIG_USERCONFIG=\"$XDG_CONFIG_HOME/npm/npmrc\"\n\n# Application-specific settings\nexport LESSHISTFILE=\"-\"                     # Disable Less history\nexport GTK_OVERLAY_SCROLLING=0             # Disable smooth scrolling\nexport _JAVA_AWT_WM_NONREPARENTING=1       # Fix Java GUI apps\nexport TMUX_TMPDIR=\"$XDG_RUNTIME_DIR\"\n\n# Nix environment configuration\nexport NIX_PATH=\"nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs\"\nexport NIX_SSL_CERT_FILE=\"/etc/ssl/certs/ca-certificates.crt\"\n\n# FZF theming (handled in .bashrc for key bindings)\nexport FZF_DEFAULT_OPTS=\"--color=fg:7,bg:-1,hl:1 --color=fg+:15,bg+:8,hl+:9 --color=info:14,prompt:13,pointer:12,marker:10,spinner:11\"\n\n# NNN configuration (if installed)\ncommand -v nnn >/dev/null && export NNN_OPTS=\"dH\"\n\n# Some \"fixes\"\nexport GTK_USE_PORTAL=1\nexport MESA_SHADER_CACHE_MAX_SIZE=100G\n"
  },
  {
    "path": "README.md",
    "content": "## Table of Contents\n- [Introduction](#introduction)\n- [Software Used](#software-used)\n- [Special Scripts](#special-scripts)\n\n## Introduction\n\nWelcome to my dotfiles repository! This repository contains my personal dotfiles for Unix systems. I strive for efficiency, simplicity and some aesthetics if it's simple enough.\n\nIf you are here for my old bspwm, wayfire, sway or river setups you can find it [here](https://github.com/speyll/misc-dotfiles).\n\n## Software Used\n\n  - mainly `niri` and somtimes `labwc` as window managers (compositors).\n  - `foot` & `alacritty` Terminal emulator.\n  - ~~`yambar`~~ ~~`waybar`~~ `dms` Status bar.\n  - ~~`fuzzel` The application launcher menu.~~\n  - `pipewire` Audio server.\n  - `grim` For taking screenshots.\n  - `slurp` To select regions for screenshot capture.\n  - `brightnessctl` Tool to control screen brightness.\n  - `wlsunset` For managing night mode settings.\n  - `wl-clipboard` For clipboard management.\n  - `cliphist` To access clipboard history.\n  - ~~`imv`~~ `swayimg` My image viewer.\n  - ~~`fnott` Notification system.~~\n  - `mpv` Video player.\n  - `nvim` & `nano` Text editor\n  - `noto-fonts-emoji`, `noto-fonts-ttf`, `noto-fonts-cjk`,`nerd-fonts-symbols-ttf`, `cascadia-mono` Fonts.\n  - `flavours` For setting base16 colors pretty much everywhere.\n\nIf you're interested in a comprehensive list of packages, check out my post-install script for Void Linux, which sets up a highly efficient system. The script is well-documented and available [here](https://gist.github.com/Speyll/b2c46449fb9a9be44f07be3a81f01a2b).\n\nFor those on a Systemd distro, I also have a script tailored for Debian. While it's Debian-specific, it can provide insight into configuring other systemd distros. You can find it [here](https://gist.github.com/Speyll/852a81e28565a7dca2777a78da36eaa9).\n\n## Special Keybinds\n\n- `Mod + Enter`: Open terminal \n- `Mod + D`: Launch menu selector\n- `Mod + Shift + Q` or `Alt + F4`: Close focused window\n- `Mod + Shift + S`: Take screenshot of selected area (slurp + grim)\n- `Impr Screen`: Capture entire screen\n- `Mod + Comma`: Access clipboard selector\n\nNote: ~~I use an **AZERTY** keyboard, so some keybindings may differ. For example, workspace switching may not use numbers, and window closing may require `Mod + Shift + A` instead of `Q`. Similarly, the **emoji selector** may be triggered by `Mod + M` instead of semicolon, if you use a QWERTY Keyboard you might want to modify that before.~~ I forced myself to learn QWERTY so this no longer applies for the moment.\n\n## Special Scripts\n\nI've crafted special script to simplify environment variable setup. This script streamline the process of launching your preferred wayland compositor with the right configurations.\n\n- `start-comp`: Use this script to launch your compositor with configured environment variables, Example: `start-comp labwc`\n- `fuzzel-launcher`: If you want the same menu I use in my bar.\n\nAdditionally, there are other handy scripts available in `.local/bin`\n"
  }
]