commit 7d3dfb9c697a429f2df02b573da644a89d135b15 Author: jrosh Date: Fri May 30 16:25:30 2025 +0200 upload to github diff --git a/.bashrc b/.bashrc new file mode 100644 index 0000000..7151470 --- /dev/null +++ b/.bashrc @@ -0,0 +1,205 @@ +# ~/.bashrc: executed by bash(1) for non-login shells. +# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) + +# If not running interactively, don't do anything +case $- in + *i*) ;; + *) return;; +esac + +# Source bash aliases if available +if [ -f ~/.bash_aliases ]; then + . ~/.bash_aliases +fi + +# History configuration +HISTCONTROL=ignoreboth:erasedups # ignore duplicates and remove duplicates from history +HISTSIZE=10000 # increased from 1000 +HISTFILESIZE=20000 # increased from 2000 +HISTTIMEFORMAT="%F %T " # add timestamps to history +shopt -s histappend # append to history file, don't overwrite +shopt -s histverify # verify history expansions before executing + +# Shell options +shopt -s checkwinsize # update LINES and COLUMNS after each command +shopt -s cdspell # correct minor spelling errors in cd commands +shopt -s dirspell # correct minor spelling errors in directory names +shopt -s autocd # cd into directories by just typing the name + +# Make less more friendly for non-text input files +[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" + +# Set variable identifying the chroot (used in the prompt below) +if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then + debian_chroot=$(cat /etc/debian_chroot) +fi + +# Function to get git branch and status +git_prompt_info() { + local branch + if branch=$(git symbolic-ref --short HEAD 2>/dev/null); then + local status="" + local git_status=$(git status --porcelain 2>/dev/null) + + # Check for various git states + if [ -n "$git_status" ]; then + if echo "$git_status" | grep -q "^M"; then + status="${status}*" # modified files + fi + if echo "$git_status" | grep -q "^A"; then + status="${status}+" # added files + fi + if echo "$git_status" | grep -q "^D"; then + status="${status}-" # deleted files + fi + if echo "$git_status" | grep -q "^??"; then + status="${status}?" # untracked files + fi + fi + + # Check if we're ahead/behind remote + local ahead_behind + ahead_behind=$(git rev-list --count --left-right @{upstream}...HEAD 2>/dev/null) + if [ $? -eq 0 ]; then + local behind=$(echo "$ahead_behind" | cut -f1) + local ahead=$(echo "$ahead_behind" | cut -f2) + if [ "$ahead" -gt 0 ] && [ "$behind" -gt 0 ]; then + status="${status}⇅" + elif [ "$ahead" -gt 0 ]; then + status="${status}↑" + elif [ "$behind" -gt 0 ]; then + status="${status}↓" + fi + fi + printf " \001\033[93m\002(%s\001\033[91m\002%s\001\033[93m\002)\001\033[00m\002" "$branch" "$status" + fi +} + +# Set colored prompt based on terminal capability +case "$TERM" in + xterm-color|*-256color) color_prompt=yes;; +esac + +force_color_prompt=yes + +if [ -n "$force_color_prompt" ]; then + if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then + color_prompt=yes + else + color_prompt= + fi +fi + +# Configure prompt with git integration +if [ "$color_prompt" = yes ]; then + PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]$(git_prompt_info)\$ ' +else + PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w$(git_prompt_info)\$ ' +fi +unset color_prompt force_color_prompt + +# Set terminal title for xterm-compatible terminals +case "$TERM" in +xterm*|rxvt*) + PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" + ;; +*) + ;; +esac + +# Enable colored output for common commands +if [ -x /usr/bin/dircolors ]; then + test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" + alias ls='ls --color=auto' + alias grep='grep --color=auto' + alias fgrep='fgrep --color=auto' + alias egrep='egrep --color=auto' +fi + +# Colored GCC warnings and errors +export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' + +# GPG TTY configuration for proper GPG agent functionality +export GPG_TTY=$(tty) + +# Enable programmable completion features +if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + . /etc/bash_completion + fi +fi + +# Common useful aliases (add more to ~/.bash_aliases for user-specific ones) +alias ll='ls -alF' +alias la='ls -A' +alias l='ls -CF' +alias ..='cd ..' +alias ...='cd ../..' +alias ....='cd ../../..' +alias grep='grep --color=auto' +alias mkdir='mkdir -pv' +alias h='history' +alias c='clear' +alias df='df -h' +alias du='du -h' +alias free='free -h' +alias ps='ps auxf' +alias less='less -R' + +# Safety aliases +alias rm='rm -i' +alias cp='cp -i' +alias mv='mv -i' + +# Development shortcuts +alias g='git' +alias gs='git status' +alias ga='git add' +alias gc='git commit' +alias gp='git push' +alias gl='git log --oneline --graph --decorate' +alias gd='git diff' + +# Extract function for various archive types +extract() { + if [ -f "$1" ]; then + case $1 in + *.tar.bz2) tar xjf "$1" ;; + *.tar.gz) tar xzf "$1" ;; + *.bz2) bunzip2 "$1" ;; + *.rar) unar "$1" ;; + *.gz) gunzip "$1" ;; + *.tar) tar xf "$1" ;; + *.tbz2) tar xjf "$1" ;; + *.tgz) tar xzf "$1" ;; + *.zip) unzip "$1" ;; + *.Z) uncompress "$1" ;; + *.7z) 7z x "$1" ;; + *) echo "'$1' cannot be extracted via extract()" ;; + esac + else + echo "'$1' is not a valid file" + fi +} + +# Create directory and cd into it +mkcd() { + mkdir -p "$1" && cd "$1" +} + +# Find and kill process by name +psgrep() { + ps aux | grep -v grep | grep "$@" -i --color=auto +} + +# Quick backup function +backup() { + cp "$1"{,.bak} +} + +# Show PATH in readable format +path() { + echo $PATH | tr ':' '\n' +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..91f2b41 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 jroshthen1 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..9ff4826 --- /dev/null +++ b/Readme.md @@ -0,0 +1,14 @@ +# dotfiles + +My generic dotfiles + +`user@host:~/pwd/ (branch+?)$ ` + +## Extract archives +extract ~/Downloads/file.tar.gz, .zip, .7z, .rar + +## Check what's running +psgrep bash + +## Backup file +backup file.json \ No newline at end of file diff --git a/pwgen.sh b/pwgen.sh new file mode 100755 index 0000000..b586dc1 --- /dev/null +++ b/pwgen.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Function to generate a random password +generate_password() { + local length=$1 + if ! [[ "$length" =~ ^[0-9]+$ ]] || [ "$length" -le 0 ]; then + echo "Please provide a valid positive integer for password length." + exit 1 + fi + + local charset='A-Z:a-z:0-9:!@#$%^&*()_+[]{}|;:,.<>?' + # Generate the password + local password=$(cat /dev/urandom | tr -dc "$charset" | fold -w "$length" | head -n 1) + echo "$password" +} + +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi +generate_password "$1" diff --git a/scramble_email.sh b/scramble_email.sh new file mode 100644 index 0000000..292c252 --- /dev/null +++ b/scramble_email.sh @@ -0,0 +1,29 @@ +#!/bin/bash +if [ -z "$1" ]; then + read -p "Enter an email to scramble: " clean_email +elif [[ "$1" == "-h" || "$1" == "--help" ]]; then + echo 'Usage: scramble_email.sh [emailtoscramble] + +$ scramble_email.sh "address@email.com" + outputs: address at email dot com + +$ echo "address@email.com" | scramble_email.sh + outputs: address at email dot com + +$ xargs -I {} -a email_list.txt scramble_email.sh {} > scrambled_emails.txt + input a txt file with emails and scramble them into a new txt file +' +exit +else + clean_email="$1" +fi + +email_pattern="^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z.]{2,8}$" + +if [[ $clean_email =~ $email_pattern ]]; then + scrambled_email="${clean_email//./' dot '}" + scrambled_email="${scrambled_email//@/' at '}" + echo $scrambled_email +else +echo "Invalid email address. Please enter a valid email." +fi diff --git a/speak.sh b/speak.sh new file mode 100755 index 0000000..0a28d3d --- /dev/null +++ b/speak.sh @@ -0,0 +1,165 @@ +#!/bin/bash +# Chunked TTS processor - Divides text into chunks, processes and plays them sequentially + +EXEC_PATH="$HOME/kokoros/target/release/koko" +MODEL_PATH="$HOME/kokoros/checkpoints/kokoro-v1.0.onnx" +VOICE_DATA="$HOME/kokoros/voices-v1.0.bin" +SPEED=1.1 +VOICE_STYLE="af_heart" +# Style mixing supported for Kokoros: "af_sky.4+af_nicole.5" +# https://github.com/hexgrad/kokoro/tree/main/kokoro.js/voices + +# Chunking parameters +MIN_CHUNK_SIZE=80 +MAX_CHUNK_SIZE=200 +MIN_SENTENCES=2 + +export LC_ALL=en_US.UTF-8 +export LANG=en_US.UTF-8 + +clipboard_content=$(xclip -o) +filtered_content=$(echo "$clipboard_content" | sed -E ' + s/-(\r|\n)//g + s/\r|\n/ /g + s/ +/ /g + s/^ *//g + s/ *$//g + s/--/ — /g + s/ - / — /g + s/\.\.\./…/g + s/([0-9]),([0-9])/\1\2/g + s/([.,;:])([^ ])/\1 \2/g +') + +TEMP_DIR=$(mktemp -d) +echo "Using temporary directory: $TEMP_DIR" + +# Save the cleaned text to a file +echo "$filtered_content" > "$TEMP_DIR/full_text.txt" + +# Smart chunking: Split text into optimal chunks +cat "$TEMP_DIR/full_text.txt" | + sed -E 's/([.!?]) +/\1\n/g' | + awk -v min_size="$MIN_CHUNK_SIZE" -v max_size="$MAX_CHUNK_SIZE" -v min_sentences="$MIN_SENTENCES" ' + BEGIN { + chunk = ""; + sentence_count = 0; + } + + NF > 0 { + sentence = $0; + + if (length(chunk) > 0) { + test_chunk = chunk " " sentence; + } else { + test_chunk = sentence; + } + + should_output = 0; + + # If adding this sentence would exceed max size, output current chunk first + if (length(test_chunk) > max_size && length(chunk) > 0) { + should_output = 1; + } + # If we have minimum sentences and minimum size, we can output + else if (sentence_count >= min_sentences && length(chunk) >= min_size) { + if (length(sentence) > (max_size - min_size)) { + should_output = 1; + } + else if (length(test_chunk) >= min_size * 1.5) { + chunk = test_chunk; + sentence_count++; + should_output = 1; + } + } + + if (should_output && length(chunk) > 0) { + print chunk; + chunk = ""; + sentence_count = 0; + + if (length(test_chunk) > max_size) { + chunk = sentence; + sentence_count = 1; + } + } + else { + chunk = test_chunk; + sentence_count++; + } + } + + END { + if (length(chunk) > 0) { + print chunk; + } + }' > "$TEMP_DIR/chunks.txt" + +process_chunk() { + local chunk="$1" + local output_file="$2" + echo "Processing: ${chunk:0:40}..." + echo "$chunk" > "$TEMP_DIR/current_chunk.txt" + + "$EXEC_PATH" \ + --model "$MODEL_PATH" \ + --data "$VOICE_DATA" \ + --speed "$SPEED" \ + --style "$VOICE_STYLE" \ + text "$(cat "$TEMP_DIR/current_chunk.txt")" \ + --output "$output_file" + + if [ ! -f "$output_file" ]; then + echo "Error: Failed to create audio file for chunk. Skipping..." + return 1 + fi + + return 0 +} + +# Process the first chunk immediately +FIRST_CHUNK=$(head -n 1 "$TEMP_DIR/chunks.txt") +FIRST_OUTPUT="$TEMP_DIR/chunk_0.wav" +process_chunk "$FIRST_CHUNK" "$FIRST_OUTPUT" + +if [ -f "$FIRST_OUTPUT" ]; then + aplay "$FIRST_OUTPUT" & + PLAY_PID=$! +else + echo "Failed to process first chunk. Continuing with next chunks..." + PLAY_PID=0 +fi + +# Process remaining chunks +CHUNK_NUM=1 +while read -r chunk; do + if [ $CHUNK_NUM -eq 1 ]; then + CHUNK_NUM=$((CHUNK_NUM + 1)) + continue + fi + + OUTPUT_FILE="$TEMP_DIR/chunk_$CHUNK_NUM.wav" + + process_chunk "$chunk" "$OUTPUT_FILE" + + if [ $PLAY_PID -ne 0 ]; then + wait $PLAY_PID || true + fi + + if [ -f "$OUTPUT_FILE" ]; then + aplay "$OUTPUT_FILE" & + PLAY_PID=$! + else + echo "Skipping playback of chunk $CHUNK_NUM (file not created)" + PLAY_PID=0 + fi + + CHUNK_NUM=$((CHUNK_NUM + 1)) +done < "$TEMP_DIR/chunks.txt" + +if [ $PLAY_PID -ne 0 ]; then + wait $PLAY_PID || true +fi + +echo "Processing complete!" +rm -rf "$TEMP_DIR" \ No newline at end of file