Compare commits

...

18 Commits

Author SHA1 Message Date
faef8da677 fix(aquaai): reduce em dashes 2025-11-21 21:02:45 -05:00
7a59efb6b0 feat(zsh): dotfile add alias 2025-11-21 21:01:58 -05:00
b23d347e26 fix(aquaai): OpenAI API url format 2025-11-21 18:50:58 -05:00
2649688ef4 feat(aquaai): change default model 2025-11-16 21:03:47 -05:00
97e7ed3e53 refactor(zsh): dotfiles alias 2025-11-16 21:02:50 -05:00
9d821052d5 feat(zsh): dotfile aliases 2025-11-16 20:50:16 -05:00
5bb978bd20 fix(scripts): use correct pass entry 2025-11-10 18:43:17 -05:00
ab6a2dd0a3 refector(zsh): text editor 2025-11-10 18:38:45 -05:00
03fe12a280 feat(zsh): update dotfiles 2025-11-10 18:35:46 -05:00
0ab0cc9827 feat(scripts): python requirements 2025-11-10 07:05:25 -05:00
96f2fde330 feat(settings): add config 2025-11-09 17:45:28 -05:00
f5fb2a8c51 feat(i3): add config 2025-11-09 16:50:54 -05:00
2f9ecf7571 feat(orcaslicer): add config 2025-11-09 16:30:00 -05:00
32ff6cb136 feat(systemd): add config 2025-11-09 09:45:36 -05:00
5ba6a04786 feat(wireplumber): add config 2025-11-09 09:21:00 -05:00
a5bc31398f fix(zsh): disable rich format for AquaAI 2025-11-08 20:32:26 -05:00
d9be0f4e18 feat(scripts): add config 2025-11-08 19:34:01 -05:00
a7319f7d7f feat(hyprland): add config 2025-11-08 12:07:21 -05:00
88 changed files with 4296 additions and 9 deletions

25
home/bin/README.md Normal file
View File

@@ -0,0 +1,25 @@
# Scripts
## AquaAI
AquaAI is bash script that interacts with OpenAI and Ollama APIs to enable terminal based interaction with LLMs.
## connect-nas.sh
Connect to long storage NAS.
## convert-mp4-to-resolve.sh
Converts mp4 video files to a video format where the audio works with the linux version of Davinci Resolve.
## frc-photo-checklist.py
Python script to generate a Todoist checklist for taking photos at an FRC event.
```sh
python frc-photo-checklist.py [Event Key]
```
## get-mouse-battery.sh
Prints out the battery percentage of a mouse and if it is charging.

121
home/bin/audio/audio-lib.sh Normal file
View File

@@ -0,0 +1,121 @@
# Mix names
MONITOR_LEFT='A'
MONITOR_RIGHT='B'
HEADPHONE_01_LEFT='C'
HEADPHONE_01_RIGHT='D'
HEADPHONE_02_LEFT='E'
HEADPHONE_02_RIGHT='F'
BLANK_LEFT="G"
BLANK_RIGHT='H'
# Level constants
MUTE='0'
ZERO_DB='0db'
# Formats a number to match the matrix numbering.
function formatMatrixNum() {
printf "%02d" $1
}
# Returns audio card number with matching card name.
function getCardNumber() {
echo $(cat /proc/asound/cards | grep -m 1 $1 | grep -Po '\d{1,2}' | head -1)
}
# Checks if the card exists and if not exits.
#
# $1 card name
# $2 card number
function checkCard() {
if [ -z "$2" ]; then
echo $1 not connected
exit 1
else
echo $1 found at hw:$2
fi
}
# Prints a list of all controls for the given sound card.
function printControls() {
amixer -c $1 controls
}
# Sets a mix to a level.
#
# $1 card number
# $2 matrix number
# $3 mix channel
function setMix() {
amixer -c $1 set "Mix $3 Input $(formatMatrixNum $2)" $4
}
# Sets the volume levels for a mono mix.
#
# $1 card number
# $2 matrix number
# $3 mix left channel
# $4 mix right channel
# $5 volume
function setMonoMix() {
setMix $1 $2 $3 $5
setMix $1 $2 $4 $5
}
# Sets the volume levels for a stereo mix.
#
# $1 card number
# $2 matrix number
# $3 mix left channel
# $4 mix right channel
# $5 volume
function setStereoMix() {
matrix=$2
setMix $1 $matrix $3 $5
setMix $1 $matrix $4 $MUTE
setMix $1 $((matrix+1)) $3 $MUTE
setMix $1 $((matrix+1)) $4 $5
}
# Sets the volume levels for a mono mix for several outputs.
#
# $1 card number
# $2 matrix number
# $3 mix left channel
# $4 mix right channel
# $5 monitor volume
# $6 first headphone volume
# $7 second headphone volume
function setMono() {
monitor=$3
headphone1=$4
headphone2=$5
if [ -n $headphone1 ]; then headphone1=$monitor; fi
if [ -n $headphone2 ]; then headphone2=$monitor; fi
setMonoMix $1 $2 $MONITOR_LEFT $MONITOR_RIGHT $monitor
setMonoMix $1 $2 $HEADPHONE_01_LEFT $HEADPHONE_01_RIGHT $headphone1
setMonoMix $1 $2 $HEADPHONE_02_LEFT $HEADPHONE_02_RIGHT $headphone2
setMonoMix $1 $2 $BLANK_LEFT $BLANK_RIGHT $MUTE
}
# Sets the volume levels for a stereo mix for several outputs.
#
# $1 card number
# $2 matrix number
# $3 mix left channel
# $4 mix right channel
# $5 monitor volume
# $6 first headphone volume
# $7 second headphone volume
function setStereo() {
monitor=$3
headphone1=$4
headphone2=$5
if [ -n $headphone1 ]; then headphone1=$monitor; fi
if [ -n $headphone2 ]; then headphone2=$monitor; fi
setStereoMix $1 $2 $MONITOR_LEFT $MONITOR_RIGHT $monitor
setStereoMix $1 $2 $HEADPHONE_01_LEFT $HEADPHONE_01_RIGHT $headphone1
setStereoMix $1 $2 $HEADPHONE_02_LEFT $HEADPHONE_02_RIGHT $headphone2
setStereoMix $1 $2 $BLANK_LEFT $BLANK_RIGHT $MUTE
}

View File

@@ -0,0 +1,11 @@
#! /bin/bash
# Load user settings from config file.
. ~/.config/settings.conf
for file in *.aax; do
convertedFile="./${file%%.*}.m4b"
if [ ! -f "$convertedFile" ]; then
ffmpeg -y -activation_bytes ${activation_bytes} -i ./${file} -codec copy $convertedFile
fi
done

View File

@@ -0,0 +1,159 @@
#!/bin/bash
# Script to manuage audio mixing the the main audio interface.
# Import library
source $(dirname ${BASH_SOURCE[0]})/audio-lib.sh
INTERFACE_NAME='Clarett+ 8Pre'
INTERFACE_NUM=$(getCardNumber $INTERFACE_NAME)
checkCard "$INTERFACE_NAME" "$INTERFACE_NUM"
# Sets the volume levels of the first mono instrument.
#
# $1 monitor volume
# $2 first headphone volume
# $3 second headphone volume
function setMonoOne() {
setMono $INTERFACE_NUM 1 $1 $2 $3
}
# Sets the volume levels of the second mono instrument.
#
# $1 monitor volume
# $2 first headphone volume
# $3 second headphone volume
function setMonoTwo() {
setMono $INTERFACE_NUM 2 $1 $2 $3
}
# Sets the volume levels of the third mono instrument.
#
# $1 monitor volume
# $2 first headphone volume
# $3 second headphone volume
function setMonoThree() {
setMono $INTERFACE_NUM 3 $1 $2 $3
}
# Sets the volume levels of the first stereo instrument.
#
# $1 monitor volume
# $2 first headphone volume
# $3 second headphone volume
function setStereoOne() {
setStereo $INTERFACE_NUM 5 $1 $2 $3
}
# Sets the volume levels of the second stereo instrument.
#
# $1 monitor volume
# $2 first headphone volume
# $3 second headphone volume
function setStereoTwo() {
setStereo $INTERFACE_NUM 7 $1 $2 $3
}
# Sets the volume levels of the third stereo instrument.
#
# $1 monitor volume
# $2 first headphone volume
# $3 second headphone volume
function setStereoThree() {
setStereo $INTERFACE_NUM 9 $1 $2 $3
}
# Sets the volume levels of the fourth stereo instrument.
#
# $1 monitor volume
# $2 first headphone volume
# $3 second headphone volume
function setStereoFour() {
setStereo $INTERFACE_NUM 11 $1 $2 $3
}
# Sets the volume levels of the fifth stereo instrument.
#
# $1 monitor volume
# $2 first headphone volume
# $3 second headphone volume
function setStereoFive() {
setStereo $INTERFACE_NUM 13 $1 $2 $3
}
# Sets the volume levels of the sixth stereo instrument.
#
# $1 monitor volume
# $2 first headphone volume
# $3 second headphone volume
function setStereoSix() {
setStereo $INTERFACE_NUM 15 $1 $2 $3
}
# Sets the volume levels of the studio microphone.
#
# $1 monitor volume
# $2 first headphone volume
# $3 second headphone volume
function setMic() {
setMono $INTERFACE_NUM 4 $1 $2 $3
}
# Sets the volume levels of the computer.
#
# $1 monitor volume
# $2 first headphone volume
# $3 second headphone volume
function setComputerAudio() {
setStereo $INTERFACE_NUM 17 $1 $2 $3
}
# Sets the volume levels of all instrument.
#
# $1 monitor volume
# $2 first headphone volume
# $3 second headphone volume
function setInstruments() {
setMonoOne $1 $2 $3
setMonoTwo $1 $2 $3
setMonoThree $1 $2 $3
setStereoOne $1 $2 $3
setStereoTwo $1 $2 $3
setStereoThree $1 $2 $3
setStereoFour $1 $2 $3
setStereoFive $1 $2 $3
setStereoSix $1 $2 $3
}
function DAWMode() {
setInstruments $MUTE
setMic $MUTE
setComputerAudio $ZERO_DB
}
function NormalMode() {
setInstruments $ZERO_DB
setMic $MUTE
setComputerAudio $ZERO_DB
}
function PrintHelp() {
echo AquaMixer
echo '-h --help print out help options'
echo '-d --daw set interface to DAW mode'
echo '-n --normal set interface to normal mode'
exit 0
}
for var in "$@"; do
if [ $var == '-h' ] || [ $var == '--help' ]; then
PrintHelp
elif [ $var == '-d' ] || [ $var == '--daw' ]; then
DAWMode
elif [ $var == '-n' ] || [ $var == '--normal' ]; then
NormalMode
fi
done

View File

@@ -0,0 +1,11 @@
#!/bin/bash
# Script to add another audio interface if available.
DEVICE_NAME='ES-8'
DEVICE_NUM=$(getCardNumber $DEVICE_NAME)
checkCard $DEVICE_NAME $DEVICE_NUM
# Start up audio interface
alsa_in -d hw:$DEVICENUM -j "$DEVICENAME In" -q 1 &
alsa_out -d hw:$DEVICENUM -j "$DEVICENAME Out" -q 1 &

View File

@@ -0,0 +1,17 @@
#!/bin/bash
# Script to add another audio interface if available.
# Import library
source $(dirname $(realpath ${BASH_SOURCE[0]}))/audio-lib.sh
DEVICE_NAME='ES-9'
DEVICE_NUM=$(getCardNumber $DEVICE_NAME)
checkCard $DEVICE_NAME $DEVICE_NUM
# Start up ES-5
pkill es-5-pipewire || true
/opt/es-5-pipewire/es-5-pipewire >/dev/null 2>/dev/null &
sleep 0.1
jack_connect ES-5:output "$DEVICE_NAME:playback_SL" || true
jack_connect ES-5:output "$DEVICE_NAME:playback_AUX6" || true

View File

@@ -0,0 +1,7 @@
#!/bin/bash
# Script to stop ES-9 audio interface
pkill alsa_in
pkill alsa_out
pkill es-5-pipewire

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env sh
# Script to bring up a prompt to set synth power state.
current='Keep current state'
off='Power synths off'
on='Power synths on'
selected=$(echo -e "${current}\n${off}\n${on}" | rofi -dmenu -p \
'Change synth power' -theme ~/.config/rofi/themes/aqua)
if [ "$selected" == "$off" ]; then
python ~/.config/scripts/audio/synth-power.py -o
elif [ "$selected" == "$on" ]; then
python ~/.config/scripts/audio/synth-power.py -d
fi

View File

@@ -0,0 +1,88 @@
#! /bin/bash
# Kill Pulse.
function killPulse() {
systemctl --user stop pulseaudio.socket
systemctl --user stop pulseaudio.service
pulseaudio -k
killall pulseaudio
}
# Start Pulseaudio properly.
function fixPulse() {
PULSE="$(alsamixer 2>&1 | killall alsamixer)"
if [[ $PULSE == *'Connection refused'* ]]; then
echo 'Fixing Pulseaudio'
killPulse
sleep 0.1
pulseaudio -D
fixPulse
else
echo 'Pulseaudio is working correctly'
fi
}
# Start up programs that use audio.
function launchi3() {
if [ -z "$skipi3" ]; then
echo Opening i3wm sound workspaces
sleep .1 && i3-msg 'workspace 5; exec brave-browser'
#sleep 5.1 && python ~/bin/start-firefox.py
fi
}
# Set up sinks.
function setupSinks() {
pactl set-default-sink speakers
pactl set-default-source sm7b
}
# Connect sinks to audio interface
function connectSinks() {
pw-link speakers:monitor_FL alsa_output.usb-Focusrite_Clarett__8Pre_00002325-00.pro-output-0:playback_AUX0
pw-link speakers:monitor_FR alsa_output.usb-Focusrite_Clarett__8Pre_00002325-00.pro-output-0:playback_AUX1
pw-link alsa_input.usb-Focusrite_Clarett__8Pre_00002325-00.pro-input-0:capture_AUX3 sm7b:input_FL
pw-link alsa_input.usb-Focusrite_Clarett__8Pre_00002325-00.pro-input-0:capture_AUX3 sm7b:input_FR
return $?
}
function renameInterface() {
for n in `seq 0 17` ; do
jack_property -p -s "alsa:pcm:2:hw:2,0:capture:capture_${n}" http://jackaudio.org/metadata/pretty-name "capture_$((n+1))"
done
for n in `seq 0 19` ; do
jack_property -p -s "alsa:pcm:2:hw:2,0:playback:playback_${n}" http://jackaudio.org/metadata/pretty-name "playback_$((n+1))"
done
for n in `seq 0 19` ; do
jack_property -p -s "alsa:pcm:2:hw:2,0:playback:monitor_${n}" http://jackaudio.org/metadata/pretty-name "monitor_$((n+1))"
done
}
# Restart the Wireplumber service.
function restartWireplumber() {
systemctl --user stop wireplumber
sleep 5
systemctl --user restart wireplumber
}
# arg parser
for arg in "$@"
do
# Skip commands for i3wm
if [[ $arg == *"-s"* ]]; then
skipi3=true
fi
done
# Wire sinks
setupSinks
# Eurorack audio interface
sh ~/bin/audio/es9start.sh
launchi3
systemctl --user restart polybar
sleep 5
restartWireplumber

View File

@@ -0,0 +1,63 @@
#!/usr/bin/env python3
# Program to control synthesizers power state.
import argparse
import configparser
import os,sys,inspect
currentDir = os.path.dirname(os.path.abspath(
inspect.getfile(inspect.currentframe())))
parentDir = os.path.dirname(currentDir)
sys.path.insert(0, parentDir)
from homeassistant import HomeAssistant
# Parse settings config
SCRIPT_DIR = os.path.abspath(os.path.dirname(sys.argv[0]))
configString = '[Settings]\n' + open(SCRIPT_DIR + '/../../settings.conf').read()
configParser = configparser.RawConfigParser()
configParser.read_string(configString)
# Load needed credentials
HA_IP = configParser.get('Settings', 'HA_IP')
HA_TOKEN = configParser.get('Settings', 'HA_TOKEN')
# Set power state of the Eurorack.
def setEurorackPower(state):
ha.setOnOff('switch.eurorack_lower', state)
ha.setOnOff('switch.eurorack_top', state)
# Set power state of the Behringer DeepMind 12.
def setDeepMind12Power(state):
ha.setOnOff('switch.deepmind_12', state)
# Set power state of the ASM Hydrasynth.
def setHydrasynthPower(state):
ha.setOnOff('switch.hydrasynth', state)
# Set power state of the Arturia MatrixBrute.
def setMatrixBrutePower(state):
ha.setOnOff('switch.matrixbrute', state)
# Set power state of all synthesizers.
def setSynthsPower(state):
setEurorackPower(state)
setDeepMind12Power(state)
setHydrasynthPower(state)
setMatrixBrutePower(state)
parser = argparse.ArgumentParser(
description='Control power state of synthesizers.')
parser.add_argument('-d', '--daw', action='store_true',
help='enable DAW mode',
dest='daw', default=False, required=False)
parser.add_argument('-o', '--off', action='store_true',
help='turn all synths off',
dest='off', default=False, required=False)
args = parser.parse_args()
ha = HomeAssistant(HA_IP, HA_TOKEN)
if args.daw:
setSynthsPower(True)
elif args.off:
setSynthsPower(False)

View File

@@ -0,0 +1,9 @@
#! /bin/bash
# Create backup directory
mkdir -p ./converted
# Convert files
for file in *.mp4 *.MP4 *.mov *.MOV; do
ffmpeg -i $file -acodec pcm_s16le -vcodec copy ./converted/${file%%.*}.mov
done

View File

@@ -0,0 +1,13 @@
#!/bin/bash
# Stop all polybar instances
killall -q polybar
while pgrep -x polybar >/dev/null; do sleep 0.1; done
for monitor in $(xrandr -q | grep -e "\sconnected\s" | cut -d' ' -f1); do
if [ $monitor == 'DP-2' ] || [ $monitor == 'LVDS-1' ]; then
MONITOR=$monitor polybar aqua &
fi
done

View File

@@ -0,0 +1,7 @@
#!/bin/bash
# Stop all waybar instances
killall -q waybar
while pgrep -x waybar >/dev/null; do sleep 0.1; done
waybar &

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env python3
import i3ipc, os
def onWindowClose(conn, win):
if(win.ipc_data['container']['window_properties']['class'] == 'Bitwig Studio'):
print(win.ipc_data['container']['window_properties']['title'])
if(win.ipc_data['container']['window_properties']['title'] !=
'DSP Performance Graph'):
os.system('sh ~/.config/scripts/audio/aquamix.sh -n')
os.system('sh ~/.config/scripts/audio/synth-power-prompt.sh')
i3 = i3ipc.Connection()
i3.on('window::close', onWindowClose)
i3.main()

View File

@@ -0,0 +1,929 @@
#!/usr/bin/env bash
# This is a bash script to enable interacting with LLMs via the command line.
#===============================================================================
## Modes
### Default mode
# Default mode uses the default prompt and model for AquaAI. It's nothing
# special.
### Bash mode
# This mode will help with writing bash scripts.
### CLI mode
# CLI mode prompts the AI with system information and will return terminal
# commands. If you wish to run the command simply type run and it will end the
# chat and run the command. You are responsible for validating what the command
# does before running.
### Code Review mode
# This will ask you what changes to look at and will provide a code review of
# the changes. This mode only works if you are currently in a git repo. It can
# look at the past few commits as well as changes that have yet to be committed.
### Reasoning mode
# This uses the best available reasoning model with the default prompt.
# Reasoning models take a task and break them up to subtask to pass to
# specialized models. They are very yappy and take a while to run. Can be good
# for complex tasks.
### Regex mode
# This mode will respond only with regex.
### Git mode
# This mode will respond only with git commands. If you wish to run the command
# simply type run and it will end the chat and run the command. You are
# responsible for validating what the command does before running.
## Special Input
### Edit
# You can type `edit` or `e` as a response and it will open your editor set with
# the EDITOR variable in your shell session. You can then type your query and
# save and exit. From there the program will send your query to the AI.
### Exit
# You can type `exit` or `q` to end the chat. Personally, I never do this just
# use C-c.
### Run
# If you are in cli mode you can type `run` or `r` and the script will run the
# given commands on your system. You are playing with fire with this, but fire
# is useful and fun just be careful.
### Save
# You can type `save` or `s` as a response and the chat history will be saved
# for use at another time. This will also end the chat. Chats are stored in
# `~/.local/share/aquaai`
## Adding custom modes
# There are two variables that need to be set to create a custom mode.
### $selected_model will set the model to be used for the chat.
### $system_prompt will be the prompt that controls how the AI behaves.
# introduce more noise into text generation leading to more out there responses.
#
# Defaults are set for all these but to define a custom mode you should override
# at least one of these in a function. Add a custom flag in the switch statement
# at the bottom of this file and call the function there. See `--bash` as an
# example of how to do this. From there add some documentation to the
# print_help() function and then here.
#===============================================================================
# User configurable variables.
#
# The following are settings that can be overwritten by environment variables.
# You can set these in your .bashrc to have them set each time you open a new
# shell. This script is designed not to be modified so updates can be applied by
# replacing the file with the newest version.
#
#
# Set the url of the ollama server.
#
# export AQUAAI_OLLAMA_URL='192.168.1.156:11434'
#
ollama_url=${AQUAAI_OLLAMA_URL:='https://ai.aquamorph.com/api'}
#
# Set the default model.
#
# export AQUAAI_DEFAULT_MODEL='qwen2.5-7b-instruct'
#
default_model=${AQUAAI_DEFAULT_MODEL:='qwen2.5:32b-instruct'}
#
# Set the default coding model.
#
# export AQUAAI_CODING_MODEL='qwen2.5-7b-coder'
#
coding_model=${AQUAAI_CODING_MODEL:='qwen2.5-32b-coder'}
#
# In multiline mode, users can input multiple lines of text by pressing the
# Enter key. The message will be sent when the user presses C-d on the keyboard.
#
# export AQUAAI_MULTILINE_MODE=true
#
multiline_mode=${AQUAAI_MULTILINE_MODE:=false}
#
# Enable rich formatting for text output. A formatting program is required for
# this see below.
#
# export AQUAAI_RICH_FORMAT_MODE=true
#
rich_format_mode=${AQUAAI_RICH_FORMAT_MODE:=false}
#
# Path to the program used for rich formatting. I am currently using streamdown
# but you are free to use something different as long as it supports streaming
# text and markdown. Go to the GitHub repo to learn to install streamdown and
# configure: https://github.com/day50-dev/Streamdown
#
# export AQUAAI_RICH_FORMAT_PATH=~/.venv/bin/streamdown
#
rich_format_path=${AQUAAI_RICH_FORMAT_PATH:=streamdown}
#
# Ignore certificate checks.
#
# export AQUAAI_INSECURE_MODE=true
#
insecure_mode=${AQUAAI_INSECURE_MODE:=false}
#
# Use OpenAI api design instead of Ollama.
#
# export AQUAAI_OPENAI_API:=true
#
openai_api=${AQUAAI_OPENAI_API:=true}
#
# Set key used to authenticate with the API.
#
# export AQUAAI_KEY:=true
#
key=${AQUAAI_KEY:=''}
#===============================================================================
# Constants.
OLLAMA_URL=${ollama_url}
CURL_FLAGS=('-sN')
USER=$(whoami)
DATA_DIR="${HOME}/.local/share/aquaai"
RESPONSE_FIFO="${DATA_DIR}/.response"
AGENT_NAME='AquaAI'
# Colors.
CLEAR='\033[0m'
BLUE='\033[0;34m'
RED='\e[1;31m'
LIGHT_GRAY='\e[38;5;247m'
# Globals.
message_history="[]"
cli_mode=false
git_mode=false
code_review_start=false
selected_model=${default_model}
# Error Codes.
ERROR_NO_SAVEFILE=1
ERROR_INVALID_TEMP=2
ERROR_UNKNOWN_OPTION=3
ERROR_UNKNOWN_MODEL=4
ERROR_NO_GIT_REPO=5
ERROR_INVALID_INPUT=6
ERROR_NO_AUTOSAVE=7
ERROR_INVALID_SSL=8
ERROR_UNKNOWN_SSL=9
#===============================================================================
# Give the AI a name. It improves prompting to call it by name.
function name_agent() {
system_prompt="You are an AI assistant named ${AGENT_NAME}."
}
# Make the AI write and behave better.
function set_better_conversions() {
system_prompt+=' Be as concise as possible.'
system_prompt+=' Be extremely accurate.'
system_prompt+=' Recommend things I would not realize I would benefit from.'
system_prompt+=' Call out my misconceptions and tell me when I am wrong.'
system_prompt+=" For personal matters ${AGENT_NAME} is encouraging"
system_prompt+=' but brutally honest.'
system_prompt+=' Never sycophantic.'
system_prompt+=' Do not use em dashes. If an em dash would normally appear,'
system_prompt+=' use a comma for continuing thoughts or a period if it'
system_prompt+=' should be a separate sentence.'
}
# Set the formatting for all reponses.
function set_response_format() {
system_prompt+=' Do not wrap response in quotation marks or apostrophes.'
system_prompt+=' Do not use html to format response.'
}
# Limit format of output to just commands.
function format_for_cli() {
system_prompt+=" ${AGENT_NAME} does not put commands in quotation marks."
system_prompt+=" ${AGENT_NAME} does not put commands in markdown."
system_prompt+=" ${AGENT_NAME} only outputs terminal commands."
}
# Default prompt.
function set_default_agent() {
name_agent
system_prompt+=" ${AGENT_NAME} follows the users instructions carefully."
system_prompt+=" ${AGENT_NAME} responds using extended markdown."
set_better_conversions
set_response_format
}
# Set chat to help with command line questions.
function set_cli_agent() {
local os_version=$(cat /etc/os-release | grep 'PRETTY_NAME' | \
sed 's/PRETTY_NAME=//g' | tr -d '"')
name_agent
system_prompt+=" ${AGENT_NAME} assists users with ${os_version}."
format_for_cli
set_response_format
}
# Set chat to help with bash questions.
function set_bash_agent() {
name_agent
system_prompt+=" ${AGENT_NAME} assists users with POSIXs bash."
system_prompt+=' Format output for view in a command line.'
system_prompt+=' Do not put commands in quotation marks.'
system_prompt+=' Use double spaces and the function keyword.'
system_prompt+=' Write documentation before the function declaration.'
set_response_format
}
# Set ai to help with code reviews.
function set_code_review_agent() {
name_agent
system_prompt+=" ${AGENT_NAME} is a senior software engineer performing a"
system_prompt+=' code review for a colleague.'
system_prompt+=''
set_better_conversions
system_prompt+=' Show code snipets when helpful.'
system_prompt+="${AGENT_NAME}'s reports should have the following format:"
system_prompt+='# Typos'
system_prompt+='List of all typos you find.'
system_prompt+='# Formatting and Readability Issues'
system_prompt+='List of all formatting and readability issues you find.'
system_prompt+='# Security Issues'
system_prompt+='List of all security issues you find.'
system_prompt+='# Other'
system_prompt+='List of all other issues you find.'
set_response_format
}
# Set chat to help with git.
function set_git_agent() {
name_agent
system_prompt+=" ${AGENT_NAME} assists users with git."
format_for_cli
if is_git_repo; then
system_prompt+="\n\nHere is some information about the current git repo.\n"
local current_branch=$(git branch --show-current)
system_prompt+="Current branch: ${current_branch} \n"
local git_remotes=$(git remote -v)
system_prompt+="Remotes: ${git_remotes}\n"
fi
}
# Set chat to help with regex.
function set_regex_agent() {
name_agent
system_prompt+=" ${AGENT_NAME} assists users with regex."
system_prompt+=' Only output a single regex expression.'
system_prompt+=' Use BRE and ERE regex.'
format_for_cli
}
# Set chat to help with Home Assistant.
function set_home_assistant_agent() {
name_agent
system_prompt+=" ${AGENT_NAME} assists users with Home Assistant programming."
system_prompt+=" Templating is done with Jinja2."
}
#===============================================================================
# Get the first available model from a given list.
function get_model_from_list() {
local models=("$@")
for m in "${models[@]}"; do
check_if_model_exists $m true
if [ $? -eq 0 ]; then
echo "${m}"
return
fi
done
print_error "could not find any models on the list."
exit $ERROR_UNKNOWN_MODEL
}
function load_model_from_list() {
local models=("$@")
selected_model=$(get_model_from_list "${models[@]}")
if [[ $? -ne 0 ]]; then
print_error "could not find any models on the list."
exit $ERROR_UNKNOWN_MODEL
fi
}
# Set the default coding model.
function set_coding_model() {
local models=(${coding_model}
'qwen2.5-32b-coder'
'qwen2.5-7b-coder'
'llama3.3-70b-instruct'
'hf.co/Qwen/Qwen2.5-Coder-3B-Instruct-GGUF:Q4_K_M'
'hf.co/bartowski/Qwen2.5-Coder-1.5B-Instruct-GGUF:Q4_K_M'
'qwen2.5-coder:3b'
'qwen2.5-coder:0.5b'
)
load_model_from_list "${models[@]}"
}
# Set the default reasoning model.
function set_reasoning_model() {
local models=(${reasing_model}
'qwen3-32b'
'gpt-oss-120b'
)
load_model_from_list "${models[@]}"
}
#===============================================================================
# Print out help menu.
function print_help() {
echo 'Interact with the AquaAI via the command line.'
echo ''
echo '--delete - delete a chat from history'
echo '-l --list - list available models'
echo '--load - load a chat from history'
echo '--restore - load last auto saved chat'
echo ''
echo '--bash - help with bash'
echo '--cli - help with command line'
echo '--code-review - code review of a git project'
echo '-r --reason - help with a reasoning model'
echo '--regex - help with regex'
echo '--git - help with git'
}
# Print out error message.
function print_error() {
local msg=${1}
printf "${RED}ERROR: ${msg}\n${CLEAR}"
}
# Check if a given program is installed on the system.
function check_program() {
if ! command -v ${1} 2>&1 >/dev/null; then
print_error "${1} not found. Please install ${1}."
exit ${ERROR_DEPENDENCY}
fi
}
# Check system for required programs.
function check_requirements() {
check_program curl
check_program jq
check_program fzf
if [ "${rich_format_mode}" == true ]; then
check_program ${rich_format_path}
fi
}
# Get available models info.
function get_models() {
local model_path=''
if [ "${openai_api}" == true ]; then
model_path='/models'
else
model_path='/tags'
fi
curl "${CURL_FLAGS[@]}" "${OLLAMA_URL}${model_path}"
}
# Get a list of available models.
function get_models_list() {
local jq_filter=''
if [ "${openai_api}" == true ]; then
jq_filter='.data[].id'
else
jq_filter='.models[].model'
fi
get_models | jq -r ${jq_filter}
}
# Print list of models.
function print_models() {
get_models_list | column -t -s $'\t'
}
# Print message variable.
function print_message_history() {
echo ${message_history}
}
# Print message variable.
function print_debug() {
echo "Model: ${selected_model}"
echo 'System Prompt:'
print_system_prompt
echo 'Chat History:'
print_message_history | jq
}
# Print the system prompt.
function print_system_prompt() {
echo -e "${system_prompt}"
}
# Check if the model exists.
function check_if_model_exists() {
local model=${1}
local enable_rc=${2}
local model_list=($(get_models_list))
for m in "${model_list[@]}"; do
if [[ "$m" == "$model" ]]; then
return 0
fi
done
if [ ${enable_rc} ]; then
return 1
else
print_error "model ${model} does not exists."
exit $ERROR_UNKNOWN_MODEL
fi
}
# Convert string to a safe format for later use.
function convert_to_safe_text() {
echo "${1}" | jq -sR @json
}
# Set the text output color for user input.
function set_user_color() {
printf "${LIGHT_GRAY}"
}
# Set the text output color for ai response.
function set_ai_color() {
printf "${CLEAR}"
}
# Set text color to defaults.
function set_clear_color() {
printf "${CLEAR}"
}
# Print the header for the ai message
function print_ai_start_message() {
echo -e "\U1F916 AquaAI"
}
# Print the header for the ai message
function print_user_start_message() {
echo -e "\U1F464 ${USER}"
}
# Opens the user's preferred text editor to allow them to input text.
function editor_input() {
local editor=${EDITOR:=nano}
local temp_file=$(mktemp)
${editor} ${temp_file}
local user_input=$(<"$temp_file")
rm "$temp_file"
msg=${user_input}
}
# Check if current directory is managed by git.
function is_git_repo() {
git rev-parse --is-inside-work-tree &> /dev/null
}
# Check if current directory is managed by git.
function check_git_directory() {
if ! git rev-parse --is-inside-work-tree &> /dev/null; then
print_error 'The current directory is not inside a git repository.'
exit ${ERROR_NO_GIT_REPO}
fi
}
# Asks the user if they want to include staged git change data.
function gather_staged_changes() {
echo -n 'Do you want to include staged changes? (y/n)? '
read response
if [[ "$response" == 'y' || "$response" == 'yes' ]]; then
msg+=$(git diff --cached --patch)
fi
}
# Ask the user if they want to include changes that have not been committed.
function gather_uncommitted_changes() {
echo -n 'Do you want to include the changes'
echo -n ' you have yet to commit or stash (y/n)? '
read response
if [[ "$response" == 'y' || "$response" == 'yes' ]]; then
changes=$(git diff)
msg+=${changes}
fi
}
# Ask the user for number of commit changes to include in code review.
# Returns a list of changes for the given number of commits.
function gather_commit_changes() {
echo -n 'How many previous commits do you want to include? '
local count
read count
# Allow hitting enter as a no response.
if [ -z "$count" ]; then
return
fi
# Validate that the input is a positive integer.
if ! [[ "$count" =~ ^[0-9]+$ ]] || [ "$count" -lt 0 ]; then
print_error 'Please enter a positive integer for the number of commits.'
exit ${ERROR_INVALID_INPUT}
fi
hashes=$(git log --format=%H -n ${count})
for h in ${hashes}; do
commit_message=$(git show ${h})
msg+="${commit_message}"$'\n'
done
}
# Create fifo for chat responses.
function create_response_fifo() {
create_data_dir
if [ ! -p ${RESPONSE_FIFO} ]; then
mkfifo ${RESPONSE_FIFO}
fi
}
# Delete fifo for chat responses.
function remove_response_fifo() {
if [ -p ${RESPONSE_FIFO} ]; then
rm ${RESPONSE_FIFO}
fi
}
# Create response trap to allow user to stop AquaAI.
function create_response_trap() {
trap 'echo "AquaAI has been interrupted...";' SIGINT
}
# Remove response trap to allow user to exit program.
function remove_response_trap() {
trap - SIGINT
}
# Get the first message from a saved chat.
function get_first_chat() {
local file_path=${1}
source <(cat ${file_path} | grep message_history)
message_history=$(echo $message_history | \
jq -r '[.[] | select(.role == "user")][0].content' \
2>/dev/null | sed 's/^"//')
echo -e $message_history | sed 's/"$//' | tr -d '\n' | cut -c 1-80 \
| sed ':a;N;$!ba;s/\n//g'
}
# Get an array of all saved chat files.
function get_save_files() {
save_files=()
create_data_dir
for f in $(find "$DATA_DIR" -type f -name "*.chat"); do
save_files+=("${f}")
done
}
# Create the data directory if it does not exist.
function create_data_dir() {
if [ ! -d "$DATA_DIR" ]; then
mkdir -p "$DATA_DIR"
fi
}
# Save the current chat to a file.
function save_chat() {
create_data_dir
local filename=${1}
if [ -z "$filename" ]; then
print_error 'No filename provided.'
exit ${ERROR_NO_SAVEFILE}
fi
declare -p selected_model system_prompt \
message_history cli_mode > "${DATA_DIR}/${filename}"
}
# Save the current chat to autosave.
function autosave() {
save_chat 'autosave.chat'
echo 'Chat has been auto saved'
}
# Find all .chat files in DATA_DIR and use fzf to select one.
function select_chat_file() {
selected_file=$(select_chat_with_fzf)
if [ -z "$selected_file" ]; then
echo 'No file selected.'
exit ${ERROR_NO_SAVEFILE}
fi
}
# Delete .chat files in DATA_DIR.
function delete_chat_file() {
selected_file=$(select_chat_with_fzf)
if [ -z "$selected_file" ]; then
echo 'No file selected.'
exit ${ERROR_NO_SAVEFILE}
else
local pretty_name=$(get_first_chat ${selected_file})
echo -n "do you want to delete '${pretty_name}' (y/n)? "
read response
if [[ "$response" == 'y' || "$response" == 'yes' ]]; then
rm -- "${selected_file}"
echo "Deleted '${pretty_name}'"
fi
fi
}
# Select saved chat with fzf program.
function select_chat_with_fzf() {
get_friendly_save_names
local selected_index=$(printf "%s\n" "${friendly_save_files[@]}" \
| cat -n | fzf --with-nth 2.. \
| awk '{print $1}')
selected_index=$((${selected_index}-1))
if [[ -n $selected_index ]]; then
echo "${save_files[selected_index]}"
fi
}
# Get an array of the first message in saved chats.
function get_friendly_save_names() {
get_save_files
friendly_save_files=()
for f in "${save_files[@]}"; do
friendly_save_files+=("$(get_first_chat ${f})")
done
}
# Validate site certificate.
function check_cert() {
curl "${CURL_FLAGS[@]}" ${OLLAMA_URL} 2>&1 >/dev/null
local ec=$?
if [ "${ec}" == '60' ]; then
print_error 'unable to get local issuer certificate.'
echo 'Install the certificate on the system.'
exit ${ERROR_INVALID_SSL}
elif [ "${ec}" != '0' ]; then
print_error 'unknown ssl error.'
exit ${ERROR_UNKNOWN_SSL}
fi
}
# Update chat history
function update_history() {
local role="$1"
local content="$2"
message_history=$(echo "$message_history" \
| jq --arg role "$role" --arg content \
"$content" '. + [{"role": $role, "content": $content}]')
}
# Read input from the user.
function read_user_input() {
if [ "${multiline_mode}" == true ]; then
msg=$(awk '{if ($0 == "END") exit; else print}')
elif [ "${code_review_start}" == true ]; then
check_git_directory
msg=''
gather_uncommitted_changes
gather_staged_changes
gather_commit_changes
code_review_start=false
else
read msg
fi
}
# Handle input related to CLI mode.
function handle_cli_mode() {
# Check for cli mode
if [ ${cli_mode} == true ]; then
if [[ -z $msg || $msg == 'run' || $msg == 'r' ]]; then
set_clear_color
autosave
echo
local commands=()
# Get a list of commands
while IFS= read -r line; do
commands+=("${line}")
done <<< "$last_cmd"
for c in "${commands[@]}"; do
# Using eval to handle commands that include pipes.
if [[ "${c}" == *'|'* ]]; then
eval "${c}"
else
${c}
fi
done
exit 0
fi
fi
}
# Check for editor request.
function handle_edit() {
if [[ $msg == 'edit' || $msg == 'e' ]]; then
editor_input
set_user_color
echo "${msg}"
fi
}
# Check for debug command.
function handle_debug() {
if [[ $msg == 'debug' ]]; then
print_debug
return 1
fi
return 0
}
# Check for save command.
function handle_save() {
if [[ $msg == 'save' || $msg == 's' ]]; then
echo "Saving chat history"
save_chat "$(date +%Y%m%d%H%M%S).chat"
exit 0
fi
}
# Chat converstation loop.
function chat_loop() {
check_if_model_exists ${selected_model}
update_history 'system' "$system_prompt"
while true; do
chat
done
}
# Main chat loop.
function chat() {
# Get user input.
set_user_color
print_user_start_message
read_user_input
echo
# Handle user input.
local rc=0
handle_edit
handle_cli_mode
handle_debug
rc=$((rc + $?))
handle_save
rc=$((rc + $?))
if [ "$rc" -ne 0 ]; then
return
fi
update_history 'user' "${msg}"
# Prepare JSON payload.
JSON_PAYLOAD=$(jq -n \
--arg model "$selected_model" \
--argjson messages "$message_history" \
'{model: $model, messages: $messages, stream: true}')
set_ai_color
print_ai_start_message
create_response_fifo
create_response_trap
# Render to console.
if [ "${rich_format_mode}" == true ]; then
cat ${RESPONSE_FIFO} | ${rich_format_path} &
else
cat ${RESPONSE_FIFO} &
fi
local flags=("${CURL_FLAGS[@]}")
local chat_path=''
local filter=''
if [ "${openai_api}" == true ]; then
flags+=(-H "Content-Type: application/json")
chat_path='/chat/completions'
filter='.choices[].delta.content // empty'
else
chat_path='/api/chat'
filter='.message.content // empty'
fi
local response=$(curl "${flags[@]}" "${OLLAMA_URL}${chat_path}" \
-d "${JSON_PAYLOAD}" | stdbuf -o0 sed 's/^data: //' \
| stdbuf -o0 jq -j "${filter}" 2>/dev/null \
| tee ${RESPONSE_FIFO})
wait
# Newline for AI response.
if [ "${rich_format_mode}" != true ]; then
echo
fi
# One line reponses do not print out when formatted with Streamdown.
if [[ "$rich_format_path" == *"streamdown"* && \
"${rich_format_mode}" == true ]]; then
local wc=$(echo "${response}" | wc -l)
if [ ${wc} -eq 1 ]; then
echo "${response}"
fi
fi
remove_response_trap
remove_response_fifo
echo
update_history "assistant" "${response}"
last_cmd="${response}"
}
#===============================================================================
check_requirements
if [ "${insecure_mode}" == true ]; then
CURL_FLAGS+=('-k')
else
check_cert
fi
if [ "${openai_api}" == true ]; then
CURL_FLAGS+=(-H "Authorization: Bearer ${key}")
fi
cmd=chat_loop
set_default_agent
# Check arguments
for i in "$@"; do
case $i in
-h|--help)
cmd=print_help
;;
-l|--list)
cmd=print_models
;;
--delete)
delete_chat_file
exit 0
;;
--load)
select_chat_file
source ${selected_file}
cmd=chat_loop
;;
--restore)
if [ ! -e "${DATA_DIR}/autosave.chat" ]; then
print_error 'auto save does not exit'
exit ${ERROR_NO_AUTOSAVE}
fi
source "${DATA_DIR}/autosave.chat"
cmd=chat_loop
;;
# Modes
--bash)
set_coding_model
set_bash_agent
cmd=chat_loop
;;
--cli)
set_coding_model
set_cli_agent
cmd=chat_loop
cli_mode=true
rich_format_mode=false
;;
--code-review)
set_coding_model
set_code_review_agent
code_review_start=true
cmd=chat_loop
;;
--git)
set_coding_model
set_git_agent
cmd=chat_loop
cli_mode=true
rich_format_mode=false
;;
-r|--reason)
set_reasoning_model
cmd=chat_loop
;;
--regex)
set_coding_model
set_regex_agent
cmd=chat_loop
rich_format_mode=false
;;
-ha|--home-assistant)
set_coding_model
set_home_assistant_agent
cmd=chat_loop
rich_format_mode=false
;;
# Other
-*|--*)
echo "Unknown option ${i}"
print_help
exit ERROR_UNKNOWN_OPTION
;;
esac
done
${cmd}

View File

@@ -0,0 +1,10 @@
#! /bin/bash
# Load user settings from config file.
. ~/.config/settings.conf
if nc -z $nasip 80 2>/dev/null; then
mount /mnt/share/lNAS
else
echo "$nasip is unreachable"
fi

View File

@@ -0,0 +1,11 @@
#! /bin/bash
mouseState=$(upower -i /org/freedesktop/UPower/devices/battery_hidpp_battery_0)
batteryPercentage=$(echo $mouseState | grep percentage | grep -Po '\d+%')
charging=$(echo $mouseState | grep 'state: charging')
if [ ! -z "$charging" ]; then
echo Charging
else
echo $batteryPercentage
fi

View File

@@ -0,0 +1,8 @@
#! /bin/bash
if [[ $* == *-b* ]]; then
cp /etc/hosts ~/.config/.dotfiles/hosts
else
sudo cp ~/.config/.dotfiles/hosts /etc/hosts
fi

View File

@@ -0,0 +1,12 @@
#! /bin/bash
# Load user settings from config file.
. ~/.config/settings.conf
cat ~/.config/i3/shared.conf ~/.config/i3/${computer}.conf > ~/.config/i3/config
if command -v i3-msg &> /dev/null; then
i3-msg reload
elif command -v swaymsg &> /dev/null; then
swaymsg reload
fi

View File

@@ -0,0 +1,8 @@
#! /bin/bash
# A script to make creating i3wm window actions easier.
info=$(xprop)
title=$(echo "$info" | grep "WM_NAME(STRING)" | cut -d "\"" -f2 | cut -d "\"" -f1)
class=$(echo "$info" | grep "WM_CLASS(STRING)" | cut -d "\"" -f2 | cut -d "\"" -f1)
echo for_window [class=\"$class\" title=\"$title\"]

View File

@@ -0,0 +1,33 @@
#!/bin/bash
# i3lock blurred screen inspired by /u/patopop007 and the blog post
# http://plankenau.com/blog/post-10/gaussianlock
# Timings are on an Intel i7-2630QM @ 2.00GHz
# Dependencies:
# imagemagick
# i3lock
# scrot (optional but default)
IMAGE=/tmp/i3lock.png
SCREENSHOT="scrot $IMAGE" # 0.46s
# Alternate screenshot method with imagemagick. NOTE: it is much slower
# SCREENSHOT="import -window root $IMAGE" # 1.35s
# Here are some imagemagick blur types
# Uncomment one to use, if you have multiple, the last one will be used
# All options are here: http://www.imagemagick.org/Usage/blur/#blur_args
BLURTYPE="0x5" # 7.52s
#BLURTYPE="0x2" # 4.39s
#BLURTYPE="5x2" # 3.80s
#BLURTYPE="2x8" # 2.90s
#BLURTYPE="2x3" # 2.92s
# Get the screenshot, add the blur and lock the screen with it
$SCREENSHOT
convert $IMAGE -blur $BLURTYPE $IMAGE
i3lock -i $IMAGE
rm $IMAGE

View File

@@ -0,0 +1,17 @@
#! /bin/bash
# Script to toggle graphical
defTarget=$(systemctl get-default)
if [[ $defTarget == 'graphical.target' ]]
then
echo 'Changing default target to nongraphical shell'
sudo systemctl set-default multi-user.target
else
echo 'Changing default target to graphical shell'
sudo systemctl set-default graphical.target
fi
echo
echo 'Default target changed to '$(systemctl get-default)
echo 'Please reboot for the change to take effect'

View File

@@ -0,0 +1,33 @@
#!/bin/bash
# Get device id of Synaptics TrackPad
id=$(xinput list --id-only 'SynPS/2 Synaptics TouchPad')
# Enables TrackPad
trackpadEnable() {
xinput set-prop $id "Device Enabled" 1
exit
}
# Disables TrackPad
trackpadDisable() {
xinput set-prop $id "Device Enabled" 0
exit
}
# Checks for disable flag
if [ ! -z $1 ] && [ $1 == '-d' ]; then
echo flag worked
trackpadDisable
fi
# Convert to an arry
read -a trackPadState <<< "$(xinput --list-props $id | grep "Device Enabled")"
devEnabled=${devString_array[3]}
# Flip the state of the TrackPad
if [ ${trackPadState[3]} -eq 1 ]; then
trackpadDisable
else
trackpadEnable
fi

View File

@@ -0,0 +1,66 @@
#! /bin/bash
# This script is a catch all program updater.
# DNF Updater
function dnfUpdate {
if command -v dnf &> /dev/null; then
echo Updating DNF...
sudo dnf update #--exclude=wine*
fi
}
# Apt Updater
function aptUpdate {
if command -v apt &> /dev/null; then
echo Updating APT...
sudo apt update
sudo apt upgrade
fi
}
# Flatpack Updater
function flatpakUpdate {
if command -v flatpak &> /dev/null; then
echo Updating Flatpak...
flatpak uninstall --unused
flatpak update
fi
}
# Appimage Updater
function appimageUpdate {
am update
}
# Checks if a program is installed and if it is runs an updater script
function updateProgram {
if command -v $1 &> /dev/null; then
sh $2
fi
}
# Manually installed programs updater
function manualUpdate {
if command -v dnf &> /dev/null; then
echo Updating manually installed programs...
SCRIPT_PATH="$HOME/bin/installers"
updateProgram bitwig-studio $SCRIPT_PATH/bitwig-install.sh &
updateProgram /opt/dragonframe5/bin/Dragonframe $SCRIPT_PATH/dragonframe-install.sh &
updateProgram reaper $SCRIPT_PATH/reaper-install.sh &
updateProgram /opt/resolve/bin/resolve $SCRIPT_PATH/resolve-install.sh &
updateProgram /opt/keeweb/keeweb $SCRIPT_PATH/keeweb-install.sh &
updateProgram yabridgectl $SCRIPT_PATH/yabridge-install.sh &
wait
fi
}
dnfUpdate
aptUpdate
echo ''
flatpakUpdate
echo ''
appimageUpdate
echo ''
manualUpdate

View File

@@ -0,0 +1,173 @@
#!/usr/bin/env python3
# Program to create a photo checklist of a given frc event.
import configparser
import datetime as dt
import re
import operator
import os
import sys
import tbapy
import todoist
# getProjectID() returns the project id that matches the name given.
def getProjectID(api, name):
for project in api.state['projects']:
if project['name'] == name:
return project['id']
print('Error: No project with the name {} found'.format(name))
exit(1)
# getChecklistName()
def getChecklistName(evemt):
return '{} Photos'.format(event['name'])
# getEventListID() returns the id of the checklist for the event and if there is none
# returns -1.
def getEventListID(items, event):
for item in items:
if item['content'] == getChecklistName(event):
return item['id']
return -1
# matchToTeamList() converts a match to two lists of teams
def matchToTeamList(match):
return match['alliances']['red']['team_keys'], match['alliances']['blue']['team_keys']
# createChecklistItem() creates a checklist item of the highest priority.
def createChecklistItem(name, api, projectID, item, date):
return api.items.add(name,
project_id=projectID,
parent_id=item['id'],
date_string=date,
priority=4)
# createPhotoChecklistItem() creates a checklist item that requires a photo.
def createPhotoChecklistItem(name, api, projectID, item, date):
return createChecklistItem('Take photo of **{}**'.format(name),
api, projectID, item, date)
# createPitList() creates a checklist for taking photos of a teams pit.
def createPitList(api, teams, projectID, checklist, date):
item = api.items.add('**Take** Pit Photos',
project_id=projectID,
parent_id=checklist['id'],
date_string=date,
priority=3)
for team in teams:
createChecklistItem('Pit photo of **{}** {}'.format(team['team_number'], team['nickname']),
api, projectID, item, date)
# createGroupsList() creates a checklist of the different groups of volenteers.
def createGroupsList(api, projectID, checklist, date):
item = api.items.add('Groups',
project_id=projectID,
parent_id=checklist['id'],
date_string=date,
priority=3)
groups = ['Judges', 'Robot Inspectors', 'Referees', 'Safety Inspectors',
'Field Reset', 'Queuers', 'CSAs', 'VC and Pit Admin']
for group in groups:
createPhotoChecklistItem(group, api, projectID, item, date)
# createWinnersList() creates a checklist of the winners of an event.
def createWinnersList(api, projectID, checklist, date):
item = api.items.add('Winners',
project_id=projectID,
parent_id=checklist['id'],
date_string=date,
priority=3)
groups = ['Chairman\'s award', 'Engineering Inspiration', 'Rookie All-Star', 'Winning Alliance',
'Winning Team 1', 'Winning Team 2', 'Winning Team 3']
for group in groups:
createPhotoChecklistItem(group, api, projectID, item, date)
# createRobotList() creates a checklist for taking photos of a team's robot.
def createRobotList(api, teams, projectID, checklist, date):
item = api.items.add('**Take** Robot Photos',
project_id=projectID,
parent_id=checklist['id'],
date_string=date,
priority=3)
for team in teams:
createChecklistItem('Robot photo of **{}** {}'.format(team['team_number'], team['nickname']),
api, projectID, item, date)
# Parse settings config
configString = '[Settings]\n' + open('../settings.conf').read()
configParser = configparser.RawConfigParser()
configParser.read_string(configString)
# Load needed credentials
tbaKey = configParser.get('Settings', 'TBAKey')
todoistToken = configParser.get('Settings', 'TodoistToken')
# Setup Todoist
api = todoist.TodoistAPI(todoistToken)
api.sync()
projectID = getProjectID(api, '🤖 Robotics')
items = api.state['items']
# Setup the Blue Alliance
tba = tbapy.TBA(tbaKey)
eventKey = sys.argv[1]
event = tba.event(eventKey)
setupDay = event['start_date']
day1 = (dt.datetime.strptime(setupDay, '%Y-%m-%d') + dt.timedelta(days=1)).strftime('%Y-%m-%d')
day2 = event['end_date']
teams = sorted(tba.event_teams(eventKey), key=operator.attrgetter('team_number'))
def firstMatch(team, matches):
for match in matches:
red, blue = matchToTeamList(match)
if team in red:
return match, 'red'
elif team in blue:
return match, 'blue'
return None, None
# Check if list already exists
eventListID = getEventListID(items, event)
if eventListID == -1:
# Create checklist
checklist = api.items.add(getChecklistName(event),
project_id=projectID,
date_string=day2,
priority=2)
# Setup
createPitList(api, teams, projectID, checklist, setupDay)
createChecklistItem('**Schedule** Judges photo', api, projectID, checklist, setupDay)
createChecklistItem('**Schedule** Inspectors photo', api, projectID, checklist, setupDay)
createChecklistItem('**Schedule** Seniors photo', api, projectID, checklist, setupDay)
createGroupsList(api, projectID, checklist, setupDay)
# Day 1
createPhotoChecklistItem('Guest Speakers', api, projectID, checklist, day1)
createRobotList(api, teams, projectID, checklist, day1)
# Day 2
createPhotoChecklistItem('Guest Speakers', api, projectID, checklist, day2)
createPhotoChecklistItem('Mentors after parade', api, projectID, checklist, day2)
createPhotoChecklistItem('Seniors', api, projectID, checklist, day2)
createPhotoChecklistItem('Alliances Representatives', api, projectID, checklist, day2)
createWinnersList(api, projectID, checklist, day2)
createChecklistItem('**Email** guest speakers and winners photos', api, projectID, checklist, day2)
else:
print('List already created')
matches = sorted(tba.event_matches(eventKey), key=operator.attrgetter('time'))
if not matches:
print('No match schedule yet')
else:
photoParentID = [item['id'] for item in items if 'parent_id' in item
and item['parent_id'] == eventListID
and 'Robot Photos' in item['content']][0]
robotPhotoList = [item for item in items if 'Robot photo of' in item['content']
and item['parent_id'] == photoParentID]
for robot in robotPhotoList:
if 'match' not in robot['content']:
team = 'frc{}'.format(re.findall(r'\d+', robot['content'])[0])
match, side = firstMatch(team, matches)
if match != None:
matchNumber = match['match_number']
matchTime = dt.datetime.fromtimestamp(match['time']).strftime('%Y-%m-%d %I:%M %p')
robot.update(date_string=matchTime, content='{} match {} {}'.format(robot['content'], matchNumber, side))
api.commit()

142
home/bin/homeassistant.py Normal file
View File

@@ -0,0 +1,142 @@
#!/usr/bin/env python3
# Python wrapper for REST API for Home Assistant.
from requests import get, post
import json
class HomeAssistant(object):
# Initalizes Home Assistant API wrapper.
def __init__(self, ip, token):
self.url = 'http://{}:8123'.format(ip)
self.headers = {
'Authorization': 'Bearer {}'.format(token),
'content-type': 'application/json',
}
# Sends post requests.
def postService(self, domain, service, data):
response = post("{}/api/services/{}/{}".format(self.url,
domain,
service),
headers=self.headers, data=json.dumps(data))
response.raise_for_status()
return response
# Sends get requests and turns requested data.
def getRequest(self, domain):
response = get("{}/api/{}".format(self.url, domain),
headers=self.headers)
return json.loads(response.text)
# Returns a message if the API is up and running.
def getAPI(self):
return self.getRequest('')
# Returns the current configuration
def getConfig(self):
return self.getRequest('config')
# Returns basic information about the Home Assistant instance.
def getDiscoveryInfo(self):
return self.getRequest('discovery_info')
# Returns an array of event objects. Each event object contains
# event name and listener count.
def getEvents(self):
return self.getRequest('events')
# Returns an array of service objects. Each object contains the
# domain and which services it contains.
def getServices(self):
return self.getRequest('services')
# Returns an array of state changes in the past. Each object contains
# further details for the entities.
def getHistory(self,
minimumResponse=False,
entityId='',
startTime='',
endTime='',
significantChangesOnly=False):
options=''
if startTime:
options = '/' + startTime
options += '?'
if endTime:
options += '&end_time=' + endTime
if minimumResponse:
options += '&minimal_response'
if entityId:
options += '&filter_entity_id=' + entityId
if significantChangesOnly:
options += '&significant_changes_only'
return self.getRequest('history/period'+options)
# Returns an array of logbook entries.
def getLogbook(self, entityId='', startTime='', endTime=''):
options=''
if startTime:
options = '/' + startTime
options += '?'
if endTime:
options += '&end_time=' + endTime
if entityId:
options += '&entity=' + entityId
return self.getRequest('logbook'+options)
# Returns an array of state objects or a state object for specified
# entity_id. Each state has the following attributes: entity_id, state,
# last_changed and attributes.
def getState(self, entityId=''):
if entityId:
entityId = '/' + entityId
return self.getRequest('states' + entityId)
# Retrieve all errors logged during the current session of Home Assistant.
def getErrorLog(self):
return self.getRequest('error_log')
# Returns the data (image) from the specified camera entity_id.
def getCameraProxy(self, entityId):
return self.getRequest('camera_proxy/' + entityId)
# Runs a Home Assistant scene.
def runScene(self, entityId):
data = {'entity_id': entityId}
self.postService('scene', 'turn_on', data)
# Runs a Home Assistant script.
def runScript(self, entityId):
data = {'entity_id': entityId}
self.postService('script', 'turn_on', data)
# Sets the brightness level of a device.
def setLevel(self, entityId, level):
data = {'entity_id': entityId, 'brightness_pct': level}
self.postService('homeassistant', 'turn_on', data)
# Turns a device off.
def turnOn(self, entityId):
data = {'entity_id': entityId}
self.postService('homeassistant', 'turn_on', data)
# Turns a device on.
def turnOff(self, entityId):
data = {'entity_id': entityId}
self.postService('homeassistant', 'turn_off', data)
# Turns a device of the given power state.
def setOnOff(self, entityId, power):
if power:
self.turnOn(entityId)
else:
self.turnOff(entityId)
# Toggles power state of a given device.
def togglePower(self, entityId):
if self.getState(entityId)['state'] == 'off':
self.turnOn(entityId)
else:
self.turnOff(entityId)

72
home/bin/i3-mouse.py Normal file
View File

@@ -0,0 +1,72 @@
#!/usr/bin/env python3
import i3ipc
import sys
import os
import time
import pyautogui
from enum import Enum
# Enum for mouse direction
class Direction(Enum):
UP = 1
LEFT = 2
RIGHT = 3
DOWN = 4
NONE = 5
# getPoints() returns x and y movement of mouse
def getPoints():
sen = 10
t = 0
delay = 0.01
x,y = pyautogui.position()
while True:
time.sleep(delay)
t += delay
if t > 0.5:
return
xp, yp = pyautogui.position()
dx = x - xp
dy = y - yp
if abs(dx) > sen or abs(dy) > sen:
break
return dx, dy
#pointsToDirection() converts mouse movement points to a direction
def pointsToDirection(points):
if points is None:
return
x, y = points
if abs(x) > abs(y):
if x < 0:
return Direction.RIGHT
else:
return Direction.LEFT
else:
if y > 0:
return Direction.UP
else:
return Direction.DOWN
i3 = i3ipc.Connection()
focused = i3.get_tree().find_focused()
command = sys.argv[1]
if command in ['back', 'forward']:
if focused.window_instance not in ['overwatch.exe', 'hl2_linux']:
if sys.argv[1] == 'forward':
i3.command('workspace prev_on_output')
else:
i3.command('workspace next_on_output')
elif command == 'thumb':
direction = pointsToDirection(getPoints())
if direction == Direction.UP:
i3.command('move up')
elif direction == Direction.RIGHT:
i3.command('move right')
elif direction == Direction.DOWN:
i3.command('move down')
elif direction == Direction.LEFT:
i3.command('move left')

View File

@@ -0,0 +1,49 @@
import json
import os
import re
import urllib.request
# getJSONData returns JSON data from Blackmagic Design's website.
def getJSONData():
with urllib.request.urlopen('https://www.blackmagicdesign.com/api/support/us/downloads.json') as url:
return json.loads(url.read().decode())
# getDownloads() returns a list of downloads.
def getDownloads():
return getJSONData()['downloads']
# getResolveStudioDownloads() returns a list of DaVinci Resolve Studio downlaods.
def getResolveStudioDownloads():
return [d for d in getDownloads() if 'davinci-resolve-and-fusion' in d['relatedFamilies'][0] and
'Studio' in d['name'] and 'Resolve' in d['name']]
# filterOnlyLinuxSupport() filters a list of downloads to only ones that
# support Linux.
def filterOnlyLinuxSupport(downloads):
return [d for d in downloads if 'Linux' in d['platforms']]
# getLinuxURL() returns the Linux download info.
def getLinuxURL(download):
return download['urls']['Linux'][0]
# getURLId() returns the download id.
def getURLId(url):
return url['downloadId']
# getURLVersion() returns the url version number.
def getURLVersion(url):
if 'Beta' in url['downloadTitle']:
beta = re.search('Beta \\d+', url['downloadTitle'])
if beta:
beta = re.search('\\d+', beta.group()).group()
else:
beta = '99'
return '{}.{}.{}.{}'.format(url['major'], url['minor'], url['releaseNum'], beta)
# getDownloadId() returns downlaod id hash.
def getDownloadId(download):
return download['id']
for d in filterOnlyLinuxSupport(getResolveStudioDownloads()):
linux = getLinuxURL(d)
print(getURLVersion(linux), getURLId(linux), getDownloadId(d))

View File

@@ -0,0 +1,27 @@
#! /bin/bash
# Automatic install script for Bitwig Studio
# Import library
source $(dirname ${BASH_SOURCE[0]})/install-lib.sh
site='https://www.bitwig.com/download/'
bitwig=$(searchProgramInstalled bitwig-studio)
bitwigVersion=$(echo $bitwig | awk '{print $2;}'| filterVersion)
urlVersion=$(curl -sL $site | grep 'Bitwig Studio' | filterVersion | head -n 1)
url=https://downloads.bitwig.com/stable/$urlVersion/bitwig-studio-$urlVersion.deb
checkUptoDate Bitwig $bitwigVersion $urlVersion
echo Installing Bitwig Studio $urlVersion
# Setting up and downloading package
downloadPackage bitwig $url $(basename $url)
# Converting to Fedora friendly package
echo Creating rpm package
package=$(sudo alien -r $(basename $url) | awk '{print $1;}')
# Installing package
sudo rpm -Uvh --nodeps --force $package
sudo ln -s /usr/lib64/libbz2.so.1.0** /usr/lib64/libbz2.so.1.0

View File

@@ -0,0 +1,41 @@
#! /bin/bash
# Automatic install script for Dragonframe
# Import library
source $(dirname ${BASH_SOURCE[0]})/install-lib.sh
# Fix issue with shared library files.
function postInstallFix() {
sudo rm /opt/dragonframe2024/lib/libtiff.so.5
sudo rm /opt/dragonframe2024/lib/libudev.so.0
sudo ln -s -f /lib64/libudev.so.1 /opt/dragonframe2024/lib/libudev.so.0
}
dragonframe=$(searchProgramInstalled dragonframe20* | \
awk 'END {print $(NF-2), $(NF-1), $NF}')
dragonframeVersion=$(echo $dragonframe | awk '{print $2;}' | filterVersion)
agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0'
url=$(curl -s https://www.dragonframe.com/downloads/ \
-A $agent | \
grep .rpm | grep downloadButton | grep downloadButton | \
grep -io 'https://[a-z0-9+-._/]*.rpm' | head -n 1)
urlVersion=$(echo $url | awk -F "-" '{ print $2 }')
# Check if installed to the most recent version
checkUptoDate dragonframe $dragonframeVersion $urlVersion
echo Installing Dragonframe $urlVersion
# Setting up and downloading package
mkdir -p ~/Downloads/installers/dragonframe
cd ~/Downloads/installers/dragonframe
installer=$(basename "$url")
curl -s $url \
-A $agent \
-o $installer
# Install package
sudo dnf install $installer -y

View File

@@ -0,0 +1,62 @@
# Program version number comparison.
function versionGreater() {
if [[ $1 == $2 ]];then
return 0
fi
local IFS=.
local i ver1=($1) ver2=($2)
# fill empty fields in ver1 with zeros
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)); do
ver1[i]=0
done
for ((i=0; i<${#ver1[@]}; i++)); do
if [[ -z ${ver2[i]} ]]; then
# fill empty fields in ver2 with zeros
ver2[i]=0
fi
if ((10#${ver1[i]} > 10#${ver2[i]})); then
return 1
fi
if ((10#${ver1[i]} < 10#${ver2[i]})); then
return 2
fi
done
return 0
}
# Check if installed to the most recent version.
function checkUptoDate() {
if versionGreater $2 $3; then
echo $1 is up to date. Installed version $2 web version $3
exit
else
echo Updating $1 from $2 to $3...
fi
}
# Returns installed programs with a given name.
function searchProgramInstalled() {
dnf list -q | grep $1
}
# Filters string to Semantic Versioning.
function filterVersion() {
grep -Po -m 1 '\d{1,4}\.\d{1,4}\.*\d{0,4}'
}
# Downloads a file to the given download directory with
# the given name.
function downloadPackage() {
mkdir -p ~/Downloads/installers/${1}
cd ~/Downloads/installers/${1}
wget -O ${3} ${2}
}
# Get package manager
function packageManager() {
if command -v dnf &> /dev/null; then
echo dnf
elif command -v apt &> /dev/null; then
echo apt
fi
}

View File

@@ -0,0 +1,25 @@
#! /bin/bash
# Automatic install script for KeeWeb password manager
# Import library
source $(dirname ${BASH_SOURCE[0]})/install-lib.sh
keeweb=$(searchProgramInstalled KeeWeb)
keewebVersion=$(echo $keeweb | awk '{print $2;}' | filterVersion)
url=$(curl -s https://github.com/keeweb/keeweb/releases | grep .rpm | grep -Po '(?<=href=")[^"]*.rpm'| head -n 1)
url='https://github.com'$url
urlVersion=$(echo $url | filterVersion | head -n 1)
# Check if installed to the most recent version
checkUptoDate keeweb $keewebVersion $urlVersion
echo Installing KeeWeb $urlVersion
# Setting up and downloading package
mkdir -p ~/Downloads/installers/keeweb
cd ~/Downloads/installers/keeweb
wget $url
# Install package
sudo dnf install $(basename $url) -y

View File

@@ -0,0 +1,26 @@
#! /bin/bash
# Automatic install script for Reaper
# Import library
source $(dirname ${BASH_SOURCE[0]})/install-lib.sh
# Get download url
reaperVersion=$(head /opt/REAPER/whatsnew.txt | filterVersion)
reaperSite='https://www.reaper.fm'
downloadPage=$(curl -s "${reaperSite}/download.php")
urlVersion=$(echo "$downloadPage" | grep -A 2 'Linux x86_64' | filterVersion)
url="${reaperSite}/$(echo "$downloadPage" | grep linux_x86_64 | grep -Po '(?<=href=")[^"]*'| head -n 1)"
checkUptoDate Reaper $reaperVersion $urlVersion
# Setting up and downloading package
downloadPackage reaper $url $(basename $url)
# Install Reaper. Requires user input
tar -xf $(basename $url)
reaperDir=reaper_linux_x86_64
sudo sh ./$reaperDir/install-reaper.sh --install /opt --integrate-sys-desktop --usr-local-bin-symlink
# Delete extracted directory
rm -rd $reaperDir

View File

@@ -0,0 +1,102 @@
#! /bin/bash
# Automatic install script for DaVinci Resolve
# Import library
source $(dirname ${BASH_SOURCE[0]})/install-lib.sh
# Graphics card fix
function graphicsCardFix() {
sudo rm /etc/OpenCL/vendors/mesa.icd
sudo rm /etc/OpenCL/vendors/pocl.icd
}
# gLib fix
function glibFix() {
sudo mkdir /opt/resolve/libs/_disabled
sudo mv /opt/resolve/libs/libglib-2.0.so* /opt/resolve/libs/_disabled
sudo mv /opt/resolve/libs/libgio-2.0.so* /opt/resolve/libs/_disabled
sudo mv /opt/resolve/libs/libgmodule-2.0.so* /opt/resolve/libs/_disabled
}
versionFile=/opt/resolve/version.txt
resolveVersion=$(cat /opt/resolve/docs/ReadMe.html | grep 'DaVinci Resolve Studio' | filterVersion)
url=$(python $(dirname ${BASH_SOURCE[0]})/blackmagic-parser.py | head -n 1)
urlVersion=$(echo $url | awk '{print $1;}')
downloadID=$(echo $url | awk '{print $2;}')
referId=$(echo $url | awk '{print $3;}')
# Check for beta
major=$(echo $urlVersion | cut -d. -f1)
minor=$(echo $urlVersion | cut -d. -f2)
micro=$(echo $urlVersion | cut -d. -f3)
beta=$(echo $urlVersion | cut -d. -f4)
if [ "$beta" == '99' ]; then
packageName="DaVinci_Resolve_Studio_${major}.${minor}"
elif [ -n "$beta" ]; then
packageName="DaVinci_Resolve_Studio_${major}.${minor}b${beta}"
else
packageName="DaVinci_Resolve_Studio_${urlVersion}"
fi
# Get version if beta installed
if [ -n $resolveVersion ]; then
resolveVersion=$(cat $versionFile)
fi
checkUptoDate Resolve $resolveVersion $urlVersion
downloadUrl="https://www.blackmagicdesign.com/api/register/us/download/${downloadID}"
useragent="User-Agent: Mozilla/5.0 (X11; Linux) \
AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/77.0.3865.75 \
Safari/537.36"
reqjson="{ \
\"firstname\": \"Fedora\", \
\"lastname\": \"Linux\", \
\"email\": \"user@getfedora.org\", \
\"phone\": \"919-555-7428\", \
\"country\": \"us\", \
\"state\": \"North Carolina\", \
\"city\": \"Raleigh\", \
\"product\": \"DaVinci Resolve\" \
}"
zipUrl="$(curl \
-s \
-H 'Host: www.blackmagicdesign.com' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Origin: https://www.blackmagicdesign.com' \
-H "$useragent" \
-H 'Content-Type: application/json;charset=UTF-8' \
-H "Referer: https://www.blackmagicdesign.com/support/download/${referId}/Linux" \
-H 'Accept-Encoding: gzip, deflate, br' \
-H 'Accept-Language: en-US,en;q=0.9' \
-H 'Authority: www.blackmagicdesign.com' \
-H 'Cookie: _ga=GA1.2.1849503966.1518103294; _gid=GA1.2.953840595.1518103294' \
--data-ascii "$reqjson" \
--compressed \
"$downloadUrl")"
# Setting up and downloading package
downloadPackage resolve $zipUrl "${packageName}.zip"
# Installing package
sudo dnf install libxcrypt-compat
unzip -o $packageName
installerName="DaVinci_Resolve_Studio_${major}.${minor}.${micro}"
if [ ! -f ./*${installerName}_Linux.run ]; then
installerName="${packageName}"
fi
echo "Installing ./*${installerName}_Linux.run"
chmod +x ./*${installerName}_Linux.run
sudo SKIP_PACKAGE_CHECK=1 ./*${installerName}_Linux.run -i -y
# Version number backup
sudo echo $urlVersion > $versionFile
glibFix
# Keyboard mapping fix
setxkbmap -option 'caps:super'

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
# Import library
source $(dirname ${BASH_SOURCE[0]})/install-lib.sh
sudo $(packageManager) install rust cargo

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
# Automatic install script for SuperSlicer.
# Import library
source $(dirname ${BASH_SOURCE[0]})/install-lib.sh
function desktopFile() {
echo 'Creating desktop file'
echo '[Desktop Entry]' > $1
echo "Name=${2}" >> $1
echo 'Comment=3D printing slicer' >> $1
echo "Exec=${3}" >> $1
echo 'Icon=' >> $1
echo 'Type=Application' >> $1
echo 'Terminal=false' >> $1
}
program='SuperSlicer'
programPath="${HOME}/.local/bin/${program}.AppImage"
programVersion=$($programPath --help | grep SuperSlicer | filterVersion)
url=$(curl -s https://api.github.com/repos/supermerill/SuperSlicer/releases)
urlVersion=$(echo $url | grep tag_name | filterVersion | head -n 1)
url=$(echo "$url" | grep browser_download | grep ubuntu | head -n 1 | \
tr -d '"'| awk '{print $2}')
# Check if installed to the most recent version
checkUptoDate $program $programVersion $urlVersion
echo Installing $program $urlVersion
# Setting up and downloading package
cd $(dirname $programPath)
rm $programPath
wget $url -O $program.AppImage
chmod +x $programPath
# Create desktop file
desktopPath="${HOME}/.local/share/applications/${program}.desktop"
if [ ! -f $desktopPath ]; then
desktopFile $desktopPath $program $programPath
fi

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
# Import library
source $(dirname ${BASH_SOURCE[0]})/install-lib.sh
sudo $(packageManager) install sway waybar rofi mako alacritty

View File

@@ -0,0 +1,38 @@
#! /bin/bash
# Automatic install script for yabridge an audio bridge for linux.
# Import library
source $(dirname ${BASH_SOURCE[0]})/install-lib.sh
# Install wine if not already installed
if ! command -v wine &> /dev/null; then
if command -v dnf &> /dev/null; then
sudo dnf config-manager --add-repo \
https://dl.winehq.org/wine-builds/fedora/36/winehq.repo
fi
sudo $(packageManager) install winehq-staging
fi
program=yabridgectl
programVersion=$(yabridgectl --version | filterVersion)
url=$(curl -s https://api.github.com/repos/robbert-vdh/yabridge/releases | \
grep .tar.gz | grep releases/download | \
grep -Po 'https://[^"]*.tar.gz' | grep -v ubuntu | head -n 1)
urlVersion=$(echo $url | filterVersion | head -n 1)
# Check if installed to the most recent version
checkUptoDate $program $programVersion $urlVersion
echo Installing $program $urlVersion
# Setting up and downloading package
mkdir -p ~/Downloads/installers/${program}
cd ~/Downloads/installers/${program}
wget $url
# Install package
tar -xvzf *${urlVersion}.tar.gz
rm -rd ~/.local/share/yabridge
mv ./yabridge ~/.local/share/
sudo rm /bin/yabridgectl
sudo ln -s ~/.local/share/yabridge/yabridgectl /bin/yabridgectl

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# Install and set zsh as the default shell.
# Import library
source $(dirname ${BASH_SOURCE[0]})/install-lib.sh
sudo $(packageManager) install zsh
chsh -s $(which zsh)

View File

@@ -0,0 +1,30 @@
import datetime, holidays, os
from dateutil.tz import tzlocal
tz = tzlocal()
usHolidays = holidays.US()
def openToday(now = None):
if not now:
now = datetime.datetime.now(tz)
openTime = datetime.time(hour = 9, minute = 30, second = 0)
closeTime = datetime.time(hour = 16, minute = 0, second = 0)
# If it is a holiday
if now.strftime('%Y-%m-%d') in usHolidays:
return False
# If it is a weekend
if now.date().weekday() > 4:
return False
return True
def closed():
now = datetime.datetime.now(tz)
closeTime = datetime.time(hour = 16, minute = 0, second = 0)
# If before 0930 or after 1600
if (now.time() > closeTime):
return True
return False
if (openToday() and not closed()):
print("Open")
os.system("i3-msg 'workspace 10; exec librewolf --new-window robinhood.com \
&& sleep 1 && firefox -new-tab app.webull.com/watch'")

85
home/bin/start-firefox.py Normal file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/env python3
from i3ipc import Connection, Event
import os, time
# moveWindowToWorkspace() moves a given window to a given workspace.
def moveWindowToWorkspace(window, workspace):
window.command('move window to workspace ' + workspace)
# getWindows() returns a list of all open windows on the desktop.
def getWindows(i3):
windows = []
for con in i3.get_tree():
if con.window and con.parent.type != 'dockarea':
windows.append(con)
return windows
# getWindowByName() returns a window with the given name.
def getWindowByName(name, windows):
for win in windows:
if name in win.name:
return win
return
# filterWindowsByClass() returns a filter list of windows by class.
def filterWindowsByClass(windowClass, windows):
return [w for w in windows if w.window_class == windowClass]
# doesWindowExist() returns if a given window exists.
def doesWindowExist(window):
return window != None
# switchWorkspace() switches currently selected workspace.
def switchWorkspace(workspace):
i3.command('workspace ' + workspace)
# execI3() runs a command from i3wm.
def execI3(program):
i3.command('exec ' + program)
# launchProgram() launches a program on a given workspace.
def launchProgram(program, workspace):
switchWorkspace(workspace)
execI3(program)
# isProgramRunning() returns if a program is running and if it is
# moves it to a given workspace.
def isProgramRunning(name, windows, workspace):
for n in name:
program = getWindowByName(n, windows)
if doesWindowExist(program):
moveWindowToWorkspace(program, workspace)
return True
return False
def isPagesLoaded(windows):
for w in windows:
if 'http' not in w.name:
return True
return True
i3 = Connection()
windows = filterWindowsByClass('librewolf-default', getWindows(i3))
while(not isPagesLoaded(windows)):
time.sleep(0.1)
switchWorkspace('10')
switchWorkspace('1')
# Music
if not isProgramRunning(['music.youtube.com'], windows, '10'):
launchProgram('librewolf --new-window music.youtube.com', '10')
# Stocks
if not isProgramRunning(['Robinhood', 'Webull'], windows, '10'):
os.system('python ~/bin/launch-stocks-tracker.py')
# Videos
if not isProgramRunning(['odysee.com', 'lbry.tv', 'www.youtube.com',
' - YouTube', 'hulu.com', 'netflix.com',
'disneyplus.com', 'tv.youtube.com'],
windows, '10'):
launchProgram('librewolf --new-window youtube.com/feed/subscriptions', '10')
launchProgram('sleep 1 && librewolf -new-tab odysee.com/$/following', '10')

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# Print help info.
function print_help() {
echo 'Control the backlight brightness with animation.'
echo
echo '-i -- increase brightness'
echo '-d -- decrease brightness'
}
# Increase backlight brightness.
function increase() {
run_animation 'light -A 0.1'
}
# Decrease backlight brightness.
function decrease() {
run_animation 'light -U 0.1'
}
# Run animation task.
function run_animation() {
local cmd="${1}"
i=0
while [ $i -lt 50 ]; do
${cmd}
sleep 0.01
((i = i + 1));
done
}
# Check arguments
for i in "$@"; do
case $i in
-h|--help)
print_help
exit 0
;;
-i)
increase
;;
-d)
decrease
;;
*)
print_help
exit 1
;;
esac
done

View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Update Passwords
pass git pull
# Desktop
~/bin/connect-nas.sh
systemctl --user start polybar
systemctl --user restart streamdeck
waybar &
/usr/libexec/polkit-gnome-authentication-agent-1 &
# Keyring
dbus-update-activation-environment --all
/usr/bin/gnome-keyring-daemon --start --components=secrets,pkcs11,ssh
# NextCloud sync client
nextcloud --background &

View File

@@ -0,0 +1,53 @@
#! /bin/bash
# Script to convert CR3 files to DNG.
WINE_PREFIX=$(echo $HOME/.dng-wine)
CONVERTER_PATH='C:\Program Files\Adobe\Adobe DNG Converter\Adobe DNG Converter.exe'
FLAGS='-c -fl -p1'
# Converts foreward slashes to back slashes.
function foreward2Back() {
sed 's:/:\\:g'
}
# Converts a directory path a wine friendly path.
function dir2Wine() {
echo 'z:'"$(echo $( cd "$1" >/dev/null 2>&1 ; pwd -P ) | foreward2Back)"
}
# Converts file path to a wine friendly path to the file.
function file2Wine() {
echo $(dir2Wine $(dirname $1))\\$(basename $1)
}
# Converts a CR3 RAW file to DNG RAW.
function convertFile() {
WINEPREFIX="$WINE_PREFIX" wine "$CONVERTER_PATH" \
$FLAGS $2 "$(file2Wine $1)" &
}
# Converts all CR3 RAW files in a directory to DNG RAW.
function convertDir() {
for file in $1*.cr3; do
convertFile $file "-d $2"
done
}
start=`date +%s%N`
src=$1
dst=$(dir2Wine $2)
if [[ -d $src ]]; then
convertDir $src $dst
elif [[ -f $src ]]; then
convertFile $src $dst
else
echo "$src is not valid"
exit 1
fi
wait
end=`date +%s%N`
echo Execution time was `expr $end - $start` nanoseconds.

View File

@@ -0,0 +1,5 @@
sync_info = update
user_id =
setting_id =
base_id = GFSA04
updated_time = 1702867957

View File

@@ -0,0 +1,40 @@
{
"fan_max_speed": [
"20"
],
"fan_min_speed": [
"10"
],
"filament_cost": [
"19.99"
],
"filament_max_volumetric_speed": [
"8"
],
"filament_settings_id": [
"PETG - Overture @CR-10s"
],
"filament_vendor": [
"Overture"
],
"from": "User",
"inherits": "My Generic PETG",
"is_custom_defined": "0",
"name": "PETG - Overture @CR-10s",
"nozzle_temperature": [
"245"
],
"nozzle_temperature_initial_layer": [
"245"
],
"overhang_fan_speed": [
"40"
],
"pressure_advance": [
"0.26"
],
"slow_down_layer_time": [
"1"
],
"version": "1.6.1.0"
}

View File

@@ -0,0 +1,5 @@
sync_info = update
user_id =
setting_id =
base_id = GFSA04
updated_time = 1696802272

View File

@@ -0,0 +1,34 @@
{
"enable_pressure_advance": [
"1"
],
"filament_cost": [
"19.99"
],
"filament_flow_ratio": [
"0.9025"
],
"filament_settings_id": [
"PETG - Overture"
],
"filament_vendor": [
"Overture"
],
"from": "User",
"inherits": "My Generic PETG",
"is_custom_defined": "0",
"name": "PETG - Overture",
"nozzle_temperature": [
"245"
],
"nozzle_temperature_initial_layer": [
"245"
],
"pressure_advance": [
"0.26"
],
"slow_down_layer_time": [
"1"
],
"version": "1.6.1.0"
}

View File

@@ -0,0 +1,5 @@
sync_info = create
user_id =
setting_id =
base_id = GFSA04
updated_time = 1734886086

View File

@@ -0,0 +1,13 @@
{
"filament_flow_ratio": [
"0.955"
],
"filament_settings_id": [
"Voron Overture PETG"
],
"from": "User",
"inherits": "Voron Generic PETG",
"is_custom_defined": "0",
"name": "Voron Overture PETG",
"version": "2.2.0.4"
}

View File

@@ -0,0 +1,5 @@
sync_info = update
user_id =
setting_id =
base_id = GM001
updated_time = 1728686097

View File

@@ -0,0 +1,10 @@
{
"from": "User",
"inherits": "Voron 2.4 350 0.4 nozzle",
"is_custom_defined": "0",
"machine_start_gcode": "PRINT_START BED_TEMP=[bed_temperature_initial_layer_single] EXTRUDER_TEMP=[nozzle_temperature_initial_layer]",
"name": "AquaVoron 2.4 350 0.4 nozzle",
"print_host": "192.168.20.21",
"printer_settings_id": "AquaVoron 2.4 350 0.4 nozzle",
"version": "1.8.0.0"
}

View File

@@ -0,0 +1,5 @@
sync_info = update
user_id =
setting_id =
base_id = GM003
updated_time = 1728686148

View File

@@ -0,0 +1,13 @@
{
"from": "User",
"inherits": "Voron 2.4 350 0.6 nozzle",
"is_custom_defined": "0",
"machine_start_gcode": "PRINT_START BED_TEMP=[bed_temperature_initial_layer_single] EXTRUDER_TEMP=[nozzle_temperature_initial_layer]",
"name": "AquaVoron 2.4 350 0.6 nozzle",
"print_host": "http://192.168.20.21",
"printer_settings_id": "AquaVoron 2.4 350 0.6 nozzle",
"retraction_length": [
"0.1"
],
"version": "1.8.0.0"
}

View File

@@ -0,0 +1,5 @@
sync_info = create
user_id =
setting_id =
base_id = GM001
updated_time = 1695585702

View File

@@ -0,0 +1,86 @@
{
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;{layer_z}\n\n",
"from": "User",
"inherits": "MyKlipper 0.4 nozzle",
"is_custom_defined": "0",
"machine_end_gcode": "END_PRINT",
"machine_max_acceleration_extruding": [
"500",
"20000"
],
"machine_max_acceleration_retracting": [
"1000",
"5000"
],
"machine_max_acceleration_x": [
"500",
"20000"
],
"machine_max_acceleration_y": [
"500",
"20000"
],
"machine_max_acceleration_z": [
"100",
"200"
],
"machine_max_jerk_e": [
"5",
"2.5"
],
"machine_max_jerk_x": [
"8",
"9"
],
"machine_max_jerk_y": [
"8",
"9"
],
"machine_max_jerk_z": [
"0.4",
"0.4"
],
"machine_max_speed_e": [
"60",
"25"
],
"machine_max_speed_z": [
"10",
"12"
],
"machine_start_gcode": "START_PRINT BED_TEMP=[bed_temperature_initial_layer_single] EXTRUDER_TEMP=[nozzle_temperature_initial_layer]",
"max_layer_height": [
"0.48"
],
"name": "CR-10s 0.25 nozzle",
"nozzle_diameter": [
"0.25"
],
"nozzle_type": "brass",
"print_host": "192.168.1.5",
"printable_area": [
"0x0",
"300x0",
"300x300",
"0x300"
],
"printable_height": "400",
"printer_settings_id": "CR-10s 0.25 nozzle",
"retract_length_toolchange": [
"1"
],
"retraction_length": [
"0.5"
],
"retraction_minimum_travel": [
"2"
],
"use_firmware_retraction": "1",
"version": "1.6.1.0",
"wipe": [
"0"
],
"z_hop_types": [
"Auto Lift"
]
}

View File

@@ -0,0 +1,5 @@
sync_info = update
user_id =
setting_id =
base_id = GM001
updated_time = 1695585702

View File

@@ -0,0 +1,86 @@
{
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;{layer_z}\n\n",
"from": "User",
"inherits": "MyKlipper 0.4 nozzle",
"is_custom_defined": "0",
"machine_end_gcode": "END_PRINT",
"machine_max_acceleration_extruding": [
"500",
"20000"
],
"machine_max_acceleration_retracting": [
"1000",
"5000"
],
"machine_max_acceleration_x": [
"500",
"20000"
],
"machine_max_acceleration_y": [
"500",
"20000"
],
"machine_max_acceleration_z": [
"100",
"200"
],
"machine_max_jerk_e": [
"5",
"2.5"
],
"machine_max_jerk_x": [
"8",
"9"
],
"machine_max_jerk_y": [
"8",
"9"
],
"machine_max_jerk_z": [
"0.4",
"0.4"
],
"machine_max_speed_e": [
"60",
"25"
],
"machine_max_speed_z": [
"10",
"12"
],
"machine_start_gcode": "START_PRINT BED_TEMP=[bed_temperature_initial_layer_single] EXTRUDER_TEMP=[nozzle_temperature_initial_layer]",
"max_layer_height": [
"0.48"
],
"name": "CR-10s 0.4 nozzle",
"nozzle_type": "brass",
"print_host": "https://cr10.aquamorph.com",
"printable_area": [
"0x0",
"300x0",
"300x300",
"0x300"
],
"printable_height": "400",
"printer_settings_id": "CR-10s 0.4 nozzle",
"retract_length_toolchange": [
"1"
],
"retraction_length": [
"0.5"
],
"retraction_minimum_travel": [
"2"
],
"use_firmware_retraction": "1",
"version": "1.6.1.0",
"wipe": [
"0"
],
"z_hop": [
"0"
],
"z_hop_types": [
"Auto Lift"
]
}

View File

@@ -0,0 +1,5 @@
sync_info = update
user_id =
setting_id =
base_id = GM001
updated_time = 1702220626

View File

@@ -0,0 +1,89 @@
{
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;{layer_z}\n\n",
"from": "User",
"inherits": "MyKlipper 0.4 nozzle",
"is_custom_defined": "0",
"machine_end_gcode": "END_PRINT",
"machine_max_acceleration_extruding": [
"500",
"20000"
],
"machine_max_acceleration_retracting": [
"1000",
"5000"
],
"machine_max_acceleration_x": [
"500",
"20000"
],
"machine_max_acceleration_y": [
"500",
"20000"
],
"machine_max_acceleration_z": [
"100",
"200"
],
"machine_max_jerk_e": [
"5",
"2.5"
],
"machine_max_jerk_x": [
"8",
"9"
],
"machine_max_jerk_y": [
"8",
"9"
],
"machine_max_jerk_z": [
"0.4",
"0.4"
],
"machine_max_speed_e": [
"60",
"25"
],
"machine_max_speed_z": [
"10",
"12"
],
"machine_start_gcode": "START_PRINT BED_TEMP=[bed_temperature_initial_layer_single] EXTRUDER_TEMP=[nozzle_temperature_initial_layer]",
"max_layer_height": [
"0.48"
],
"name": "CR-10s 0.6 nozzle",
"nozzle_diameter": [
"0.6"
],
"nozzle_type": "brass",
"print_host": "192.168.20.20",
"printable_area": [
"0x0",
"300x0",
"300x300",
"0x300"
],
"printable_height": "400",
"printer_settings_id": "CR-10s 0.6 nozzle",
"retract_length_toolchange": [
"1"
],
"retraction_length": [
"0.5"
],
"retraction_minimum_travel": [
"2"
],
"use_firmware_retraction": "1",
"version": "1.6.1.0",
"wipe": [
"0"
],
"z_hop": [
"0"
],
"z_hop_types": [
"Auto Lift"
]
}

View File

@@ -0,0 +1,5 @@
sync_info = update
user_id =
setting_id =
base_id = GM001
updated_time = 1695341948

View File

@@ -0,0 +1,85 @@
{
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;{layer_z}\n\n",
"from": "User",
"inherits": "MyKlipper 0.4 nozzle",
"is_custom_defined": "0",
"machine_end_gcode": "END_PRINT",
"machine_max_acceleration_extruding": [
"500",
"20000"
],
"machine_max_acceleration_retracting": [
"1000",
"5000"
],
"machine_max_acceleration_x": [
"500",
"20000"
],
"machine_max_acceleration_y": [
"500",
"20000"
],
"machine_max_acceleration_z": [
"100",
"200"
],
"machine_max_jerk_e": [
"5",
"2.5"
],
"machine_max_jerk_x": [
"8",
"9"
],
"machine_max_jerk_y": [
"8",
"9"
],
"machine_max_jerk_z": [
"0.4",
"0.4"
],
"machine_max_speed_e": [
"60",
"25"
],
"machine_max_speed_z": [
"10",
"12"
],
"machine_start_gcode": "START_PRINT BED_TEMP=[bed_temperature_initial_layer_single] EXTRUDER_TEMP=[nozzle_temperature_initial_layer]",
"max_layer_height": [
"0.48"
],
"name": "Ender 3 0.6 nozzle",
"nozzle_diameter": [
"0.6"
],
"nozzle_type": "brass",
"print_host": "192.168.1.6",
"printable_area": [
"0x0",
"235x0",
"235x235",
"0x235"
],
"printer_settings_id": "Ender 3 0.6 nozzle",
"retract_length_toolchange": [
"1"
],
"retraction_length": [
"0.5"
],
"retraction_minimum_travel": [
"2"
],
"use_firmware_retraction": "1",
"version": "1.6.1.0",
"wipe": [
"0"
],
"z_hop_types": [
"Auto Lift"
]
}

View File

@@ -0,0 +1,5 @@
sync_info =
user_id =
setting_id =
base_id = GP004
updated_time = 1735702877

View File

@@ -0,0 +1,9 @@
{
"brim_type": "no_brim",
"from": "User",
"inherits": "0.18mm Fine 0.6 nozzle @Voron",
"is_custom_defined": "0",
"name": "0.18mm Fine 0.6 nozzle @Voron - AquaMorph",
"print_settings_id": "0.18mm Fine 0.6 nozzle @Voron - AquaMorph",
"version": "2.2.0.4"
}

View File

@@ -0,0 +1,5 @@
sync_info = update
user_id =
setting_id =
base_id = GP004
updated_time = 1702867957

View File

@@ -0,0 +1,41 @@
{
"brim_type": "no_brim",
"brim_width": "10",
"default_acceleration": "0",
"enable_support": "1",
"from": "User",
"gap_infill_speed": "30",
"infill_combination": "1",
"inherits": "0.20mm Standard @MyKlipper",
"initial_layer_acceleration": "0",
"initial_layer_infill_speed": "35",
"initial_layer_line_width": "137%",
"initial_layer_speed": "20",
"inner_wall_acceleration": "0",
"inner_wall_line_width": "112%",
"inner_wall_speed": "35",
"internal_solid_infill_line_width": "112%",
"internal_solid_infill_speed": "50",
"is_custom_defined": "0",
"line_width": "100%",
"name": "0.20mm Standard CR-10s",
"outer_wall_acceleration": "0",
"outer_wall_line_width": "80%",
"outer_wall_speed": "35",
"print_settings_id": "0.20mm Standard CR-10s",
"sparse_infill_density": "30%",
"sparse_infill_line_width": "107%",
"sparse_infill_pattern": "adaptivecubic",
"sparse_infill_speed": "60",
"support_interface_speed": "30",
"support_line_width": "95%",
"support_object_xy_distance": "0.75",
"support_speed": "30",
"support_type": "tree(auto)",
"top_surface_acceleration": "0",
"top_surface_line_width": "107%",
"top_surface_speed": "30",
"travel_acceleration": "1500",
"travel_speed": "150",
"version": "1.6.1.0"
}

View File

@@ -0,0 +1,5 @@
sync_info =
user_id =
setting_id =
base_id = GP004
updated_time = 1736606291

View File

@@ -0,0 +1,9 @@
{
"brim_type": "no_brim",
"from": "User",
"inherits": "0.30mm Standard 0.6 nozzle @Voron",
"is_custom_defined": "0",
"name": "0.30mm Standard 0.6 nozzle @Voron - AquaMorph",
"print_settings_id": "0.30mm Standard 0.6 nozzle @Voron - AquaMorph",
"version": "2.2.0.4"
}

View File

@@ -0,0 +1,51 @@
$mainMod = SUPER
# Keybindings
bind = $mainMod, return, exec, $terminal
bind = $mainMod, Q, killactive,
bind = $mainMod, C, exit,
bind = $mainMod, E, exec, $fileManager
bind = $mainMod, V, togglefloating,
bind = $mainMod, D, exec, $menu
bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod, J, togglesplit, # dwindle
bind = $mainMod, L, exec, hyprlock
bind = $mainMod, F, fullscreen
# Move focus window
bind = $mainMod, left, movefocus, l
bind = $mainMod, right, movefocus, r
bind = $mainMod, up, movefocus, u
bind = $mainMod, down, movefocus, d
# Switch workspaces
bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, workspace, 5
bind = $mainMod, 6, workspace, 6
bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10
# Move active window to a workspace
bind = $mainMod SHIFT, 1, movetoworkspace, 1
bind = $mainMod SHIFT, 2, movetoworkspace, 2
bind = $mainMod SHIFT, 3, movetoworkspace, 3
bind = $mainMod SHIFT, 4, movetoworkspace, 4
bind = $mainMod SHIFT, 5, movetoworkspace, 5
bind = $mainMod SHIFT, 6, movetoworkspace, 6
bind = $mainMod SHIFT, 7, movetoworkspace, 7
bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10
# Scroll through existing workspaces with mainMod + scroll
bind = $mainMod, mouse_down, workspace, e+1
bind = $mainMod, mouse_up, workspace, e-1
# Move/resize windows with mainMod + LMB/RMB and dragging
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow

View File

@@ -0,0 +1,17 @@
# Screen brightness controls
exec-once = light -N 1
bind = ,XF86MonBrightnessUp, exec, ~/bin/system/backlight-ctl.sh -i
bind = ,XF86MonBrightnessDown, exec, ~/bin/system/backlight-ctl.sh -d
# Pulse Audio controls
bind = ,XF86AudioRaiseVolume, exec, amixer set Master 3%+ #increase sound volume
bind = ,XF86AudioLowerVolume, exec, amixer set Master 3%- #decrease sound volume
bind = ,XF86AudioMute, exec, amixer set Master toggle # toggle sound
# Media controls
bind = ,XF86AudioPrev, exec, playerctl previous
bind = ,XF86AudioPlay, exec, playerctl play-pause
bind = ,XF86AudioNext, exec, playerctl next
# Lockscreen
bind = $mainMod, escape, exec, swaylock

View File

@@ -0,0 +1,4 @@
# Programs
$terminal = alacritty
$fileManager = dolphin
$menu = rofi -show combi

View File

@@ -0,0 +1,43 @@
general {
gaps_in = 5
gaps_out = 5
border_size = 2
col.active_border = rgba(e91e63ee) rgba(ffcdd2ee) 45deg
col.inactive_border = rgba(0288d1aa)
layout = dwindle
allow_tearing = false
}
decoration {
rounding = 5
blur {
enabled = true
size = 3
passes = 1
}
}
animations {
enabled = yes
bezier = myBezier, 0.05, 0.9, 0.1, 1.05
animation = windows, 1, 3, myBezier
animation = windowsOut, 1, 7, default, popin 80%
animation = border, 1, 10, default
animation = borderangle, 1, 8, default
animation = fade, 1, 7, default
animation = workspaces, 1, 2, default
}
dwindle {
pseudotile = yes
preserve_split = yes
force_split = 2
}
master {
orientation = right
}
gesture = 3, horizontal, workspace

View File

@@ -0,0 +1,40 @@
monitor=eDP-1,2256x1504@60,auto,1.175
# Enviroment
source = ~/.config/hypr/env.conf
# Startup programs
source = ~/.config/hypr/startup-all.conf
source = ~/.config/hypr/startup-framework.conf
# Default env vars
env = XCURSOR_SIZE,24
env = QT_QPA_PLATFORMTHEME,qt5ct
source = ~/.config/hypr/general.conf
input {
kb_layout = us
kb_variant =
kb_model =
kb_options =
kb_rules =
follow_mouse = 1
touchpad {
natural_scroll = yes
}
sensitivity = 0
}
xwayland {
force_zero_scaling = true
}
misc {
force_default_wallpaper = 0
}
windowrulev2 = suppressevent maximize, class:.*
source = ~/.config/hypr/bind-all.conf
source = ~/.config/hypr/bind-framework.conf

View File

@@ -0,0 +1,76 @@
background {
monitor =
path = $HOME/.cache/blurred_wallpaper.png
}
input-field {
monitor =
size = 200, 50
outline_thickness = 3
dots_size = 0.33 # Scale of input-field height, 0.2 - 0.8
dots_spacing = 0.15 # Scale of dots' absolute size, 0.0 - 1.0
dots_center = true
dots_rounding = -1 # -1 default circle, -2 follow input-field rounding
outer_color = rgb(151515)
inner_color = rgb(FFFFFF)
font_color = rgb(10, 10, 10)
fade_on_empty = true
fade_timeout = 1000 # Milliseconds before fade_on_empty is triggered.
placeholder_text = <i>Input Password...</i> # Text rendered in the input box when it's empty.
hide_input = false
rounding = -1 # -1 means complete rounding (circle/oval)
check_color = rgb(204, 136, 34)
fail_color = rgb(204, 34, 34) # if authentication failed, changes outer_color and fail message color
fail_text = <i>$FAIL <b>($ATTEMPTS)</b></i> # can be set to empty
fail_transition = 300 # transition time in ms between normal outer_color and fail_color
capslock_color = -1
numlock_color = -1
bothlock_color = -1 # when both locks are active. -1 means don't change outer color (same for above)
invert_numlock = false # change color if numlock is off
swap_font_color = false # see below
position = 0, -20
halign = center
valign = center
}
label {
monitor =
#clock
text = cmd[update:1000] echo "$TIME"
color = rgba(200, 200, 200, 1.0)
font_size = 55
font_family = Fira Semibold
position = -100, 70
halign = right
valign = bottom
shadow_passes = 5
shadow_size = 10
}
label {
monitor =
text = $USER
color = rgba(200, 200, 200, 1.0)
font_size = 20
font_family = Fira Semibold
position = -100, 160
halign = right
valign = bottom
shadow_passes = 5
shadow_size = 10
}
image {
monitor =
path = $HOME/.cache/square_wallpaper.png
size = 280 # lesser side if not 1:1 ratio
rounding = -1 # negative values mean circle
border_size = 4
border_color = rgb(221, 221, 221)
rotate = 0 # degrees, counter-clockwise
reload_time = -1 # seconds between reloading, 0 to reload with SIGUSR2
# reload_cmd = # command to get new path. if empty, old path will be used. don't run "follow" commands like tail -F
position = 0, 200
halign = center
valign = center
}

View File

@@ -0,0 +1,6 @@
# Password manager update
exec-once = pass git pull
# Start up script
exec-once = ~/bin/system/system-start.sh

View File

@@ -0,0 +1,2 @@
exec-once = [workspace 1 silent] brave-browser
exec-once = [workspace 2 silent] $terminal

View File

@@ -0,0 +1,434 @@
# Set super key as mod
set $mod Mod4
# Colors
set $blue "#0288D1"
set $pink "#E91E63"
set $lpink "#FFCDD2"
# Font for window titles. Will also be used by the bar unless a different font
# is used in the bar {} block below.
font pango:NimbusSans Bold 10
# Use Mouse+$mod to drag floating windows to their wanted position
floating_modifier $mod
# start a terminal
bindsym $mod+Return exec --no-startup-id alacritty
# kill focused window
bindsym $mod+q kill
# start program launcher
bindsym $mod+d exec --no-startup-id rofi -show combi
# change focus
bindsym $mod+j focus left
bindsym $mod+k focus down
bindsym $mod+l focus up
bindsym $mod+semicolon focus right
# alternatively, you can use the cursor keys:
bindsym $mod+Left focus left
bindsym $mod+Down focus down
bindsym $mod+Up focus up
bindsym $mod+Right focus right
# move focused window
bindsym $mod+Shift+j move left
bindsym $mod+Shift+k move down
bindsym $mod+Shift+l move up
bindsym $mod+Shift+semicolon move right
# alternatively, you can use the cursor keys:
bindsym $mod+Shift+Left move left
bindsym $mod+Shift+Down move down
bindsym $mod+Shift+Up move up
bindsym $mod+Shift+Right move right
# split in horizontal orientation
bindsym $mod+h split h
# split in vertical orientation
bindsym $mod+v split v
# Cycle workspaces
bindsym $mod+apostrophe workspace next_on_output
# enter fullscreen mode for the focused container
bindsym $mod+f fullscreen toggle
# change container layout (stacked, tabbed, toggle split)
#bindsym $mod+s layout stacking
bindsym $mod+w layout tabbed
bindsym $mod+e layout toggle split
# toggle tiling / floating
bindsym $mod+Shift+space floating toggle
# change focus between tiling / floating windows
bindsym $mod+space focus mode_toggle
# focus the parent container
bindsym $mod+a focus parent
# media controls
bindsym Ctrl+Left exec playerctl previous
bindsym Ctrl+Down exec playerctl play-pause
bindsym Ctrl+Right exec playerctl next
# Gaps
set $inner 8
set $outer 0
gaps inner $inner
gaps outer $outer
# Define names for default workspaces
set $ws1 "1"
set $ws2 "2"
set $ws3 "3"
set $ws4 "4"
set $ws5 "5"
set $ws6 "6"
set $ws7 "7"
set $ws8 "8"
set $ws9 "9"
set $ws10 "10"
set $wsResolve "11"
set $wsReaper "12"
set $wsBitwig "13"
set $wsGames "14"
set $wsSignal "15"
# switch to workspace
bindsym $mod+1 workspace $ws1
bindsym $mod+2 workspace $ws2
bindsym $mod+3 workspace $ws3
bindsym $mod+4 workspace $ws4
bindsym $mod+5 workspace $ws5
bindsym $mod+6 workspace $ws6
bindsym $mod+7 workspace $ws7
bindsym $mod+8 workspace $ws8
bindsym $mod+9 workspace $ws9
bindsym $mod+0 workspace $ws10
# move focused container to workspace
bindsym $mod+Shift+1 move container to workspace $ws1
bindsym $mod+Shift+2 move container to workspace $ws2
bindsym $mod+Shift+3 move container to workspace $ws3
bindsym $mod+Shift+4 move container to workspace $ws4
bindsym $mod+Shift+5 move container to workspace $ws5
bindsym $mod+Shift+6 move container to workspace $ws6
bindsym $mod+Shift+7 move container to workspace $ws7
bindsym $mod+Shift+8 move container to workspace $ws8
bindsym $mod+Shift+9 move container to workspace $ws9
bindsym $mod+Shift+0 move container to workspace $ws10
# reload the configuration file
bindsym $mod+Shift+c exec "sh ~/bin/i3wm-config-gen.sh"
# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
bindsym $mod+Shift+r exec "sh ~/bin/i3wm-config-gen.sh" ; restart
# exit i3 (logs you out of your X session)
bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'"
# resize window (you can also use the mouse for that)
mode "resize" {
# These bindings trigger as soon as you enter the resize mode
# Pressing left will shrink the windows width.
# Pressing right will grow the windows width.
# Pressing up will shrink the windows height.
# Pressing down will grow the windows height.
bindsym j resize shrink width 10 px or 10 ppt
bindsym k resize grow height 10 px or 10 ppt
bindsym l resize shrink height 10 px or 10 ppt
bindsym semicolon resize grow width 10 px or 10 ppt
bindsym Shift+j resize shrink width 1 px or 1 ppt
bindsym Shift+k resize grow height 1 px or 1 ppt
bindsym Shift+l resize shrink height 1 px or 1 ppt
bindsym Shift+semicolon resize grow width 1 px or 1 ppt
# same bindings, but for the arrow keys
bindsym Left resize shrink width 10 px or 10 ppt
bindsym Down resize grow height 10 px or 10 ppt
bindsym Up resize shrink height 10 px or 10 ppt
bindsym Right resize grow width 10 px or 10 ppt
bindsym Shift+Left resize shrink width 1 px or 1 ppt
bindsym Shift+Down resize grow height 1 px or 1 ppt
bindsym Shift+Up resize shrink height 1 px or 1 ppt
bindsym Shift+Right resize grow width 1 px or 1 ppt
# back to normal: Enter or Escape or $mod+r
bindsym Return mode "default"
bindsym Escape mode "default"
bindsym $mod+r mode "default"
}
bindsym $mod+r mode "resize"
# Set caps lock key to super
exec_always --no-startup-id setxkbmap -option 'caps:super'
# Startup scripts
exec --no-startup-id ~/bin/system/system-start.sh
# class border backgr. text indicator child_border
client.focused $pink $pink $pink $pink $pink
client.focused_inactive $blue $blue $blue $blue $blue
client.unfocused $blue $blue $blue $blue $blue
client.urgent $blue $blue $blue $blue $blue
client.placeholder $blue $blue $blue $blue $blue
client.background $blue
# Removes border and title bar
for_window [class="^.*"] border pixel 3
#new_window 1pixel
#new_float normal 4
default_floating_border normal 3
#new_window normal 0 px
# Screenshots
bindsym Print exec scrot '%Y:%m:%d:%H:%M:%S.png' -e 'mv $f ~/Pictures/screenshots/'
bindsym --release $mod+Print exec scrot '%Y:%m:%d:%H:%M:%S.png' -s -e 'mv $f ~/Pictures/screenshots/'
bindsym $mod+s exec scrot '%Y:%m:%d:%H:%M:%S.png' -e 'mv $f ~/Pictures/screenshots/'
bindsym --release $mod+Shift+s exec grim -g "$(slurp)" - | wl-copy
bindsym $mod+n exec nautilus
bindsym $mod+m exec nautilus ~/Videos
# Steam
for_window [class="^steamwebhelper$" title="^Friends$"] floating enable
for_window [class="^steamwebhelper$" title="Steam - News"] floating enable
for_window [class="^steamwebhelper" title=".* - Chat"] floating enable
for_window [class="^steamwebhelper$" title="^Settings$"] floating enable
for_window [class="^steamwebhelper$" title=".* - event started"] floating enable
for_window [class="^steamwebhelper$" title=".* CD key"] floating enable
for_window [class="^steamwebhelper$" title="^Steam - Self Updater$"] floating enable
for_window [class="^steamwebhelper$" title="^Screenshot Uploader$"] floating enable
for_window [class="^steamwebhelper$" title="^Steam Guard - Computer Authorization Required$"] floating enable
for_window [title="^Steam Keyboard$"] floating enable
# Jetbrains
for_window [class="^com-intellij-updater-Runner$" title="^Update$"] floating enable
for_window [instance="^sun-awt-X11-XDialogPeer$" title="^Complete Installation$"] floating enable
# DaVinci Resolve
#for_window [class="resolve"] gaps inner current set 0; gaps outer current set 0
# Bitwig
for_window [class="^Bitwig Studio$" title="^Bitwig Studio"] gaps inner set 0; gaps outer set 0
for_window [class="^Bitwig Studio$" title="^Bitwig Studio"] exec python ~/bin/audio/synth-power.py -d
for_window [class="^Bitwig Studio$" title="^Bitwig Studio"] exec sh ~/bin/audio/aquamix.sh -d
for_window [class="^Bitwig Studio$" title="^Bitwig Studio"] exec systemctl --user restart i3wm-close-window.service
#Other
for_window [class="Signal"] move to workspace $wsSignal
#bindsym $mod+F5 gaps inner current set 0; gaps outer current set 0
#bindsym $mod+F6 gaps inner current set $inner; gaps outer current set $outer
{{- if eq .chezmoi.hostname "desktop" }}
# Assign workspaces to monitors
workspace $ws1 output DP-4
workspace $ws2 output DP-4
workspace $ws3 output DP-4
workspace $ws4 output DP-4
workspace $wsGames output DP-4
workspace $wsResolve output DP-4
workspace $wsReaper output DP-4
workspace $wsBitwig output DP-4
workspace $ws5 output DP-2
workspace $ws6 output DP-2
workspace $ws7 output DP-2
workspace $ws8 output DP-2
workspace $wsSignal output DP-2
workspace $ws9 output HDMI-0
workspace $ws10 output HDMI-0
exec --no-startup-id compton &
exec --no-startup-id feh --bg-scale ~/Pictures/desktop/0001.jpg &
mode "$g13" {
bindsym 1 exec --no-startup-id cat ~/.config/g13/overwatch.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/overwatch.lpbm > /tmp/g13-0; mode "default"
bindsym 2 exec --no-startup-id cat ~/.config/g13/resolve.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/resolve.lpbm > /tmp/g13-0; mode "default"
bindsym 3 exec --no-startup-id cat ~/.config/g13/planet-coaster.bind > /tmp/g13-0 && sleep 0.1 && cat ~/.config/g13/planet-coaster.lpbm > /tmp/g13-0; mode "default"
bindsym 4 exec --no-startup-id cat ~/.config/g13/fall-guys.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/fall-guys.lpbm > /tmp/g13-0; mode "default"
bindsym Escape mode "default"
bindsym Return mode "default"
}
set $g13 G13 Profile: [1] Overwatch [2] Resolve [3] Planet Coaster [4] Fall Guys
bindsym $mod+F1 mode "$g13"
exec_always --no-startup-id g13d --config ~/.config/g13/resolve.bind --logo ~/.config/g13/resolve.lpbm &
# Startup programs
exec --no-startup-id "workspace $10"
exec --no-startup-id "workspace $15; exec flatpak run org.signal.Signal"
# Starts Jack for audio
exec --no-startup-id "workspace $1; exec alacritty"
exec --no-startup-id sh ~/bin/audio/system-start-audio.sh
# Open Google Play Music on workspace 10
for_window [title="Google Play Music Desktop Player"] move to workspace $ws10
# Among Us
for_window [class="steam_app_945360" title="Among Us"] move to workspace $wsGames
for_window [class="steam_app_945360" title="Among Us"] exec --no-startup-id cat ~/.config/g13/among-us.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/among-us.lpbm > /tmp/g13-0
# Starting Overwatch
for_window [class="overwatch.exe" title="Overwatch"] move to workspace $wsGames
for_window [class="overwatch.exe" title="Overwatch"] exec --no-startup-id cat ~/.config/g13/overwatch.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/overwatch.lpbm > /tmp/g13-0
for_window [class="steam_app_2357570" title="Overwatch"] move to workspace $wsGames
for_window [class="steam_app_2357570" title="Overwatch"] exec --no-startup-id cat ~/.config/g13/overwatch.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/overwatch.lpbm > /tmp/g13-0
for_window [class="battle.net.exe" title="Battle.net"] move to workspace $wsGames
for_window [class="battle.net.exe" title="Blizzard Battle.net"] move to workspace $wsGames
for_window [class="Lutris"] move to workspace $ws4
# DOOM
for_window [class="Wine" title="DOOMx64vk"] move to workspace $wsGames
for_window [class="Wine" title="DOOMx64vk"] exec --no-startup-id cat ~/.config/g13/doom.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/doom.lpbm > /tmp/g13-0
# DOOM Eternal
for_window [title="DOOMEternal"] move to workspace $wsGames
for_window [title="DOOMEternal"] exec --no-startup-id cat ~/.config/g13/doom-eternal.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/doom.lpbm > /tmp/g13-0
# Planet Coaster
for_window [class="planetcoaster.exe" title="Planet Coaster"] move to workspace $wsGames
for_window [class="planetcoaster.exe" title="Planet Coaster"] exec --no-startup-id cat ~/.config/g13/planet-coaster.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/planet-coaster.lpbm > /tmp/g13-0
# Cyberpunk 2077
for_window [class="steam_app_1091500" title="Cyberpunk 2077 (C) 2020 by CD Projekt RED"] move to workspace $wsGames
for_window [class="steam_app_1091500" title="Cyberpunk 2077 (C) 2020 by CD Projekt RED"] exec --no-startup-id cat ~/.config/g13/cyberpunk-2077.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/cyberpunk-2077.lpbm > /tmp/g13-0
# Starting DaVinci Resolve
for_window [class="resolve"] move to workspace $wsResolve
for_window [class="resolve"] exec --no-startup-id cat ~/.config/g13/resolve.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/resolve.lpbm > /tmp/g13-0
bindsym $mod+/ gaps inner current set 0; gaps outer current set 0
# Starting Reaper
for_window [class="REAPER"] move to workspace $wsReaper
# Steam
for_window [class="^Steam$"] move to workspace $wsGames
for_window [title="^Steam$"] move to workspace $wsGames
# Bitwig
for_window [class="^Show-splash-gtk$"] move to workspace $wsBitwig
for_window [class="^Bitwig Studio$"] move to workspace $wsBitwig
for_window [class="com.bitwig.BitwigStudio"] exec sleep 1; move to workspace $wsBitwig
# Fall Guys
for_window [title="FallGuys_client"] move to workspace $wsGames
for_window [title="FallGuys_client"] exec --no-startup-id cat ~/.config/g13/fall-guys.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/fall-guys.lpbm > /tmp/g13-0
# Portal
for_window [class="hl2_linux" title="Portal - OpenGL"] move to workspace $wsGames
for_window [class="hl2_linux" title="Portal - OpenGL"] exec --no-startup-id cat ~/.config/g13/portal.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/portal.lpbm > /tmp/g13-0
for_window [class="portal2_linux" title="PORTAL 2 - OpenGL"] move to workspace $wsGames
for_window [class="portal2_linux" title="PORTAL 2 - OpenGL"] exec --no-startup-id cat ~/.config/g13/portal.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/portal.lpbm > /tmp/g13-0
# Two Point Hospital
for_window [class="TPH.x86_64" title="Two Point Hospital"] move to workspace $wsGames
for_window [class="TPH.x86_64" title="Two Point Hospital"] exec --no-startup-id cat ~/.config/g13/two-point-hospital.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/two-point-hospital.lpbm > /tmp/g13-0
# Minecraft
for_window [class="Minecraft*" title="Minecraft*"] move to workspace $wsGames
for_window [class="Minecraft*" title="Minecraft*"] exec --no-startup-id cat ~/.config/g13/minecraft.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/minecraft.lpbm > /tmp/g13-0
# Arkham Knight
for_window [class="steam_app_208650" title="*"] move to workspace $wsGames
for_window [class="steam_app_208650" title="*"] exec --no-startup-id cat ~/.config/g13/arkham-knight.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/arkham-knight.lpbm > /tmp/g13-0
# Factorio
for_window [class="factorio" title="Factorio*"] move to workspace $wsGames
for_window [class="factorio" title="Factorio*"] exec --no-startup-id cat ~/.config/g13/factorio.bind > /tmp/g13-0 && sleep .1 && cat ~/.config/g13/factorio.lpbm > /tmp/g13-0
# The side buttons move the desktop around
bindsym --whole-window button9 exec --no-startup-id python3 ~/bin/i3-mouse.py back
bindsym --whole-window button8 exec --no-startup-id python3 ~/bin/i3-mouse.py forward
bindsym $mod+Tab exec --no-startup-id python3 ~/bin/i3-mouse.py thumb
{{- end }}
{{- if eq .chezmoi.hostname "framework" }}
# Display
output eDP-1 scale 1.25
# Desktop background
output "*" bg ~/Pictures/wallpaper/0000.jpg fill
# Screen brightness controls
exec light -N 1
bindsym XF86MonBrightnessUp exec light -A 5 # increase screen brightness
bindsym XF86MonBrightnessDown exec light -U 5 # decrease screen brightness
# Pulse Audio controls
bindsym XF86AudioRaiseVolume exec amixer set Master 3%+ #increase sound volume
bindsym XF86AudioLowerVolume exec amixer set Master 3%- #decrease sound volume
bindsym XF86AudioMute exec amixer set Master toggle # toggle sound
# Media controls
bindsym XF86AudioPrev exec playerctl previous
bindsym XF86AudioPlay exec playerctl play-pause
bindsym XF86AudioNext exec playerctl next
# Lockscreen
bindsym $mod+Escape exec swaylock
# Touchpad Settings
input "2362:628:PIXA3854:00_093A:0274_Touchpad" {
accel_profile flat
click_method clickfinger
dwt disabled
natural_scroll enabled
scroll_method two_finger
tap enabled
pointer_accel 0.8
}
# Move Programs
for_window [app_id="firefox"] move to workspace $ws1
for_window [class="Emacs"] move to workspace $ws2
for_window [class="Steam"] move to workspace $wsGames
for_window [class="com.bitwig.BitwigStudio"] move to workspace $wsBitwig
# Notifications
exec mako
# Startup Programs
exec "swaymsg 'workspace $wsSignal; exec flatpak run org.signal.Signal'"
exec "swaymsg 'workspace $ws2; exec alacritty'"
exec "swaymsg 'workspace $ws1; exec brave-browser'"
{{- end }}
{{- if eq .chezmoi.hostname "w530" }}
# Screen brightness controls
bindsym XF86MonBrightnessUp exec light -A 5 # increase screen brightness
bindsym XF86MonBrightnessDown exec light -U 5 # decrease screen brightness
# Pulse Audio controls
bindsym XF86AudioRaiseVolume exec amixer set Master 3%+ #increase sound volume
bindsym XF86AudioLowerVolume exec amixer set Master 3%- #decrease sound volume
bindsym XF86AudioMute exec amixer set Master toggle # toggle sound
bindsym XF86AudioMicMute exec amixer set Capture toggle # toggle mic
# Turn off trackpad
bindsym $mod+Shift+u exec sh ~/dotfiles/scripts/trackpad-toggle.sh
exec --no-startup-id ~/dotfiles/scripts/trackpad-toggle.sh
# Desktop background
output "*" bg ~/Pictures/wallpaper/0001.jpg fill
# Turn off the screen
bindsym XF86Launch1 exec xset -display :0.0 dpms force off
# Start up programs
for_window [class="Firefox"] move to workspace $ws1
for_window [class="emacs" title="emacs@*"] move to workspace $ws2
for_window [class="jetbrains-studio"] move to workspace $ws3
for_window [title="Google Play Music Desktop Player"] move to workspace $ws10
exec mako
exec --no-startup-id "firefox"
{{- end }}

View File

@@ -0,0 +1,3 @@
computer={{ .chezmoi.hostname }}
activation_bytes={{ pass "self-host/token/audible-activation-bytes" }}
AQUAAI_KEY={{ pass "self-host/token/aquaai" }}

View File

@@ -0,0 +1,13 @@
wireplumber.components = [
{
name = auto-connect-ports.lua, type = script/lua
provides = custom.auto-connect-ports
}
]
wireplumber.profiles = {
main = {
custom.auto-connect-ports = required
}
}

View File

@@ -19,18 +19,28 @@ SAVEHIST=99999999
source "$HOME/.config/settings.conf" source "$HOME/.config/settings.conf"
# Text Editor # Text Editor
alias emacs='emacs -nw' export EDITOR='emacs -nw'
alias e='emacs -nw' alias emacs="${EDITOR}"
alias e="${EDITOR}"
export TERM=xterm
# Search # Search
alias g='grep -Irn' alias g='grep -Irn'
# Dotfiles
alias dot='cd ~/.local/share/chezmoi'
export DOT_PROGRAM='chezmoi'
alias dota="${DOT_PROGRAM} add"
alias dotd="${DOT_PROGRAM} diff"
alias dote="${DOT_PROGRAM} edit --apply"
alias dotu="${DOT_PROGRAM} update"
# Other # Other
alias i='sudo dnf install' alias i='sudo dnf install'
alias d='sudo dnf' alias d='sudo dnf'
alias u='sh ~/bin/update.sh' alias u='sh ~/bin/update.sh'
alias dot='cd ~/dotfiles'
alias h='cd ~/git/cacolglazier.com/ && hugo server' alias h='cd ~/git/cacolglazier.com/ && hugo server'
# Git # Git
alias c='git commit -m' alias c='git commit -m'
alias a='git add' alias a='git add'
@@ -51,14 +61,11 @@ alias qc="${AQUAAI_PATH} --cli"
alias qg="${AQUAAI_PATH} --git" alias qg="${AQUAAI_PATH} --git"
alias qr="${AQUAAI_PATH} --code-review" alias qr="${AQUAAI_PATH} --code-review"
alias qa="${AQUAAI_PATH} --home-assistant" alias qa="${AQUAAI_PATH} --home-assistant"
export AQUAAI_DEFAULT_MODEL='hf.co/unsloth/Qwen3-4B-Instruct-2507-GGUF:Q4_K_M' export AQUAAI_DEFAULT_MODEL='hf.co/unsloth/Qwen3-4B-Instruct-2507-GGUF:Q3_K_M'
export AQUAAI_CODING_MODEL='hf.co/unsloth/Qwen3-4B-Instruct-2507-GGUF:Q4_K_M' export AQUAAI_CODING_MODEL='hf.co/unsloth/Qwen3-4B-Instruct-2507-GGUF:Q3_K_M'
export AQUAAI_RICH_FORMAT_MODE=true export AQUAAI_RICH_FORMAT_MODE=false
export AQUAAI_KEY export AQUAAI_KEY
export TERM=xterm
export EDITOR='emacs -nw'
# Daisy build toolkit # Daisy build toolkit
GCC_PATH=~/dev/gcc-arm-none-eabi-10-2020-q4-major/bin GCC_PATH=~/dev/gcc-arm-none-eabi-10-2020-q4-major/bin
export PATH=$GCC_PATH:$PATH export PATH=$GCC_PATH:$PATH

View File

@@ -0,0 +1,165 @@
-- As explained on: https://bennett.dev/auto-link-pipewire-ports-wireplumber/
--
-- This script keeps my stereo-null-sink connected to whatever output I'm currently using.
-- I do this so Pulseaudio (and Wine) always sees a stereo output plus I can swap the output
-- without needing to reconnect everything.
-- Link two ports together
function link_port(output_port, input_port)
if not input_port or not output_port then
return nil
end
local link_args = {
["link.input.node"] = input_port.properties["node.id"],
["link.input.port"] = input_port.properties["object.id"],
["link.output.node"] = output_port.properties["node.id"],
["link.output.port"] = output_port.properties["object.id"],
-- The node never got created if it didn't have this field set to something
["object.id"] = nil,
-- I was running into issues when I didn't have this set
["object.linger"] = true,
["node.description"] = "Link created by auto_connect_ports"
}
local link = Link("link-factory", link_args)
link:activate(1)
return link
end
-- Automatically link ports together by their specific audio channels.
--
-- ┌──────────────────┐ ┌───────────────────┐
-- │ │ │ │
-- │ FL ├────────►│ AUX0 │
-- │ OUTPUT │ │ │
-- │ FR ├────────►│ AUX1 INPUT │
-- │ │ │ │
-- └──────────────────┘ │ AUX2 │
-- │ │
-- └───────────────────┘
--
-- -- Call this method inside a script in global scope
--
-- auto_connect_ports {
--
-- -- A constraint for all the required ports of the output device
-- output = Constraint { "node.name"}
--
-- -- A constraint for all the required ports of the input device
-- input = Constraint { .. }
--
-- -- A mapping of output audio channels to input audio channels
--
-- connections = {
-- ["FL"] = "AUX0"
-- ["FR"] = "AUX1"
-- }
--
-- }
--
function auto_connect_ports(args)
local output_om = ObjectManager {
Interest {
type = "port",
args["output"],
Constraint { "port.direction", "equals", "out" }
}
}
local links = {}
local input_om = ObjectManager {
Interest {
type = "port",
args["input"],
Constraint { "port.direction", "equals", "in" }
}
}
local all_links = ObjectManager {
Interest {
type = "link",
}
}
local unless = nil
if args["unless"] then
unless = ObjectManager {
Interest {
type = "port",
args["unless"],
Constraint { "port.direction", "equals", "in" }
}
}
end
function _connect()
local delete_links = unless and unless:get_n_objects() > 0
if delete_links then
for _i, link in pairs(links) do
link:request_destroy()
end
links = {}
return
end
for output_name, input_names in pairs(args.connect) do
local input_names = input_names[1] == nil and { input_names } or input_names
if delete_links then
else
-- Iterate through all the output ports with the correct channel name
for output in output_om:iterate { Constraint { "audio.channel", "equals", output_name } } do
for _i, input_name in pairs(input_names) do
-- Iterate through all the input ports with the correct channel name
for input in input_om:iterate { Constraint { "audio.channel", "equals", input_name } } do
-- Link all the nodes
local link = link_port(output, input)
if link then
table.insert(links, link)
end
end
end
end
end
end
end
output_om:connect("object-added", _connect)
input_om:connect("object-added", _connect)
all_links:connect("object-added", _connect)
output_om:activate()
input_om:activate()
all_links:activate()
if unless then
unless:connect("object-added", _connect)
unless:connect("object-removed", _connect)
unless:activate()
end
end
-- pw-cli list-objects | grep object.path
-- Connect to speakers
auto_connect_ports {
output = Constraint { "object.path", "matches", "speakers:*" },
input = Constraint { "object.path", "matches", "alsa:acp:C8Pre:0:playback:*" },
connect = {
["FL"] = "AUX0",
["FR"] = "AUX1"
}
}

View File

@@ -0,0 +1,26 @@
-- Dump all Wireplumber ports
function dump(o)
if type(o) == 'table' then
local s = '{ '
for k,v in pairs(o) do
if type(k) ~= 'number' then k = '"'..k..'"' end
s = s .. '['..k..'] = ' .. dump(v) .. ',\n'
end
return s .. '} '
else
return tostring(o)
end
end
local port_om = ObjectManager {
Interest {
type = "port",
}
}
port_om:connect("object-added", function (om, port)
print(dump(port.properties) .. '\n\n')
end)
port_om:activate()

14
home/user/es-9.service Normal file
View File

@@ -0,0 +1,14 @@
[Unit]
Description=ES-9 Audio Interface
BindsTo=dev-snd-by\x2did-usb\x2dExpert_Sleepers_Ltd_ES\x2d9\x2d01.device
After=dev-snd-by\x2did-usb\x2dExpert_Sleepers_Ltd_ES\x2d9\x2d01.device
Requisite=dev-snd-by\x2did-usb\x2dExpert_Sleepers_Ltd_ES\x2d9\x2d01.device
[Install]
WantedBy=dev-snd-by\x2did-usb\x2dExpert_Sleepers_Ltd_ES\x2d9\x2d01.device
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=%h/.config/scripts/audio/es9start.sh
ExecStop=%h/.config/scripts/audio/es9stop.sh

View File

@@ -0,0 +1,11 @@
[Unit]
Description=i3wm close window service
[Service]
RemainAfterExit=true
ExecStart=python %h/.config/scripts/desktop/i3wm-close-window.py
Restart=always
RestartSec=1
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,8 @@
[Unit]
Description=Polybar
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=%h/bin/desktop/polybar-start.sh
ExecStop=killall -q polybar

View File

@@ -0,0 +1,13 @@
[Unit]
Description=Snapcast
After=pipewire.service
Requires=pipewire.service
[Install]
WantedBy=default.target
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=%h/git/audio/snapcast/bin/snapclient
ExecStop=killall -q snapclient

View File

@@ -0,0 +1,24 @@
[Unit]
Description=Streamdeck
After=multi-user.target
#Conflicts=getty@tty1.service
#After=graphical.target
#After = network.target
[Service]
#Type=simple
Type=idle
Restart=on-failure
#WorkingDirectory=/home/aqua
#User=aqua
#RemainAfterExit=true
ExecStart=/usr/bin/python /home/aqua/git/streamdeck/streamdeck.py
ExecStop=pkill -9 -f streamdeck.py
#StandardInput=tty-force
#StandardOutput=append:/home/aqua/streamdeck.log
#StandardError=append:/home/aqua/streamdeck.log
[Install]
WantedBy = multi-user.target

6
requirements.txt Normal file
View File

@@ -0,0 +1,6 @@
configparser
todoist-python
tbapy
holidays
i3ipc
pyautogui