A new start
This commit is contained in:
34
.editorconfig
Executable file
34
.editorconfig
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
# EditorConfig is awesome: https://editorconfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Unix-style newlines with a newline ending every file
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# Matches multiple files with brace expansion notation
|
||||||
|
# Set default charset
|
||||||
|
[*.{js,py}]
|
||||||
|
charset = utf-8
|
||||||
|
|
||||||
|
# 4 space indentation
|
||||||
|
[*.py]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
# Tab indentation (no size specified)
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
# Indentation override for all JS under lib directory
|
||||||
|
[lib/**.js]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# Matches the exact files either package.json or .travis.yml
|
||||||
|
[{package.json,.travis.yml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
16
.gitconfig
Executable file
16
.gitconfig
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
[user]
|
||||||
|
name = Sebastian Krüger
|
||||||
|
email = valknar@pivoine.art
|
||||||
|
[filter "lfs"]
|
||||||
|
clean = git-lfs clean -- %f
|
||||||
|
smudge = git-lfs smudge -- %f
|
||||||
|
process = git-lfs filter-process
|
||||||
|
required = true
|
||||||
|
[core]
|
||||||
|
editor = nano
|
||||||
|
[init]
|
||||||
|
defaultBranch = main
|
||||||
|
[alias]
|
||||||
|
squash-all = "!f(){ git reset $(git commit-tree \"HEAD^{tree}\" \"$@\");};f"
|
||||||
|
[push]
|
||||||
|
autoSetupRemote = true
|
||||||
55
.gitignore
vendored
Executable file
55
.gitignore
vendored
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
# Ignore everything
|
||||||
|
*
|
||||||
|
|
||||||
|
# But not these files.
|
||||||
|
!CLAUDE.md
|
||||||
|
!.gitignore
|
||||||
|
!.gitconfig
|
||||||
|
!.gitmodules
|
||||||
|
!README.md
|
||||||
|
!.editorconfig
|
||||||
|
!*.env
|
||||||
|
!.prettierrc
|
||||||
|
!.prettierignore
|
||||||
|
!package.json
|
||||||
|
!pnpm-workspace.yaml
|
||||||
|
!.nvmrc
|
||||||
|
!.ruby-version
|
||||||
|
!.python-version
|
||||||
|
!.pre-commit-config.yaml
|
||||||
|
!.rubocop.yml
|
||||||
|
!requirements.txt
|
||||||
|
!Gemfile
|
||||||
|
!ecosystem.config.js
|
||||||
|
!playbook.yml
|
||||||
|
!.p10k.zsh
|
||||||
|
!crates.yml
|
||||||
|
!flatpaks.yml
|
||||||
|
!eslint.config.mts
|
||||||
|
!.zprofile
|
||||||
|
!.zlogout
|
||||||
|
!.zlogin
|
||||||
|
!.zshrc
|
||||||
|
!.zshenv
|
||||||
|
!.hushlogin
|
||||||
|
!.last_pwd
|
||||||
|
!biome.json
|
||||||
|
!arty.yml
|
||||||
|
|
||||||
|
!/.github/
|
||||||
|
!/.github/**
|
||||||
|
|
||||||
|
!/.init/
|
||||||
|
!/.init/**
|
||||||
|
|
||||||
|
!.vscode/
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
|
||||||
|
# Ignore so we won't commit these in the allowed dirctories.
|
||||||
|
.DS_Store
|
||||||
|
*.log*
|
||||||
|
*.db*
|
||||||
|
*.vscdb*
|
||||||
|
*.sqlite*
|
||||||
|
*.bnk*
|
||||||
0
.hushlogin
Normal file
0
.hushlogin
Normal file
17
.init/alias.sh
Executable file
17
.init/alias.sh
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
alias ri='source ~/.init/init.sh'
|
||||||
|
|
||||||
|
# git
|
||||||
|
alias g0='git add . && git diff --quiet && git diff --cached --quiet'
|
||||||
|
alias g1='git reset $(git commit-tree "HEAD^{tree}" -m "A new start")'
|
||||||
|
alias g2='git log --format=%B -n 1 HEAD | head -n 1'
|
||||||
|
|
||||||
|
# rsync
|
||||||
|
alias rs='rsync --rsync-path="sudo rsync" -avzhe ssh'
|
||||||
|
|
||||||
|
# serve static files
|
||||||
|
alias ss='python -m http.server 8000 -d'
|
||||||
|
|
||||||
|
# download youtube mp3
|
||||||
|
alias yt='yt-dlp -x --audio-format mp3'
|
||||||
0
.init/bin/.gitkeep
Normal file
0
.init/bin/.gitkeep
Normal file
477
.init/bin/artifact_github_download.sh
Executable file
477
.init/bin/artifact_github_download.sh
Executable file
@@ -0,0 +1,477 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# GitHub Artifact Downloader
|
||||||
|
#
|
||||||
|
# Download and extract GitHub Actions artifacts with style
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# artifact_github_download.sh <REPO> [OPTIONS]
|
||||||
|
#
|
||||||
|
# Arguments:
|
||||||
|
# REPO GitHub repository (owner/repo)
|
||||||
|
#
|
||||||
|
# Options:
|
||||||
|
# -n, --name NAME Artifact name to download (preselect)
|
||||||
|
# -o, --output DIR Output directory (default: current directory)
|
||||||
|
# -h, --help Show this help message
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# artifact_github_download.sh valknarness/awesome
|
||||||
|
# artifact_github_download.sh valknarness/awesome -n awesome-database-latest
|
||||||
|
# artifact_github_download.sh valknarness/awesome -o ~/downloads
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Color Definitions
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Check if terminal supports colors
|
||||||
|
if [[ -t 1 ]] && command -v tput >/dev/null 2>&1; then
|
||||||
|
COLORS=$(tput colors 2>/dev/null || echo 0)
|
||||||
|
if [[ $COLORS -ge 8 ]]; then
|
||||||
|
# Standard colors
|
||||||
|
RED=$(tput setaf 1)
|
||||||
|
GREEN=$(tput setaf 2)
|
||||||
|
YELLOW=$(tput setaf 3)
|
||||||
|
BLUE=$(tput setaf 4)
|
||||||
|
MAGENTA=$(tput setaf 5)
|
||||||
|
CYAN=$(tput setaf 6)
|
||||||
|
WHITE=$(tput setaf 7)
|
||||||
|
|
||||||
|
# Bright colors
|
||||||
|
BRIGHT_GREEN=$(tput setaf 10 2>/dev/null || tput setaf 2)
|
||||||
|
BRIGHT_YELLOW=$(tput setaf 11 2>/dev/null || tput setaf 3)
|
||||||
|
BRIGHT_BLUE=$(tput setaf 12 2>/dev/null || tput setaf 4)
|
||||||
|
BRIGHT_MAGENTA=$(tput setaf 13 2>/dev/null || tput setaf 5)
|
||||||
|
BRIGHT_CYAN=$(tput setaf 14 2>/dev/null || tput setaf 6)
|
||||||
|
|
||||||
|
# Text formatting
|
||||||
|
BOLD=$(tput bold)
|
||||||
|
DIM=$(tput dim 2>/dev/null || echo "")
|
||||||
|
RESET=$(tput sgr0)
|
||||||
|
else
|
||||||
|
RED="" GREEN="" YELLOW="" BLUE="" MAGENTA="" CYAN="" WHITE=""
|
||||||
|
BRIGHT_GREEN="" BRIGHT_YELLOW="" BRIGHT_BLUE="" BRIGHT_MAGENTA="" BRIGHT_CYAN=""
|
||||||
|
BOLD="" DIM="" RESET=""
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
RED="" GREEN="" YELLOW="" BLUE="" MAGENTA="" CYAN="" WHITE=""
|
||||||
|
BRIGHT_GREEN="" BRIGHT_YELLOW="" BRIGHT_BLUE="" BRIGHT_MAGENTA="" BRIGHT_CYAN=""
|
||||||
|
BOLD="" DIM="" RESET=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Logging Functions
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
log_info() {
|
||||||
|
echo -e "${BRIGHT_BLUE}${BOLD}ℹ${RESET} ${CYAN}$*${RESET}" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
log_success() {
|
||||||
|
echo -e "${BRIGHT_GREEN}${BOLD}✓${RESET} ${GREEN}$*${RESET}" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warning() {
|
||||||
|
echo -e "${BRIGHT_YELLOW}${BOLD}⚠${RESET} ${YELLOW}$*${RESET}" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "${RED}${BOLD}✗${RESET} ${RED}$*${RESET}" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
log_step() {
|
||||||
|
echo -e "${BRIGHT_MAGENTA}${BOLD}▸${RESET} ${MAGENTA}$*${RESET}" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
log_header() {
|
||||||
|
local text="$*"
|
||||||
|
local length=${#text}
|
||||||
|
local line=$(printf '═%.0s' $(seq 1 $length))
|
||||||
|
echo "" >&2
|
||||||
|
echo -e "${BRIGHT_CYAN}${BOLD}╔${line}╗${RESET}" >&2
|
||||||
|
echo -e "${BRIGHT_CYAN}${BOLD}║${RESET}${BOLD}${WHITE}${text}${RESET}${BRIGHT_CYAN}${BOLD}║${RESET}" >&2
|
||||||
|
echo -e "${BRIGHT_CYAN}${BOLD}╚${line}╝${RESET}" >&2
|
||||||
|
echo "" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
log_data() {
|
||||||
|
local label="$1"
|
||||||
|
local value="$2"
|
||||||
|
echo -e " ${DIM}${label}:${RESET} ${BOLD}${value}${RESET}" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Helper Functions
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
check_dependencies() {
|
||||||
|
local missing=()
|
||||||
|
|
||||||
|
if ! command -v gh &> /dev/null; then
|
||||||
|
missing+=("gh (GitHub CLI)")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v jq &> /dev/null; then
|
||||||
|
missing+=("jq")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v unzip &> /dev/null; then
|
||||||
|
missing+=("unzip")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||||
|
log_error "Missing required dependencies:"
|
||||||
|
for dep in "${missing[@]}"; do
|
||||||
|
echo -e " ${RED}•${RESET} ${dep}"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_gh_auth() {
|
||||||
|
if ! gh auth status &> /dev/null; then
|
||||||
|
log_error "Not authenticated with GitHub CLI"
|
||||||
|
log_info "Run: ${BOLD}gh auth login${RESET}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
show_help() {
|
||||||
|
cat << EOF
|
||||||
|
${BOLD}${BRIGHT_CYAN}GitHub Artifact Downloader${RESET}
|
||||||
|
|
||||||
|
${BOLD}USAGE:${RESET}
|
||||||
|
$(basename "$0") ${CYAN}<REPO>${RESET} [${YELLOW}OPTIONS${RESET}]
|
||||||
|
|
||||||
|
${BOLD}ARGUMENTS:${RESET}
|
||||||
|
${CYAN}REPO${RESET} GitHub repository (${DIM}owner/repo${RESET})
|
||||||
|
|
||||||
|
${BOLD}OPTIONS:${RESET}
|
||||||
|
${YELLOW}-n, --name NAME${RESET} Artifact name to download (preselect)
|
||||||
|
${YELLOW}-o, --output DIR${RESET} Output directory (default: current directory)
|
||||||
|
${YELLOW}-h, --help${RESET} Show this help message
|
||||||
|
|
||||||
|
${BOLD}EXAMPLES:${RESET}
|
||||||
|
${DIM}# Interactive mode - list and select artifacts${RESET}
|
||||||
|
$(basename "$0") valknarness/awesome
|
||||||
|
|
||||||
|
${DIM}# Preselect artifact by name${RESET}
|
||||||
|
$(basename "$0") valknarness/awesome -n awesome-database-latest
|
||||||
|
|
||||||
|
${DIM}# Download to specific directory${RESET}
|
||||||
|
$(basename "$0") valknarness/awesome -o ~/downloads
|
||||||
|
|
||||||
|
${DIM}# Combine options${RESET}
|
||||||
|
$(basename "$0") valknarness/awesome -n awesome-database-latest -o ~/downloads
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
format_size() {
|
||||||
|
local bytes=$1
|
||||||
|
if (( bytes < 1024 )); then
|
||||||
|
echo "${bytes}B"
|
||||||
|
elif (( bytes < 1048576 )); then
|
||||||
|
awk "BEGIN {printf \"%.1fKB\", $bytes/1024}"
|
||||||
|
elif (( bytes < 1073741824 )); then
|
||||||
|
awk "BEGIN {printf \"%.1fMB\", $bytes/1048576}"
|
||||||
|
else
|
||||||
|
awk "BEGIN {printf \"%.2fGB\", $bytes/1073741824}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
format_date() {
|
||||||
|
local iso_date="$1"
|
||||||
|
if command -v date &> /dev/null; then
|
||||||
|
if date --version &> /dev/null 2>&1; then
|
||||||
|
# GNU date
|
||||||
|
date -d "$iso_date" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "$iso_date"
|
||||||
|
else
|
||||||
|
# BSD date (macOS)
|
||||||
|
date -j -f "%Y-%m-%dT%H:%M:%SZ" "$iso_date" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "$iso_date"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "$iso_date"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Main Functions
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
list_artifacts() {
|
||||||
|
local repo="$1"
|
||||||
|
|
||||||
|
log_step "Fetching artifacts from ${BOLD}${repo}${RESET}..."
|
||||||
|
|
||||||
|
# First check if there are any artifacts using gh's built-in jq
|
||||||
|
local count
|
||||||
|
count=$(gh api \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||||
|
--jq '.artifacts | length' \
|
||||||
|
"/repos/${repo}/actions/artifacts?per_page=100" 2>/dev/null)
|
||||||
|
|
||||||
|
if [[ -z "$count" ]]; then
|
||||||
|
log_error "Failed to fetch artifacts from repository"
|
||||||
|
log_info "Please check that:"
|
||||||
|
echo " • The repository ${BOLD}${repo}${RESET} exists and you have access"
|
||||||
|
echo " • GitHub Actions is enabled for this repository"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$count" -eq 0 ]]; then
|
||||||
|
log_warning "No artifacts found in repository ${BOLD}${repo}${RESET}"
|
||||||
|
log_info "This repository may not have any workflow runs that produced artifacts"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Now fetch the full JSON response
|
||||||
|
local artifacts_json
|
||||||
|
artifacts_json=$(gh api \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||||
|
"/repos/${repo}/actions/artifacts?per_page=100" 2>/dev/null)
|
||||||
|
|
||||||
|
echo "$artifacts_json"
|
||||||
|
}
|
||||||
|
|
||||||
|
select_artifact() {
|
||||||
|
local artifacts_json="$1"
|
||||||
|
local preselect_name="$2"
|
||||||
|
|
||||||
|
# Parse artifacts
|
||||||
|
local artifacts
|
||||||
|
artifacts=$(echo "$artifacts_json" | jq -r '.artifacts[] |
|
||||||
|
"\(.id)|\(.name)|\(.size_in_bytes)|\(.created_at)|\(.workflow_run.id)"')
|
||||||
|
|
||||||
|
# If preselect name is provided, find matching artifact
|
||||||
|
if [[ -n "$preselect_name" ]]; then
|
||||||
|
local selected
|
||||||
|
selected=$(echo "$artifacts" | grep -F "|${preselect_name}|" | head -1)
|
||||||
|
|
||||||
|
if [[ -z "$selected" ]]; then
|
||||||
|
log_error "Artifact '${BOLD}${preselect_name}${RESET}' not found"
|
||||||
|
log_info "Available artifacts:"
|
||||||
|
echo "$artifacts" | while IFS='|' read -r id name size created workflow; do
|
||||||
|
echo " ${CYAN}•${RESET} ${name}"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$selected"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Interactive selection
|
||||||
|
log_info "Available artifacts:"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
local i=1
|
||||||
|
local -a artifact_array
|
||||||
|
|
||||||
|
while IFS='|' read -r id name size created workflow; do
|
||||||
|
artifact_array+=("$id|$name|$size|$created|$workflow")
|
||||||
|
local formatted_size=$(format_size "$size")
|
||||||
|
local formatted_date=$(format_date "$created")
|
||||||
|
|
||||||
|
printf " ${BOLD}${YELLOW}[%2d]${RESET} ${BRIGHT_CYAN}%s${RESET}\n" "$i" "$name"
|
||||||
|
printf " ${DIM}Size: ${RESET}%s ${DIM}Created: ${RESET}%s\n" "$formatted_size" "$formatted_date"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
((i++))
|
||||||
|
done <<< "$artifacts"
|
||||||
|
|
||||||
|
# Prompt for selection
|
||||||
|
local selection
|
||||||
|
while true; do
|
||||||
|
echo -n -e "${BRIGHT_MAGENTA}${BOLD}<EFBFBD>${RESET} ${MAGENTA}Select artifact [1-$((i-1))]:${RESET} "
|
||||||
|
read -r selection
|
||||||
|
|
||||||
|
if [[ "$selection" =~ ^[0-9]+$ ]] && [[ "$selection" -ge 1 ]] && [[ "$selection" -lt "$i" ]]; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
log_warning "Invalid selection. Please enter a number between 1 and $((i-1))"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "${artifact_array[$((selection-1))]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
download_artifact() {
|
||||||
|
local repo="$1"
|
||||||
|
local artifact_id="$2"
|
||||||
|
local artifact_name="$3"
|
||||||
|
local output_dir="$4"
|
||||||
|
|
||||||
|
log_step "Downloading artifact ${BOLD}${artifact_name}${RESET}..."
|
||||||
|
|
||||||
|
# Create output directory if it doesn't exist
|
||||||
|
mkdir -p "$output_dir"
|
||||||
|
|
||||||
|
# Download artifact using gh
|
||||||
|
local zip_file="${output_dir}/${artifact_name}.zip"
|
||||||
|
|
||||||
|
if gh api \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||||
|
"/repos/${repo}/actions/artifacts/${artifact_id}/zip" \
|
||||||
|
> "$zip_file" 2>/dev/null; then
|
||||||
|
|
||||||
|
log_success "Downloaded to ${BOLD}${zip_file}${RESET}"
|
||||||
|
echo "$zip_file"
|
||||||
|
else
|
||||||
|
log_error "Failed to download artifact"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_artifact() {
|
||||||
|
local zip_file="$1"
|
||||||
|
local output_dir="$2"
|
||||||
|
|
||||||
|
log_step "Extracting archive..."
|
||||||
|
|
||||||
|
# Create extraction directory
|
||||||
|
local extract_dir="${output_dir}/$(basename "$zip_file" .zip)"
|
||||||
|
mkdir -p "$extract_dir"
|
||||||
|
|
||||||
|
if unzip -q "$zip_file" -d "$extract_dir"; then
|
||||||
|
log_success "Extracted to ${BOLD}${extract_dir}${RESET}"
|
||||||
|
|
||||||
|
# Show extracted files
|
||||||
|
log_info "Extracted files:"
|
||||||
|
find "$extract_dir" -type f -exec basename {} \; | while read -r file; do
|
||||||
|
echo " ${GREEN}•${RESET} ${file}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Remove zip file
|
||||||
|
rm "$zip_file"
|
||||||
|
log_info "Cleaned up zip file"
|
||||||
|
|
||||||
|
echo "$extract_dir"
|
||||||
|
else
|
||||||
|
log_error "Failed to extract archive"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Main Script
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
main() {
|
||||||
|
local repo=""
|
||||||
|
local artifact_name=""
|
||||||
|
local output_dir="."
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-h|--help)
|
||||||
|
show_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-n|--name)
|
||||||
|
artifact_name="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-o|--output)
|
||||||
|
output_dir="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
log_error "Unknown option: $1"
|
||||||
|
echo ""
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ -z "$repo" ]]; then
|
||||||
|
repo="$1"
|
||||||
|
else
|
||||||
|
log_error "Unexpected argument: $1"
|
||||||
|
echo ""
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Validate required arguments
|
||||||
|
if [[ -z "$repo" ]]; then
|
||||||
|
log_error "Repository argument is required"
|
||||||
|
echo ""
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate repository format
|
||||||
|
if [[ ! "$repo" =~ ^[^/]+/[^/]+$ ]]; then
|
||||||
|
log_error "Invalid repository format. Expected: ${BOLD}owner/repo${RESET}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show header
|
||||||
|
log_header "GitHub Artifact Downloader"
|
||||||
|
|
||||||
|
# Check dependencies
|
||||||
|
log_step "Checking dependencies..."
|
||||||
|
check_dependencies
|
||||||
|
log_success "All dependencies found"
|
||||||
|
|
||||||
|
# Check GitHub authentication
|
||||||
|
log_step "Checking GitHub authentication..."
|
||||||
|
check_gh_auth
|
||||||
|
log_success "Authenticated with GitHub"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_data "Repository" "${BRIGHT_CYAN}${repo}${RESET}"
|
||||||
|
if [[ -n "$artifact_name" ]]; then
|
||||||
|
log_data "Artifact" "${BRIGHT_YELLOW}${artifact_name}${RESET}"
|
||||||
|
fi
|
||||||
|
log_data "Output" "${BRIGHT_GREEN}${output_dir}${RESET}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# List artifacts
|
||||||
|
local artifacts_json
|
||||||
|
artifacts_json=$(list_artifacts "$repo")
|
||||||
|
|
||||||
|
# Select artifact
|
||||||
|
local selected
|
||||||
|
selected=$(select_artifact "$artifacts_json" "$artifact_name")
|
||||||
|
|
||||||
|
IFS='|' read -r artifact_id name size created workflow <<< "$selected"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_info "Selected artifact:"
|
||||||
|
log_data " Name" "${BRIGHT_CYAN}${name}${RESET}"
|
||||||
|
log_data " Size" "$(format_size "$size")"
|
||||||
|
log_data " Created" "$(format_date "$created")"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Download artifact
|
||||||
|
local zip_file
|
||||||
|
zip_file=$(download_artifact "$repo" "$artifact_id" "$name" "$output_dir")
|
||||||
|
|
||||||
|
# Extract artifact
|
||||||
|
local extract_dir
|
||||||
|
extract_dir=$(extract_artifact "$zip_file" "$output_dir")
|
||||||
|
|
||||||
|
# Success summary
|
||||||
|
echo ""
|
||||||
|
log_header "Download Complete!"
|
||||||
|
log_data "Location" "${BOLD}${extract_dir}${RESET}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
log_success "All done! 🎉"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main "$@"
|
||||||
592
.init/bin/mime_mp4_gif.sh
Executable file
592
.init/bin/mime_mp4_gif.sh
Executable file
@@ -0,0 +1,592 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# mime_mp4_gif.sh - Advanced MP4 to Animated GIF converter
|
||||||
|
# Converts MP4 videos to GIFs with sophisticated keyframe extraction,
|
||||||
|
# interpolation algorithms, and scheduling distributions
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
KEYFRAMES=10
|
||||||
|
INPUT_SCHEDULES=1
|
||||||
|
TRANSITION="linear"
|
||||||
|
SCHEDULE="uniform"
|
||||||
|
MAGIC="none"
|
||||||
|
KEYFRAME_DURATION=100
|
||||||
|
INPUT_FILE=""
|
||||||
|
OUTPUT_FILE=""
|
||||||
|
VERBOSE=false
|
||||||
|
|
||||||
|
# Color codes for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Available algorithms
|
||||||
|
TRANSITIONS=("linear" "sinoid" "cubic" "quadratic" "exponential" "bounce" "elastic")
|
||||||
|
SCHEDULES=("uniform" "front-load" "back-load" "center-peak" "edge-peak" "fibonacci" "golden-ratio")
|
||||||
|
MAGICS=("none" "psychedelic" "dither-bloom" "edge-glow" "temporal-blur" "chromatic-shift" "vaporwave")
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Helper Functions
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
print_usage() {
|
||||||
|
cat << EOF
|
||||||
|
Usage: $(basename "$0") [OPTIONS] INPUT_FILE [OUTPUT_FILE]
|
||||||
|
|
||||||
|
Convert MP4 videos to animated GIFs with advanced frame extraction algorithms.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
INPUT_FILE Input MP4 video file (required)
|
||||||
|
OUTPUT_FILE Output GIF file (optional, defaults to INPUT_FILE.gif)
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-k, --keyframes N Number of keyframes to extract (default: 10)
|
||||||
|
-d, --keyframe-duration MS Duration of each frame in milliseconds (default: 100)
|
||||||
|
Valid range: 1-30000 ms
|
||||||
|
Lower values = faster animation
|
||||||
|
Higher values = slower animation
|
||||||
|
-i, --input-schedules N Number of input schedules (default: 1)
|
||||||
|
1 schedule = entire video duration
|
||||||
|
N schedules = divide video into N segments
|
||||||
|
-t, --transition TYPE Interpolation function for frame timing
|
||||||
|
Available: ${TRANSITIONS[*]}
|
||||||
|
(default: linear)
|
||||||
|
-s, --schedule TYPE Algorithm to distribute keyframes across schedules
|
||||||
|
Available: ${SCHEDULES[*]}
|
||||||
|
(default: uniform)
|
||||||
|
-m, --magic TYPE Apply magical effects to the GIF
|
||||||
|
Available: ${MAGICS[*]}
|
||||||
|
(default: none)
|
||||||
|
-v, --verbose Enable verbose output
|
||||||
|
-h, --help Show this help message
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
# Basic conversion with 15 keyframes
|
||||||
|
$(basename "$0") -k 15 video.mp4
|
||||||
|
|
||||||
|
# Fast animation with 50ms per frame
|
||||||
|
$(basename "$0") -k 20 -d 50 video.mp4
|
||||||
|
|
||||||
|
# Slow animation with 500ms per frame
|
||||||
|
$(basename "$0") -k 10 -d 500 video.mp4
|
||||||
|
|
||||||
|
# Use sinusoidal transition with center-peak distribution
|
||||||
|
$(basename "$0") -t sinoid -s center-peak -k 20 video.mp4
|
||||||
|
|
||||||
|
# Apply psychedelic magic with fibonacci distribution
|
||||||
|
$(basename "$0") -m psychedelic -s fibonacci -k 13 video.mp4 trippy.gif
|
||||||
|
|
||||||
|
# Complex: 3 schedules with cubic interpolation and edge glow
|
||||||
|
$(basename "$0") -i 3 -t cubic -s front-load -m edge-glow -k 30 video.mp4
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info() {
|
||||||
|
echo -e "${BLUE}[INFO]${NC} $*"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_success() {
|
||||||
|
echo -e "${GREEN}[SUCCESS]${NC} $*"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warning() {
|
||||||
|
echo -e "${YELLOW}[WARNING]${NC} $*"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
verbose_log() {
|
||||||
|
if [[ "$VERBOSE" == "true" ]]; then
|
||||||
|
log_info "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_enum() {
|
||||||
|
local value="$1"
|
||||||
|
local array_name="$2"
|
||||||
|
local -n arr=$array_name
|
||||||
|
|
||||||
|
for item in "${arr[@]}"; do
|
||||||
|
if [[ "$value" == "$item" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Mathematical Functions
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
# Calculate transition weight based on interpolation type
|
||||||
|
# Input: progress (0.0 to 1.0), Returns: weighted value (0.0 to 1.0)
|
||||||
|
calculate_transition() {
|
||||||
|
local progress="$1"
|
||||||
|
local type="$2"
|
||||||
|
|
||||||
|
case "$type" in
|
||||||
|
linear)
|
||||||
|
echo "$progress"
|
||||||
|
;;
|
||||||
|
sinoid)
|
||||||
|
# Smooth sinusoidal easing
|
||||||
|
awk -v p="$progress" 'BEGIN { print (1 - cos(p * 3.14159265359)) / 2 }'
|
||||||
|
;;
|
||||||
|
cubic)
|
||||||
|
# Cubic easing in-out
|
||||||
|
awk -v p="$progress" 'BEGIN {
|
||||||
|
if (p < 0.5)
|
||||||
|
print 4 * p * p * p;
|
||||||
|
else
|
||||||
|
print 1 - ((-2 * p + 2) ^ 3) / 2;
|
||||||
|
}'
|
||||||
|
;;
|
||||||
|
quadratic)
|
||||||
|
# Quadratic easing
|
||||||
|
awk -v p="$progress" 'BEGIN {
|
||||||
|
if (p < 0.5)
|
||||||
|
print 2 * p * p;
|
||||||
|
else
|
||||||
|
print 1 - ((-2 * p + 2) ^ 2) / 2;
|
||||||
|
}'
|
||||||
|
;;
|
||||||
|
exponential)
|
||||||
|
# Exponential easing
|
||||||
|
awk -v p="$progress" 'BEGIN {
|
||||||
|
if (p == 0) print 0;
|
||||||
|
else if (p == 1) print 1;
|
||||||
|
else if (p < 0.5) print (2 ^ (20 * p - 10)) / 2;
|
||||||
|
else print (2 - (2 ^ (-20 * p + 10))) / 2;
|
||||||
|
}'
|
||||||
|
;;
|
||||||
|
bounce)
|
||||||
|
# Bouncing effect
|
||||||
|
awk -v p="$progress" 'BEGIN {
|
||||||
|
n1 = 7.5625; d1 = 2.75;
|
||||||
|
x = 1 - p;
|
||||||
|
if (x < 1/d1) result = n1 * x * x;
|
||||||
|
else if (x < 2/d1) { x -= 1.5/d1; result = n1 * x * x + 0.75; }
|
||||||
|
else if (x < 2.5/d1) { x -= 2.25/d1; result = n1 * x * x + 0.9375; }
|
||||||
|
else { x -= 2.625/d1; result = n1 * x * x + 0.984375; }
|
||||||
|
print 1 - result;
|
||||||
|
}'
|
||||||
|
;;
|
||||||
|
elastic)
|
||||||
|
# Elastic spring effect
|
||||||
|
awk -v p="$progress" 'BEGIN {
|
||||||
|
c4 = (2 * 3.14159265359) / 3;
|
||||||
|
if (p == 0) print 0;
|
||||||
|
else if (p == 1) print 1;
|
||||||
|
else if (p < 0.5) print -(2 ^ (20 * p - 10) * sin((20 * p - 11.125) * c4)) / 2;
|
||||||
|
else print (2 ^ (-20 * p + 10) * sin((20 * p - 11.125) * c4)) / 2 + 1;
|
||||||
|
}'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "$progress"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate keyframe distribution based on schedule type
|
||||||
|
generate_schedule_distribution() {
|
||||||
|
local num_frames="$1"
|
||||||
|
local schedule_type="$2"
|
||||||
|
local -n result_array=$3
|
||||||
|
|
||||||
|
case "$schedule_type" in
|
||||||
|
uniform)
|
||||||
|
for ((i=0; i<num_frames; i++)); do
|
||||||
|
result_array[$i]=$(awk -v i="$i" -v n="$num_frames" 'BEGIN { print i / (n - 1) }')
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
front-load)
|
||||||
|
# More frames at the beginning
|
||||||
|
for ((i=0; i<num_frames; i++)); do
|
||||||
|
local t=$(awk -v i="$i" -v n="$num_frames" 'BEGIN { print i / (n - 1) }')
|
||||||
|
result_array[$i]=$(awk -v t="$t" 'BEGIN { print t * t }')
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
back-load)
|
||||||
|
# More frames at the end
|
||||||
|
for ((i=0; i<num_frames; i++)); do
|
||||||
|
local t=$(awk -v i="$i" -v n="$num_frames" 'BEGIN { print i / (n - 1) }')
|
||||||
|
result_array[$i]=$(awk -v t="$t" 'BEGIN { print 1 - (1 - t) * (1 - t) }')
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
center-peak)
|
||||||
|
# More frames in the middle
|
||||||
|
for ((i=0; i<num_frames; i++)); do
|
||||||
|
local t=$(awk -v i="$i" -v n="$num_frames" 'BEGIN { print i / (n - 1) }')
|
||||||
|
result_array[$i]=$(awk -v t="$t" 'BEGIN { print 1 - 4 * (t - 0.5) * (t - 0.5) }')
|
||||||
|
result_array[$i]=$(awk -v val="${result_array[$i]}" -v t="$t" 'BEGIN { print t }')
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
edge-peak)
|
||||||
|
# More frames at start and end
|
||||||
|
for ((i=0; i<num_frames; i++)); do
|
||||||
|
local t=$(awk -v i="$i" -v n="$num_frames" 'BEGIN { print i / (n - 1) }')
|
||||||
|
result_array[$i]=$(awk -v t="$t" 'BEGIN { print 4 * (t - 0.5) * (t - 0.5) }')
|
||||||
|
result_array[$i]=$(awk -v val="${result_array[$i]}" -v t="$t" 'BEGIN { print t }')
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
fibonacci)
|
||||||
|
# Fibonacci sequence distribution
|
||||||
|
local fib=(1 1)
|
||||||
|
for ((i=2; i<num_frames; i++)); do
|
||||||
|
fib[$i]=$((fib[i-1] + fib[i-2]))
|
||||||
|
done
|
||||||
|
local sum=0
|
||||||
|
for val in "${fib[@]}"; do
|
||||||
|
((sum += val))
|
||||||
|
done
|
||||||
|
local cumsum=0
|
||||||
|
for ((i=0; i<num_frames; i++)); do
|
||||||
|
((cumsum += fib[i]))
|
||||||
|
result_array[$i]=$(awk -v c="$cumsum" -v s="$sum" 'BEGIN { print c / s }')
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
golden-ratio)
|
||||||
|
# Golden ratio distribution
|
||||||
|
local phi=1.618033988749895
|
||||||
|
for ((i=0; i<num_frames; i++)); do
|
||||||
|
result_array[$i]=$(awk -v i="$i" -v n="$num_frames" -v phi="$phi" 'BEGIN {
|
||||||
|
print ((i * phi) - int(i * phi))
|
||||||
|
}')
|
||||||
|
done
|
||||||
|
# Sort the array for monotonic distribution
|
||||||
|
IFS=$'\n' result_array=($(sort -n <<<"${result_array[*]}"))
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Default to uniform
|
||||||
|
for ((i=0; i<num_frames; i++)); do
|
||||||
|
result_array[$i]=$(awk -v i="$i" -v n="$num_frames" 'BEGIN { print i / (n - 1) }')
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Video Processing Functions
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
get_video_duration() {
|
||||||
|
local file="$1"
|
||||||
|
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_frames() {
|
||||||
|
local input="$1"
|
||||||
|
local duration="$2"
|
||||||
|
local -n ts_ref=$3
|
||||||
|
local temp_dir="$4"
|
||||||
|
|
||||||
|
verbose_log "Extracting ${#ts_ref[@]} frames from video..."
|
||||||
|
|
||||||
|
for i in "${!ts_ref[@]}"; do
|
||||||
|
local time="${ts_ref[$i]}"
|
||||||
|
verbose_log " Frame $((i+1)): ${time}s"
|
||||||
|
|
||||||
|
ffmpeg -v quiet -ss "$time" -i "$input" -vframes 1 \
|
||||||
|
-vf "scale=480:-1:flags=lanczos" \
|
||||||
|
"${temp_dir}/frame_$(printf "%04d" "$i").png" 2>/dev/null
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_magic_effects() {
|
||||||
|
local magic_type="$1"
|
||||||
|
local temp_dir="$2"
|
||||||
|
|
||||||
|
if [[ "$magic_type" == "none" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
verbose_log "Applying magic effect: $magic_type"
|
||||||
|
|
||||||
|
case "$magic_type" in
|
||||||
|
psychedelic)
|
||||||
|
for frame in "$temp_dir"/*.png; do
|
||||||
|
ffmpeg -v quiet -i "$frame" -vf "hue=s=3:h=sin(2*PI*t)*360" \
|
||||||
|
"${frame}.tmp.png" 2>/dev/null && mv "${frame}.tmp.png" "$frame"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
dither-bloom)
|
||||||
|
for frame in "$temp_dir"/*.png; do
|
||||||
|
ffmpeg -v quiet -i "$frame" -vf "format=gbrp,split[a][b],[a]negate[c],[b][c]blend=all_mode=xor,noise=alls=20:allf=t" \
|
||||||
|
"${frame}.tmp.png" 2>/dev/null && mv "${frame}.tmp.png" "$frame"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
edge-glow)
|
||||||
|
for frame in "$temp_dir"/*.png; do
|
||||||
|
ffmpeg -v quiet -i "$frame" -vf "edgedetect=low=0.1:high=0.3,negate,hue=s=2" \
|
||||||
|
"${temp_dir}/edges_$(basename "$frame")"
|
||||||
|
ffmpeg -v quiet -i "$frame" -i "${temp_dir}/edges_$(basename "$frame")" \
|
||||||
|
-filter_complex "[0:v][1:v]blend=all_mode=addition:all_opacity=0.5" \
|
||||||
|
"${frame}.tmp.png" 2>/dev/null && mv "${frame}.tmp.png" "$frame"
|
||||||
|
rm "${temp_dir}/edges_$(basename "$frame")"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
temporal-blur)
|
||||||
|
# Create motion blur effect
|
||||||
|
local frames=("$temp_dir"/*.png)
|
||||||
|
for i in "${!frames[@]}"; do
|
||||||
|
local prev_idx=$((i > 0 ? i - 1 : 0))
|
||||||
|
local next_idx=$((i < ${#frames[@]} - 1 ? i + 1 : ${#frames[@]} - 1))
|
||||||
|
|
||||||
|
ffmpeg -v quiet -i "${frames[$prev_idx]}" -i "${frames[$i]}" -i "${frames[$next_idx]}" \
|
||||||
|
-filter_complex "[0:v][1:v][2:v]blend=all_mode=average" \
|
||||||
|
"${frames[$i]}.tmp.png" 2>/dev/null && mv "${frames[$i]}.tmp.png" "${frames[$i]}"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
chromatic-shift)
|
||||||
|
for frame in "$temp_dir"/*.png; do
|
||||||
|
ffmpeg -v quiet -i "$frame" -vf "rgbashift=rh=5:bh=-5" \
|
||||||
|
"${frame}.tmp.png" 2>/dev/null && mv "${frame}.tmp.png" "$frame"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
vaporwave)
|
||||||
|
for frame in "$temp_dir"/*.png; do
|
||||||
|
ffmpeg -v quiet -i "$frame" -vf "curves=vintage,hue=h=300:s=1.5,eq=saturation=1.5:contrast=1.2" \
|
||||||
|
"${frame}.tmp.png" 2>/dev/null && mv "${frame}.tmp.png" "$frame"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
create_gif() {
|
||||||
|
local temp_dir="$1"
|
||||||
|
local output="$2"
|
||||||
|
local frame_delay="$3"
|
||||||
|
|
||||||
|
verbose_log "Creating animated GIF with ${frame_delay}ms per frame..."
|
||||||
|
|
||||||
|
# Convert milliseconds to centiseconds (GIF delay unit)
|
||||||
|
local delay_cs
|
||||||
|
delay_cs=$(awk -v ms="$frame_delay" 'BEGIN { print int(ms / 10) }')
|
||||||
|
|
||||||
|
# Ensure minimum delay of 1 centisecond
|
||||||
|
if [[ $delay_cs -lt 1 ]]; then
|
||||||
|
delay_cs=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Calculate input framerate (frames are read at this rate)
|
||||||
|
# For GIF delay, we want 1000ms / frame_delay fps
|
||||||
|
local fps
|
||||||
|
fps=$(awk -v ms="$frame_delay" 'BEGIN { printf "%.2f", 1000.0 / ms }')
|
||||||
|
|
||||||
|
verbose_log "Frame delay: ${delay_cs} centiseconds (${frame_delay}ms), FPS: ${fps}"
|
||||||
|
|
||||||
|
# Generate palette for better color quality
|
||||||
|
ffmpeg -v error -pattern_type glob -i "${temp_dir}/frame_*.png" \
|
||||||
|
-vf "scale=480:-1:flags=lanczos,palettegen=stats_mode=diff" \
|
||||||
|
-y "${temp_dir}/palette.png"
|
||||||
|
|
||||||
|
# Create GIF using palette with specified frame delay
|
||||||
|
ffmpeg -v error -framerate "$fps" -pattern_type glob -i "${temp_dir}/frame_*.png" -i "${temp_dir}/palette.png" \
|
||||||
|
-filter_complex "[0:v]scale=480:-1:flags=lanczos[scaled];[scaled][1:v]paletteuse=dither=bayer:bayer_scale=5" \
|
||||||
|
-gifflags +transdiff -y "$output"
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Main Processing
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
process_video() {
|
||||||
|
local input="$INPUT_FILE"
|
||||||
|
local output="$OUTPUT_FILE"
|
||||||
|
|
||||||
|
# Validate input file
|
||||||
|
if [[ ! -f "$input" ]]; then
|
||||||
|
log_error "Input file not found: $input"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get video duration
|
||||||
|
local duration
|
||||||
|
duration=$(get_video_duration "$input")
|
||||||
|
verbose_log "Video duration: ${duration}s"
|
||||||
|
|
||||||
|
# Calculate schedule duration
|
||||||
|
local schedule_duration
|
||||||
|
schedule_duration=$(awk -v d="$duration" -v s="$INPUT_SCHEDULES" 'BEGIN { print d / s }')
|
||||||
|
verbose_log "Schedule duration: ${schedule_duration}s (${INPUT_SCHEDULES} schedule(s))"
|
||||||
|
|
||||||
|
# Generate frame distribution
|
||||||
|
local -a distribution
|
||||||
|
generate_schedule_distribution "$KEYFRAMES" "$SCHEDULE" distribution
|
||||||
|
|
||||||
|
verbose_log "Using schedule: $SCHEDULE"
|
||||||
|
verbose_log "Using transition: $TRANSITION"
|
||||||
|
|
||||||
|
# Calculate actual timestamps with transition function
|
||||||
|
local -a timestamps
|
||||||
|
for i in "${!distribution[@]}"; do
|
||||||
|
local base_time="${distribution[$i]}"
|
||||||
|
local weighted_time
|
||||||
|
weighted_time=$(calculate_transition "$base_time" "$TRANSITION")
|
||||||
|
|
||||||
|
# Map to video duration considering input schedules
|
||||||
|
local actual_time
|
||||||
|
actual_time=$(awk -v w="$weighted_time" -v d="$duration" 'BEGIN { print w * d }')
|
||||||
|
|
||||||
|
# Ensure we don't exceed video duration
|
||||||
|
timestamps[$i]=$(awk -v t="$actual_time" -v d="$duration" 'BEGIN {
|
||||||
|
if (t > d) print d;
|
||||||
|
else print t;
|
||||||
|
}')
|
||||||
|
done
|
||||||
|
|
||||||
|
# Create temporary directory
|
||||||
|
local temp_dir
|
||||||
|
temp_dir=$(mktemp -d)
|
||||||
|
trap "rm -rf '$temp_dir'" EXIT
|
||||||
|
|
||||||
|
# Extract frames
|
||||||
|
extract_frames "$input" "$duration" timestamps "$temp_dir"
|
||||||
|
|
||||||
|
# Apply magic effects
|
||||||
|
apply_magic_effects "$MAGIC" "$temp_dir"
|
||||||
|
|
||||||
|
# Create GIF with specified frame duration
|
||||||
|
create_gif "$temp_dir" "$output" "$KEYFRAME_DURATION"
|
||||||
|
|
||||||
|
log_success "GIF created successfully: $output"
|
||||||
|
|
||||||
|
# Show file size
|
||||||
|
local size
|
||||||
|
size=$(du -h "$output" | cut -f1)
|
||||||
|
log_info "Output size: $size"
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Command Line Parsing
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
parse_arguments() {
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-k|--keyframes)
|
||||||
|
KEYFRAMES="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-d|--keyframe-duration)
|
||||||
|
KEYFRAME_DURATION="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-i|--input-schedules)
|
||||||
|
INPUT_SCHEDULES="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-t|--transition)
|
||||||
|
TRANSITION="$2"
|
||||||
|
if ! validate_enum "$TRANSITION" TRANSITIONS; then
|
||||||
|
log_error "Invalid transition type: $TRANSITION"
|
||||||
|
log_error "Available: ${TRANSITIONS[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-s|--schedule)
|
||||||
|
SCHEDULE="$2"
|
||||||
|
if ! validate_enum "$SCHEDULE" SCHEDULES; then
|
||||||
|
log_error "Invalid schedule type: $SCHEDULE"
|
||||||
|
log_error "Available: ${SCHEDULES[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-m|--magic)
|
||||||
|
MAGIC="$2"
|
||||||
|
if ! validate_enum "$MAGIC" MAGICS; then
|
||||||
|
log_error "Invalid magic type: $MAGIC"
|
||||||
|
log_error "Available: ${MAGICS[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-v|--verbose)
|
||||||
|
VERBOSE=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
print_usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
log_error "Unknown option: $1"
|
||||||
|
print_usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ -z "$INPUT_FILE" ]]; then
|
||||||
|
INPUT_FILE="$1"
|
||||||
|
elif [[ -z "$OUTPUT_FILE" ]]; then
|
||||||
|
OUTPUT_FILE="$1"
|
||||||
|
else
|
||||||
|
log_error "Too many arguments"
|
||||||
|
print_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Validate required arguments
|
||||||
|
if [[ -z "$INPUT_FILE" ]]; then
|
||||||
|
log_error "Input file is required"
|
||||||
|
print_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set default output file
|
||||||
|
if [[ -z "$OUTPUT_FILE" ]]; then
|
||||||
|
OUTPUT_FILE="${INPUT_FILE%.*}.gif"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate numeric arguments
|
||||||
|
if ! [[ "$KEYFRAMES" =~ ^[0-9]+$ ]] || [[ "$KEYFRAMES" -lt 2 ]]; then
|
||||||
|
log_error "Keyframes must be a positive integer >= 2"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [[ "$KEYFRAME_DURATION" =~ ^[0-9]+$ ]] || [[ "$KEYFRAME_DURATION" -lt 1 ]] || [[ "$KEYFRAME_DURATION" -gt 30000 ]]; then
|
||||||
|
log_error "Keyframe duration must be an integer between 1 and 30000 milliseconds"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [[ "$INPUT_SCHEDULES" =~ ^[0-9]+$ ]] || [[ "$INPUT_SCHEDULES" -lt 1 ]]; then
|
||||||
|
log_error "Input schedules must be a positive integer >= 1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Entry Point
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
main() {
|
||||||
|
parse_arguments "$@"
|
||||||
|
|
||||||
|
log_info "Starting MP4 to GIF conversion..."
|
||||||
|
log_info "Configuration:"
|
||||||
|
log_info " Input: $INPUT_FILE"
|
||||||
|
log_info " Output: $OUTPUT_FILE"
|
||||||
|
log_info " Keyframes: $KEYFRAMES"
|
||||||
|
log_info " Frame Duration: ${KEYFRAME_DURATION}ms"
|
||||||
|
log_info " Schedules: $INPUT_SCHEDULES"
|
||||||
|
log_info " Transition: $TRANSITION"
|
||||||
|
log_info " Schedule: $SCHEDULE"
|
||||||
|
log_info " Magic: $MAGIC"
|
||||||
|
|
||||||
|
process_video
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main "$@"
|
||||||
13
.init/eval.sh
Executable file
13
.init/eval.sh
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if command -v oh-my-posh 2>&1 >/dev/null; then
|
||||||
|
eval "$(! oh-my-posh init zsh --config=~/worker.omp.json)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v rbenv 2>&1 >/dev/null; then
|
||||||
|
eval "$(rbenv init - --no-rehash zsh)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v pyenv 2>&1 >/dev/null; then
|
||||||
|
eval "$(pyenv init --path)"
|
||||||
|
fi
|
||||||
5
.init/export.sh
Executable file
5
.init/export.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export NVM_DIR="$HOME/.nvm"
|
||||||
|
export REPOS_DIR="$HOME/repos"
|
||||||
|
export CHORE_CHORE="chore: chore"
|
||||||
116
.init/functions.sh
Executable file
116
.init/functions.sh
Executable file
@@ -0,0 +1,116 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
is_ssh() {
|
||||||
|
IS_SSH=$(cat /proc/$PPID/status | head -1 | cut -f2)
|
||||||
|
if [ "$_IS_SSH" = "sshd-session" ]; then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_home_push() {
|
||||||
|
git add -A
|
||||||
|
git commit -m "${1:-$CHORE_CHORE}"
|
||||||
|
git push $2 $3
|
||||||
|
}
|
||||||
|
|
||||||
|
_home_pull() {
|
||||||
|
[ -n $(is_ssh) ] && git checkout $HOME/.last_pwd
|
||||||
|
git stash
|
||||||
|
git pull $1 $2
|
||||||
|
git stash pop
|
||||||
|
}
|
||||||
|
|
||||||
|
_site_deploy_jekyll() {
|
||||||
|
cd "$HOME/repos/$1"
|
||||||
|
rm -rf _site
|
||||||
|
JEKYLL_ENV=production bundle exec jekyll build
|
||||||
|
rsync -avzhe ssh _site/ "pi@hive:$DOCKER_STORAGE_DIR/staticwebserver/hosts/$1/" --delete
|
||||||
|
cd -
|
||||||
|
}
|
||||||
|
|
||||||
|
_site_deploy_nuxt() {
|
||||||
|
cd "$HOME/repos/$1"
|
||||||
|
rm -rf .output
|
||||||
|
npm run generate
|
||||||
|
rsync -avzhe ssh .output/public/ "pi@hive:$DOCKER_STORAGE_DIR/staticwebserver/hosts/$1/" --delete
|
||||||
|
cd -
|
||||||
|
}
|
||||||
|
|
||||||
|
_site_deploy_static() {
|
||||||
|
cd "$HOME/repos/$1"
|
||||||
|
rsync -avzhe ssh src/ "pi@hive:$DOCKER_STORAGE_DIR/staticwebserver/hosts/$1/" --delete
|
||||||
|
cd -
|
||||||
|
}
|
||||||
|
|
||||||
|
_site_run_jekyll() {
|
||||||
|
cd "$HOME/repos/$1"
|
||||||
|
bundle exec jekyll serve --livereload
|
||||||
|
cd -
|
||||||
|
}
|
||||||
|
|
||||||
|
_site_run_nuxt() {
|
||||||
|
cd "$HOME/repos/$1"
|
||||||
|
npm run dev
|
||||||
|
cd -
|
||||||
|
}
|
||||||
|
|
||||||
|
_site_run_static() {
|
||||||
|
cd "$HOME/repos/$1"
|
||||||
|
python -m http.server 8000 -d src
|
||||||
|
cd -
|
||||||
|
}
|
||||||
|
|
||||||
|
batch_file_sequence() {
|
||||||
|
a=0
|
||||||
|
for i in *.$2; do
|
||||||
|
new=$(printf "$1-%03d.$2" "$a")
|
||||||
|
mv -i -- "$i" "$new"
|
||||||
|
let a="$a+1"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
batch_image_webp() {
|
||||||
|
find . -type f -regex ".*\.\(jpg\|jpeg\|png\)" -exec mogrify -format webp {} \; -print
|
||||||
|
find . -type f -regex ".*\.\(jpg\|jpeg\|png\)" -exec rm {} \; -print
|
||||||
|
}
|
||||||
|
|
||||||
|
batch_video_x264() {
|
||||||
|
find . -type f -regex ".*\.\(mp4\)" -exec ffmpeg -i {} -vcodec libx264 -crf 24 "{}.mp4" \; -print
|
||||||
|
find . -type f -regex ".+mp4\.mp4" -exec python3 -c "import os;os.rename('{}', '{}'[:-4])" \; -print
|
||||||
|
}
|
||||||
|
|
||||||
|
_image_description() {
|
||||||
|
identify -verbose $1 | grep ImageDescription | sed "s/ exif:ImageDescription: //"
|
||||||
|
}
|
||||||
|
|
||||||
|
_image_optimize() {
|
||||||
|
i_x4 && cp -rf x4/* . && i_x05 && cp -rf x05/* . && _file_sequence $1 webp && mv $1-000.webp $1.webp
|
||||||
|
_image_description *.png
|
||||||
|
rm -rf *.png x4 x05
|
||||||
|
}
|
||||||
|
|
||||||
|
_video_optimize() {
|
||||||
|
filename=$(basename -- "$1")
|
||||||
|
extension="${filename##*.}"
|
||||||
|
filename="${filename%.*}"
|
||||||
|
ffmpeg -y -i $1 -vf "setpts=1.25*PTS" -r 24 "$filename.mp4"
|
||||||
|
}
|
||||||
|
|
||||||
|
function _over_subdirs {
|
||||||
|
_PWD=$PWD
|
||||||
|
. $PWD/.env
|
||||||
|
for D in $(find . -mindepth 1 -maxdepth 1 -type d); do
|
||||||
|
cd "$D" && $1
|
||||||
|
cd $_PWD
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_join_by() {
|
||||||
|
local d=${1-} f=${2-}
|
||||||
|
if shift 2; then
|
||||||
|
printf %s "$f" "${@/#/$d}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
0
.init/hooks/.gitkeep
Normal file
0
.init/hooks/.gitkeep
Normal file
41
.init/init.sh
Executable file
41
.init/init.sh
Executable file
@@ -0,0 +1,41 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -f "$HOME/.init/path.sh" ] ; then
|
||||||
|
. "$HOME/.init/path.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$HOME/.init/export.sh" ] ; then
|
||||||
|
. "$HOME/.init/export.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$HOME/.init/alias.sh" ] ; then
|
||||||
|
. "$HOME/.init/alias.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$HOME/.init/source.sh" ] ; then
|
||||||
|
. "$HOME/.init/source.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$HOME/.init/functions.sh" ] ; then
|
||||||
|
. "$HOME/.init/functions.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$HOME/.init/links.sh" ] ; then
|
||||||
|
. "$HOME/.init/links.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$HOME/.init/source.sh" ] ; then
|
||||||
|
. "$HOME/.init/source.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$HOME/.init/eval.sh" ] ; then
|
||||||
|
. "$HOME/.init/eval.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$HOME/.init/trap.sh" ] ; then
|
||||||
|
. "$HOME/.init/trap.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$HOME/.init/start.sh" ] ; then
|
||||||
|
. "$HOME/.init/start.sh"
|
||||||
|
fi
|
||||||
1
.init/links.sh
Executable file
1
.init/links.sh
Executable file
@@ -0,0 +1 @@
|
|||||||
|
#!/bin/bash
|
||||||
66
.init/path.sh
Executable file
66
.init/path.sh
Executable file
@@ -0,0 +1,66 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -d "$HOME/bin" ]; then
|
||||||
|
export PATH="$HOME/bin:$PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$HOME/.local/bin" ]; then
|
||||||
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$HOME/.rvm/bin" ]; then
|
||||||
|
export PATH="$HOME/.rvm/bin:$PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$HOME/repos/flutter/bin" ]; then
|
||||||
|
export PATH="$HOME/repos/flutter/bin:$PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$HOME/.rbenv/bin" ]; then
|
||||||
|
export PATH="$PATH:$HOME/.rbenv/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$HOME/.pyenv/bin" ]; then
|
||||||
|
export PYENV_ROOT="$HOME/.pyenv"
|
||||||
|
export PATH="$PYENV_ROOT/bin:$PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$HOME/.cargo/bin" ]; then
|
||||||
|
export PATH="$PATH:$HOME/.cargo/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "/opt/Upscayl/resources/bin" ]; then
|
||||||
|
export PATH="$PATH:/opt/Upscayl/resources/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "/usr/local/go/bin" ]; then
|
||||||
|
export PATH="$PATH:/usr/local/go/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$HOME/go/bin" ]; then
|
||||||
|
export PATH="$PATH:$HOME/go/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$HOME/node_modules/.bin" ]; then
|
||||||
|
export PATH="$PATH:$HOME/node_modules/.bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$HOME/miniconda3/bin" ]; then
|
||||||
|
export PATH="$PATH:$HOME/miniconda3/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$HOME/.local/share/flatpak/exports/share" ] ; then
|
||||||
|
export XDG_DATA_DIRS="$XDG_DATA_DIRS:$HOME/.local/share/flatpak/exports/share"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "/var/lib/flatpak/exports/share" ] ; then
|
||||||
|
export XDG_DATA_DIRS="$XDG_DATA_DIRS:/var/lib/flatpak/exports/share"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$HOME/.init/bin" ] ; then
|
||||||
|
export PATH="$PATH:$HOME/.init/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$HOME/Projects/kompose" ] ; then
|
||||||
|
export PATH="$PATH:$HOME/Projects/kompose"
|
||||||
|
fi
|
||||||
28
.init/source.sh
Executable file
28
.init/source.sh
Executable file
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -n "$BASH_VERSION" ]; then
|
||||||
|
# include .bashrc if it exists
|
||||||
|
if [ -f "$HOME/.bashrc" ]; then
|
||||||
|
. "$HOME/.bashrc"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -s "$NVM_DIR/nvm.sh" ] ; then
|
||||||
|
. "$NVM_DIR/nvm.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -s "$NVM_DIR/bash_completion" ] ; then
|
||||||
|
. "$NVM_DIR/bash_completion"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -s "$HOME/.rvm/scripts/rvm" ] ; then
|
||||||
|
. "$HOME/.rvm/scripts/rvm"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -s "$HOME/.cargo/env" ] ; then
|
||||||
|
. "$HOME/.cargo/env"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if [ -s "$HOME/.gvm/scripts/gvm" ]; then
|
||||||
|
# . "$HOME/.gvm/scripts/gvm"
|
||||||
|
# fi
|
||||||
26
.init/start.sh
Executable file
26
.init/start.sh
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
ssh-add &>/dev/null
|
||||||
|
|
||||||
|
# SSH_ENV="$HOME/.ssh/agent-environment"
|
||||||
|
|
||||||
|
# function start_agent {
|
||||||
|
# echo "Initialising new SSH agent..."
|
||||||
|
# /usr/bin/ssh-agent | sed 's/^echo/#echo/' >"$SSH_ENV"
|
||||||
|
# echo succeeded
|
||||||
|
# chmod 600 "$SSH_ENV"
|
||||||
|
# . "$SSH_ENV" >/dev/null
|
||||||
|
# /usr/bin/ssh-add;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# # Source SSH settings, if applicable
|
||||||
|
|
||||||
|
# if [ -f "$SSH_ENV" ]; then
|
||||||
|
# . "$SSH_ENV" >/dev/null
|
||||||
|
# #ps $SSH_AGENT_PID doesn't work under Cygwin
|
||||||
|
# ps -ef | grep $SSH_AGENT_PID | grep ssh-agent$ >/dev/null || {
|
||||||
|
# start_agent
|
||||||
|
# }
|
||||||
|
# else
|
||||||
|
# start_agent
|
||||||
|
# fi
|
||||||
13
.init/trap.sh
Executable file
13
.init/trap.sh
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
TRAPINT() {
|
||||||
|
}
|
||||||
|
|
||||||
|
TRAPQUIT() {
|
||||||
|
}
|
||||||
|
|
||||||
|
TRAPTERM() {
|
||||||
|
}
|
||||||
|
|
||||||
|
TRAPEXIT() {
|
||||||
|
}
|
||||||
193
.p10k.zsh
Normal file
193
.p10k.zsh
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
# Generated by Powerlevel10k configuration wizard on 2025-09-04 at 02:33 CEST.
|
||||||
|
# Based on romkatv/powerlevel10k/config/p10k-pure.zsh, checksum 07533.
|
||||||
|
# Wizard options: nerdfont-v3 + powerline, small icons, pure, snazzy, 24h time, 1 line,
|
||||||
|
# compact, instant_prompt=verbose.
|
||||||
|
# Type `p10k configure` to generate another config.
|
||||||
|
#
|
||||||
|
# Config file for Powerlevel10k with the style of Pure (https://github.com/sindresorhus/pure).
|
||||||
|
#
|
||||||
|
# Differences from Pure:
|
||||||
|
#
|
||||||
|
# - Git:
|
||||||
|
# - `@c4d3ec2c` instead of something like `v1.4.0~11` when in detached HEAD state.
|
||||||
|
# - No automatic `git fetch` (the same as in Pure with `PURE_GIT_PULL=0`).
|
||||||
|
#
|
||||||
|
# Apart from the differences listed above, the replication of Pure prompt is exact. This includes
|
||||||
|
# even the questionable parts. For example, just like in Pure, there is no indication of Git status
|
||||||
|
# being stale; prompt symbol is the same in command, visual and overwrite vi modes; when prompt
|
||||||
|
# doesn't fit on one line, it wraps around with no attempt to shorten it.
|
||||||
|
#
|
||||||
|
# If you like the general style of Pure but not particularly attached to all its quirks, type
|
||||||
|
# `p10k configure` and pick "Lean" style. This will give you slick minimalist prompt while taking
|
||||||
|
# advantage of Powerlevel10k features that aren't present in Pure.
|
||||||
|
|
||||||
|
# Temporarily change options.
|
||||||
|
'builtin' 'local' '-a' 'p10k_config_opts'
|
||||||
|
[[ ! -o 'aliases' ]] || p10k_config_opts+=('aliases')
|
||||||
|
[[ ! -o 'sh_glob' ]] || p10k_config_opts+=('sh_glob')
|
||||||
|
[[ ! -o 'no_brace_expand' ]] || p10k_config_opts+=('no_brace_expand')
|
||||||
|
'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand'
|
||||||
|
|
||||||
|
() {
|
||||||
|
emulate -L zsh -o extended_glob
|
||||||
|
|
||||||
|
# Unset all configuration options.
|
||||||
|
unset -m '(POWERLEVEL9K_*|DEFAULT_USER)~POWERLEVEL9K_GITSTATUS_DIR'
|
||||||
|
|
||||||
|
# Zsh >= 5.1 is required.
|
||||||
|
[[ $ZSH_VERSION == (5.<1->*|<6->.*) ]] || return
|
||||||
|
|
||||||
|
# Prompt colors.
|
||||||
|
local grey='242'
|
||||||
|
local red='#FF5C57'
|
||||||
|
local yellow='#F3F99D'
|
||||||
|
local blue='#57C7FF'
|
||||||
|
local magenta='#FF6AC1'
|
||||||
|
local cyan='#9AEDFE'
|
||||||
|
local white='#F1F1F0'
|
||||||
|
|
||||||
|
# Left prompt segments.
|
||||||
|
typeset -g POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(
|
||||||
|
context # user@host
|
||||||
|
dir # current directory
|
||||||
|
vcs # git status
|
||||||
|
command_execution_time # previous command duration
|
||||||
|
# virtualenv # python virtual environment
|
||||||
|
prompt_char # prompt symbol
|
||||||
|
)
|
||||||
|
|
||||||
|
# Right prompt segments.
|
||||||
|
typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(
|
||||||
|
# command_execution_time # previous command duration
|
||||||
|
# virtualenv # python virtual environment
|
||||||
|
# context # user@host
|
||||||
|
time # current time
|
||||||
|
)
|
||||||
|
|
||||||
|
# Basic style options that define the overall prompt look.
|
||||||
|
typeset -g POWERLEVEL9K_BACKGROUND= # transparent background
|
||||||
|
typeset -g POWERLEVEL9K_{LEFT,RIGHT}_{LEFT,RIGHT}_WHITESPACE= # no surrounding whitespace
|
||||||
|
typeset -g POWERLEVEL9K_{LEFT,RIGHT}_SUBSEGMENT_SEPARATOR=' ' # separate segments with a space
|
||||||
|
typeset -g POWERLEVEL9K_{LEFT,RIGHT}_SEGMENT_SEPARATOR= # no end-of-line symbol
|
||||||
|
typeset -g POWERLEVEL9K_VISUAL_IDENTIFIER_EXPANSION= # no segment icons
|
||||||
|
|
||||||
|
# Add an empty line before each prompt except the first. This doesn't emulate the bug
|
||||||
|
# in Pure that makes prompt drift down whenever you use the Alt-C binding from fzf or similar.
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_ADD_NEWLINE=false
|
||||||
|
|
||||||
|
# Magenta prompt symbol if the last command succeeded.
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_OK_{VIINS,VICMD,VIVIS}_FOREGROUND=$magenta
|
||||||
|
# Red prompt symbol if the last command failed.
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_ERROR_{VIINS,VICMD,VIVIS}_FOREGROUND=$red
|
||||||
|
# Default prompt symbol.
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIINS_CONTENT_EXPANSION='❯'
|
||||||
|
# Prompt symbol in command vi mode.
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VICMD_CONTENT_EXPANSION='❮'
|
||||||
|
# Prompt symbol in visual vi mode is the same as in command mode.
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIVIS_CONTENT_EXPANSION='❮'
|
||||||
|
# Prompt symbol in overwrite vi mode is the same as in command mode.
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_OVERWRITE_STATE=false
|
||||||
|
|
||||||
|
# Grey Python Virtual Environment.
|
||||||
|
typeset -g POWERLEVEL9K_VIRTUALENV_FOREGROUND=$grey
|
||||||
|
# Don't show Python version.
|
||||||
|
typeset -g POWERLEVEL9K_VIRTUALENV_SHOW_PYTHON_VERSION=false
|
||||||
|
typeset -g POWERLEVEL9K_VIRTUALENV_{LEFT,RIGHT}_DELIMITER=
|
||||||
|
|
||||||
|
# Blue current directory.
|
||||||
|
typeset -g POWERLEVEL9K_DIR_FOREGROUND=$blue
|
||||||
|
|
||||||
|
# Context format when root: user@host. The first part white, the rest grey.
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_ROOT_TEMPLATE="%F{$white}%n%f%F{$grey}@%m%f"
|
||||||
|
# Context format when not root: user@host. The whole thing grey.
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_TEMPLATE="%F{$grey}%n@%m%f"
|
||||||
|
# Don't show context unless root or in SSH.
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_{DEFAULT,SUDO}_CONTENT_EXPANSION=
|
||||||
|
|
||||||
|
# Show previous command duration only if it's >= 5s.
|
||||||
|
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_THRESHOLD=5
|
||||||
|
# Don't show fractional seconds. Thus, 7s rather than 7.3s.
|
||||||
|
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_PRECISION=0
|
||||||
|
# Duration format: 1d 2h 3m 4s.
|
||||||
|
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FORMAT='d h m s'
|
||||||
|
# Yellow previous command duration.
|
||||||
|
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FOREGROUND=$yellow
|
||||||
|
|
||||||
|
# Grey Git prompt. This makes stale prompts indistinguishable from up-to-date ones.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_FOREGROUND=$grey
|
||||||
|
|
||||||
|
# Disable async loading indicator to make directories that aren't Git repositories
|
||||||
|
# indistinguishable from large Git repositories without known state.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_LOADING_TEXT=
|
||||||
|
|
||||||
|
# Don't wait for Git status even for a millisecond, so that prompt always updates
|
||||||
|
# asynchronously when Git state changes.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_MAX_SYNC_LATENCY_SECONDS=0
|
||||||
|
|
||||||
|
# Cyan ahead/behind arrows.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_{INCOMING,OUTGOING}_CHANGESFORMAT_FOREGROUND=$cyan
|
||||||
|
# Don't show remote branch, current tag or stashes.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_GIT_HOOKS=(vcs-detect-changes git-untracked git-aheadbehind)
|
||||||
|
# Don't show the branch icon.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_BRANCH_ICON=
|
||||||
|
# When in detached HEAD state, show @commit where branch normally goes.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_COMMIT_ICON='@'
|
||||||
|
# Don't show staged, unstaged, untracked indicators.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_{STAGED,UNSTAGED,UNTRACKED}_ICON=
|
||||||
|
# Show '*' when there are staged, unstaged or untracked files.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_DIRTY_ICON='*'
|
||||||
|
# Show '⇣' if local branch is behind remote.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_INCOMING_CHANGES_ICON=':⇣'
|
||||||
|
# Show '⇡' if local branch is ahead of remote.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_OUTGOING_CHANGES_ICON=':⇡'
|
||||||
|
# Don't show the number of commits next to the ahead/behind arrows.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_{COMMITS_AHEAD,COMMITS_BEHIND}_MAX_NUM=1
|
||||||
|
# Remove space between '⇣' and '⇡' and all trailing spaces.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_CONTENT_EXPANSION='${${${P9K_CONTENT/⇣* :⇡/⇣⇡}// }//:/ }'
|
||||||
|
|
||||||
|
# Grey current time.
|
||||||
|
typeset -g POWERLEVEL9K_TIME_FOREGROUND=$grey
|
||||||
|
# Format for the current time: 09:51:02. See `man 3 strftime`.
|
||||||
|
typeset -g POWERLEVEL9K_TIME_FORMAT='%D{%H:%M:%S}'
|
||||||
|
# If set to true, time will update when you hit enter. This way prompts for the past
|
||||||
|
# commands will contain the start times of their commands rather than the end times of
|
||||||
|
# their preceding commands.
|
||||||
|
typeset -g POWERLEVEL9K_TIME_UPDATE_ON_COMMAND=false
|
||||||
|
|
||||||
|
# Transient prompt works similarly to the builtin transient_rprompt option. It trims down prompt
|
||||||
|
# when accepting a command line. Supported values:
|
||||||
|
#
|
||||||
|
# - off: Don't change prompt when accepting a command line.
|
||||||
|
# - always: Trim down prompt when accepting a command line.
|
||||||
|
# - same-dir: Trim down prompt when accepting a command line unless this is the first command
|
||||||
|
# typed after changing current working directory.
|
||||||
|
typeset -g POWERLEVEL9K_TRANSIENT_PROMPT=off
|
||||||
|
|
||||||
|
# Instant prompt mode.
|
||||||
|
#
|
||||||
|
# - off: Disable instant prompt. Choose this if you've tried instant prompt and found
|
||||||
|
# it incompatible with your zsh configuration files.
|
||||||
|
# - quiet: Enable instant prompt and don't print warnings when detecting console output
|
||||||
|
# during zsh initialization. Choose this if you've read and understood
|
||||||
|
# https://github.com/romkatv/powerlevel10k#instant-prompt.
|
||||||
|
# - verbose: Enable instant prompt and print a warning when detecting console output during
|
||||||
|
# zsh initialization. Choose this if you've never tried instant prompt, haven't
|
||||||
|
# seen the warning, or if you are unsure what this all means.
|
||||||
|
typeset -g POWERLEVEL9K_INSTANT_PROMPT=off
|
||||||
|
|
||||||
|
# Hot reload allows you to change POWERLEVEL9K options after Powerlevel10k has been initialized.
|
||||||
|
# For example, you can type POWERLEVEL9K_BACKGROUND=red and see your prompt turn red. Hot reload
|
||||||
|
# can slow down prompt by 1-2 milliseconds, so it's better to keep it turned off unless you
|
||||||
|
# really need it.
|
||||||
|
typeset -g POWERLEVEL9K_DISABLE_HOT_RELOAD=off
|
||||||
|
|
||||||
|
# If p10k is already loaded, reload configuration.
|
||||||
|
# This works even with POWERLEVEL9K_DISABLE_HOT_RELOAD=true.
|
||||||
|
(( ! $+functions[p10k] )) || p10k reload
|
||||||
|
}
|
||||||
|
|
||||||
|
# Tell `p10k configure` which file it should overwrite.
|
||||||
|
typeset -g POWERLEVEL9K_CONFIG_FILE=${${(%):-%x}:a}
|
||||||
|
|
||||||
|
(( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]}
|
||||||
|
'builtin' 'unset' 'p10k_config_opts'
|
||||||
5
.pre-commit-config.yaml
Normal file
5
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
fail_fast: false
|
||||||
|
default_stages: [pre-commit]
|
||||||
|
repos:
|
||||||
|
- repo: local
|
||||||
|
hooks: []
|
||||||
5
.prettierignore
Normal file
5
.prettierignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Ignore artifacts:
|
||||||
|
build
|
||||||
|
coverage
|
||||||
|
|
||||||
|
repos/hydejack/**/*.html
|
||||||
16
.prettierrc
Normal file
16
.prettierrc
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"arrowParens": "always",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"htmlWhitespaceSensitivity": "css",
|
||||||
|
"insertPragma": false,
|
||||||
|
"jsxSingleQuote": true,
|
||||||
|
"printWidth": 80,
|
||||||
|
"proseWrap": "always",
|
||||||
|
"quoteProps": "as-needed",
|
||||||
|
"requirePragma": false,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"useTabs": false
|
||||||
|
}
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.10.17
|
||||||
267
.rubocop.yml
Normal file
267
.rubocop.yml
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
AllCops:
|
||||||
|
NewCops: enable
|
||||||
|
|
||||||
|
Gemspec/AddRuntimeDependency: # new in 1.65
|
||||||
|
Enabled: true
|
||||||
|
Gemspec/DeprecatedAttributeAssignment: # new in 1.30
|
||||||
|
Enabled: true
|
||||||
|
Gemspec/DevelopmentDependencies: # new in 1.44
|
||||||
|
Enabled: true
|
||||||
|
Gemspec/RequireMFA: # new in 1.23
|
||||||
|
Enabled: true
|
||||||
|
Layout/LineContinuationLeadingSpace: # new in 1.31
|
||||||
|
Enabled: true
|
||||||
|
Layout/LineContinuationSpacing: # new in 1.31
|
||||||
|
Enabled: true
|
||||||
|
Layout/LineEndStringConcatenationIndentation: # new in 1.18
|
||||||
|
Enabled: true
|
||||||
|
Layout/SpaceBeforeBrackets: # new in 1.7
|
||||||
|
Enabled: true
|
||||||
|
Lint/AmbiguousAssignment: # new in 1.7
|
||||||
|
Enabled: true
|
||||||
|
Lint/AmbiguousOperatorPrecedence: # new in 1.21
|
||||||
|
Enabled: true
|
||||||
|
Lint/AmbiguousRange: # new in 1.19
|
||||||
|
Enabled: true
|
||||||
|
Lint/ArrayLiteralInRegexp: # new in 1.71
|
||||||
|
Enabled: true
|
||||||
|
Lint/ConstantOverwrittenInRescue: # new in 1.31
|
||||||
|
Enabled: true
|
||||||
|
Lint/ConstantReassignment: # new in 1.70
|
||||||
|
Enabled: true
|
||||||
|
Lint/CopDirectiveSyntax: # new in 1.72
|
||||||
|
Enabled: true
|
||||||
|
Lint/DeprecatedConstants: # new in 1.8
|
||||||
|
Enabled: true
|
||||||
|
Lint/DuplicateBranch: # new in 1.3
|
||||||
|
Enabled: true
|
||||||
|
Lint/DuplicateMagicComment: # new in 1.37
|
||||||
|
Enabled: true
|
||||||
|
Lint/DuplicateMatchPattern: # new in 1.50
|
||||||
|
Enabled: true
|
||||||
|
Lint/DuplicateRegexpCharacterClassElement: # new in 1.1
|
||||||
|
Enabled: true
|
||||||
|
Lint/DuplicateSetElement: # new in 1.67
|
||||||
|
Enabled: true
|
||||||
|
Lint/EmptyBlock: # new in 1.1
|
||||||
|
Enabled: true
|
||||||
|
Lint/EmptyClass: # new in 1.3
|
||||||
|
Enabled: true
|
||||||
|
Lint/EmptyInPattern: # new in 1.16
|
||||||
|
Enabled: true
|
||||||
|
Lint/HashNewWithKeywordArgumentsAsDefault: # new in 1.69
|
||||||
|
Enabled: true
|
||||||
|
Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21
|
||||||
|
Enabled: true
|
||||||
|
Lint/ItWithoutArgumentsInBlock: # new in 1.59
|
||||||
|
Enabled: true
|
||||||
|
Lint/LambdaWithoutLiteralBlock: # new in 1.8
|
||||||
|
Enabled: true
|
||||||
|
Lint/LiteralAssignmentInCondition: # new in 1.58
|
||||||
|
Enabled: true
|
||||||
|
Lint/MixedCaseRange: # new in 1.53
|
||||||
|
Enabled: true
|
||||||
|
Lint/NoReturnInBeginEndBlocks: # new in 1.2
|
||||||
|
Enabled: true
|
||||||
|
Lint/NonAtomicFileOperation: # new in 1.31
|
||||||
|
Enabled: true
|
||||||
|
Lint/NumberedParameterAssignment: # new in 1.9
|
||||||
|
Enabled: true
|
||||||
|
Lint/NumericOperationWithConstantResult: # new in 1.69
|
||||||
|
Enabled: true
|
||||||
|
Lint/OrAssignmentToConstant: # new in 1.9
|
||||||
|
Enabled: true
|
||||||
|
Lint/RedundantDirGlobSort: # new in 1.8
|
||||||
|
Enabled: true
|
||||||
|
Lint/RedundantRegexpQuantifiers: # new in 1.53
|
||||||
|
Enabled: true
|
||||||
|
Lint/RedundantTypeConversion: # new in 1.72
|
||||||
|
Enabled: true
|
||||||
|
Lint/RefinementImportMethods: # new in 1.27
|
||||||
|
Enabled: true
|
||||||
|
Lint/RequireRangeParentheses: # new in 1.32
|
||||||
|
Enabled: true
|
||||||
|
Lint/RequireRelativeSelfPath: # new in 1.22
|
||||||
|
Enabled: true
|
||||||
|
Lint/SharedMutableDefault: # new in 1.70
|
||||||
|
Enabled: true
|
||||||
|
Lint/SuppressedExceptionInNumberConversion: # new in 1.72
|
||||||
|
Enabled: true
|
||||||
|
Lint/SymbolConversion: # new in 1.9
|
||||||
|
Enabled: true
|
||||||
|
Lint/ToEnumArguments: # new in 1.1
|
||||||
|
Enabled: true
|
||||||
|
Lint/TripleQuotes: # new in 1.9
|
||||||
|
Enabled: true
|
||||||
|
Lint/UnescapedBracketInRegexp: # new in 1.68
|
||||||
|
Enabled: true
|
||||||
|
Lint/UnexpectedBlockArity: # new in 1.5
|
||||||
|
Enabled: true
|
||||||
|
Lint/UnmodifiedReduceAccumulator: # new in 1.1
|
||||||
|
Enabled: true
|
||||||
|
Lint/UselessConstantScoping: # new in 1.72
|
||||||
|
Enabled: true
|
||||||
|
Lint/UselessDefined: # new in 1.69
|
||||||
|
Enabled: true
|
||||||
|
Lint/UselessNumericOperation: # new in 1.66
|
||||||
|
Enabled: true
|
||||||
|
Lint/UselessRescue: # new in 1.43
|
||||||
|
Enabled: true
|
||||||
|
Lint/UselessRuby2Keywords: # new in 1.23
|
||||||
|
Enabled: true
|
||||||
|
Metrics/CollectionLiteralLength: # new in 1.47
|
||||||
|
Enabled: true
|
||||||
|
Naming/BlockForwarding: # new in 1.24
|
||||||
|
Enabled: true
|
||||||
|
Security/CompoundHash: # new in 1.28
|
||||||
|
Enabled: true
|
||||||
|
Security/IoMethods: # new in 1.22
|
||||||
|
Enabled: true
|
||||||
|
Style/AmbiguousEndlessMethodDefinition: # new in 1.68
|
||||||
|
Enabled: true
|
||||||
|
Style/ArgumentsForwarding: # new in 1.1
|
||||||
|
Enabled: true
|
||||||
|
Style/ArrayIntersect: # new in 1.40
|
||||||
|
Enabled: true
|
||||||
|
Style/BitwisePredicate: # new in 1.68
|
||||||
|
Enabled: true
|
||||||
|
Style/CollectionCompact: # new in 1.2
|
||||||
|
Enabled: true
|
||||||
|
Style/CombinableDefined: # new in 1.68
|
||||||
|
Enabled: true
|
||||||
|
Style/ComparableBetween: # new in 1.74
|
||||||
|
Enabled: true
|
||||||
|
Style/ComparableClamp: # new in 1.44
|
||||||
|
Enabled: true
|
||||||
|
Style/ConcatArrayLiterals: # new in 1.41
|
||||||
|
Enabled: true
|
||||||
|
Style/DataInheritance: # new in 1.49
|
||||||
|
Enabled: true
|
||||||
|
Style/DigChain: # new in 1.69
|
||||||
|
Enabled: true
|
||||||
|
Style/DirEmpty: # new in 1.48
|
||||||
|
Enabled: true
|
||||||
|
Style/DocumentDynamicEvalDefinition: # new in 1.1
|
||||||
|
Enabled: true
|
||||||
|
Style/EmptyHeredoc: # new in 1.32
|
||||||
|
Enabled: true
|
||||||
|
Style/EndlessMethod: # new in 1.8
|
||||||
|
Enabled: true
|
||||||
|
Style/EnvHome: # new in 1.29
|
||||||
|
Enabled: true
|
||||||
|
Style/ExactRegexpMatch: # new in 1.51
|
||||||
|
Enabled: true
|
||||||
|
Style/FetchEnvVar: # new in 1.28
|
||||||
|
Enabled: true
|
||||||
|
Style/FileEmpty: # new in 1.48
|
||||||
|
Enabled: true
|
||||||
|
Style/FileNull: # new in 1.69
|
||||||
|
Enabled: true
|
||||||
|
Style/FileRead: # new in 1.24
|
||||||
|
Enabled: true
|
||||||
|
Style/FileTouch: # new in 1.69
|
||||||
|
Enabled: true
|
||||||
|
Style/FileWrite: # new in 1.24
|
||||||
|
Enabled: true
|
||||||
|
Style/HashConversion: # new in 1.10
|
||||||
|
Enabled: true
|
||||||
|
Style/HashExcept: # new in 1.7
|
||||||
|
Enabled: true
|
||||||
|
Style/HashFetchChain: # new in 1.75
|
||||||
|
Enabled: true
|
||||||
|
Style/HashSlice: # new in 1.71
|
||||||
|
Enabled: true
|
||||||
|
Style/IfWithBooleanLiteralBranches: # new in 1.9
|
||||||
|
Enabled: true
|
||||||
|
Style/InPatternThen: # new in 1.16
|
||||||
|
Enabled: true
|
||||||
|
Style/ItAssignment: # new in 1.70
|
||||||
|
Enabled: true
|
||||||
|
Style/ItBlockParameter: # new in 1.75
|
||||||
|
Enabled: true
|
||||||
|
Style/KeywordArgumentsMerging: # new in 1.68
|
||||||
|
Enabled: true
|
||||||
|
Style/MagicCommentFormat: # new in 1.35
|
||||||
|
Enabled: true
|
||||||
|
Style/MapCompactWithConditionalBlock: # new in 1.30
|
||||||
|
Enabled: true
|
||||||
|
Style/MapIntoArray: # new in 1.63
|
||||||
|
Enabled: true
|
||||||
|
Style/MapToHash: # new in 1.24
|
||||||
|
Enabled: true
|
||||||
|
Style/MapToSet: # new in 1.42
|
||||||
|
Enabled: true
|
||||||
|
Style/MinMaxComparison: # new in 1.42
|
||||||
|
Enabled: true
|
||||||
|
Style/MultilineInPatternThen: # new in 1.16
|
||||||
|
Enabled: true
|
||||||
|
Style/NegatedIfElseCondition: # new in 1.2
|
||||||
|
Enabled: true
|
||||||
|
Style/NestedFileDirname: # new in 1.26
|
||||||
|
Enabled: true
|
||||||
|
Style/NilLambda: # new in 1.3
|
||||||
|
Enabled: true
|
||||||
|
Style/NumberedParameters: # new in 1.22
|
||||||
|
Enabled: true
|
||||||
|
Style/NumberedParametersLimit: # new in 1.22
|
||||||
|
Enabled: true
|
||||||
|
Style/ObjectThen: # new in 1.28
|
||||||
|
Enabled: true
|
||||||
|
Style/OpenStructUse: # new in 1.23
|
||||||
|
Enabled: true
|
||||||
|
Style/OperatorMethodCall: # new in 1.37
|
||||||
|
Enabled: true
|
||||||
|
Style/QuotedSymbols: # new in 1.16
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantArgument: # new in 1.4
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantArrayConstructor: # new in 1.52
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantConstantBase: # new in 1.40
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantCurrentDirectoryInPath: # new in 1.53
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantDoubleSplatHashBraces: # new in 1.41
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantEach: # new in 1.38
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantFilterChain: # new in 1.52
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantFormat: # new in 1.72
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantHeredocDelimiterQuotes: # new in 1.45
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantInitialize: # new in 1.27
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantInterpolationUnfreeze: # new in 1.66
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantLineContinuation: # new in 1.49
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantRegexpArgument: # new in 1.53
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantRegexpConstructor: # new in 1.52
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantSelfAssignmentBranch: # new in 1.19
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantStringEscape: # new in 1.37
|
||||||
|
Enabled: true
|
||||||
|
Style/ReturnNilInPredicateMethodDefinition: # new in 1.53
|
||||||
|
Enabled: true
|
||||||
|
Style/SafeNavigationChainLength: # new in 1.68
|
||||||
|
Enabled: true
|
||||||
|
Style/SelectByRegexp: # new in 1.22
|
||||||
|
Enabled: true
|
||||||
|
Style/SendWithLiteralMethodName: # new in 1.64
|
||||||
|
Enabled: true
|
||||||
|
Style/SingleLineDoEndBlock: # new in 1.57
|
||||||
|
Enabled: true
|
||||||
|
Style/StringChars: # new in 1.12
|
||||||
|
Enabled: true
|
||||||
|
Style/SuperArguments: # new in 1.64
|
||||||
|
Enabled: true
|
||||||
|
Style/SuperWithArgsParentheses: # new in 1.58
|
||||||
|
Enabled: true
|
||||||
|
Style/SwapValues: # new in 1.1
|
||||||
|
Enabled: true
|
||||||
|
Style/YAMLFileRead: # new in 1.53
|
||||||
|
Enabled: true
|
||||||
1
.ruby-version
Normal file
1
.ruby-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.4.1
|
||||||
49
.vscode/settings.json
vendored
Normal file
49
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"explorer.excludeGitIgnore": false,
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
|
"[ignore]": {
|
||||||
|
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||||
|
},
|
||||||
|
"[shellscript]": {
|
||||||
|
"editor.defaultFormatter": "mkhl.shfmt"
|
||||||
|
},
|
||||||
|
"[xml]": {
|
||||||
|
"editor.defaultFormatter": "trunk.io"
|
||||||
|
},
|
||||||
|
"[html]": {
|
||||||
|
"editor.defaultFormatter": "trunk.io"
|
||||||
|
},
|
||||||
|
"[javascript]": {
|
||||||
|
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||||
|
},
|
||||||
|
"[markdown]": {
|
||||||
|
"editor.defaultFormatter": "trunk.io"
|
||||||
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||||
|
},
|
||||||
|
"[yaml]": {
|
||||||
|
"editor.defaultFormatter": "kennylong.kubernetes-yaml-formatter"
|
||||||
|
},
|
||||||
|
"[dockercompose]": {
|
||||||
|
"editor.defaultFormatter": "ms-azuretools.vscode-containers"
|
||||||
|
},
|
||||||
|
"[svelte]": {
|
||||||
|
"editor.defaultFormatter": "svelte.svelte-vscode"
|
||||||
|
},
|
||||||
|
"[css]": {
|
||||||
|
"editor.defaultFormatter": "vscode.css-language-features"
|
||||||
|
},
|
||||||
|
"[json]": {
|
||||||
|
"editor.defaultFormatter": "vscode.json-language-features"
|
||||||
|
},
|
||||||
|
"[rust]": {
|
||||||
|
"editor.defaultFormatter": "rust-lang.rust-analyzer"
|
||||||
|
},
|
||||||
|
"[jsonc]": {
|
||||||
|
"editor.defaultFormatter": "vscode.json-language-features"
|
||||||
|
},
|
||||||
|
"[vue]": {
|
||||||
|
"editor.defaultFormatter": "Vue.volar"
|
||||||
|
}
|
||||||
|
}
|
||||||
130
.zshrc
Normal file
130
.zshrc
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
if [ -f "$HOME/.init/init.sh" ] ; then
|
||||||
|
. "$HOME/.init/init.sh"
|
||||||
|
fi
|
||||||
|
# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
|
||||||
|
# Initialization code that may require console input (password prompts, [y/n]
|
||||||
|
# confirmations, etc.) must go above this block; everything else may go below.
|
||||||
|
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
|
||||||
|
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If you come from bash you might have to change your $PATH.
|
||||||
|
# export PATH=$HOME/bin:$HOME/.local/bin:/usr/local/bin:$PATH
|
||||||
|
|
||||||
|
# Path to your Oh My Zsh installation.
|
||||||
|
export ZSH="$HOME/.oh-my-zsh"
|
||||||
|
|
||||||
|
# Set name of the theme to load --- if set to "random", it will
|
||||||
|
# load a random theme each time Oh My Zsh is loaded, in which case,
|
||||||
|
# to know which specific one was loaded, run: echo $RANDOM_THEME
|
||||||
|
# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
|
||||||
|
ZSH_THEME="powerlevel10k/powerlevel10k"
|
||||||
|
|
||||||
|
# Set list of themes to pick from when loading at random
|
||||||
|
# Setting this variable when ZSH_THEME=random will cause zsh to load
|
||||||
|
# a theme from this variable instead of looking in $ZSH/themes/
|
||||||
|
# If set to an empty array, this variable will have no effect.
|
||||||
|
# ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" )
|
||||||
|
|
||||||
|
# Uncomment the following line to use case-sensitive completion.
|
||||||
|
# CASE_SENSITIVE="true"
|
||||||
|
|
||||||
|
# Uncomment the following line to use hyphen-insensitive completion.
|
||||||
|
# Case-sensitive completion must be off. _ and - will be interchangeable.
|
||||||
|
# HYPHEN_INSENSITIVE="true"
|
||||||
|
|
||||||
|
# Uncomment one of the following lines to change the auto-update behavior
|
||||||
|
# zstyle ':omz:update' mode disabled # disable automatic updates
|
||||||
|
# zstyle ':omz:update' mode auto # update automatically without asking
|
||||||
|
# zstyle ':omz:update' mode reminder # just remind me to update when it's time
|
||||||
|
|
||||||
|
# Uncomment the following line to change how often to auto-update (in days).
|
||||||
|
# zstyle ':omz:update' frequency 13
|
||||||
|
|
||||||
|
# Uncomment the following line if pasting URLs and other text is messed up.
|
||||||
|
# DISABLE_MAGIC_FUNCTIONS="true"
|
||||||
|
|
||||||
|
# Uncomment the following line to disable colors in ls.
|
||||||
|
# DISABLE_LS_COLORS="true"
|
||||||
|
|
||||||
|
# Uncomment the following line to disable auto-setting terminal title.
|
||||||
|
# DISABLE_AUTO_TITLE="true"
|
||||||
|
|
||||||
|
# Uncomment the following line to enable command auto-correction.
|
||||||
|
# ENABLE_CORRECTION="true"
|
||||||
|
|
||||||
|
# Uncomment the following line to display red dots whilst waiting for completion.
|
||||||
|
# You can also set it to another string to have that shown instead of the default red dots.
|
||||||
|
# e.g. COMPLETION_WAITING_DOTS="%F{yellow}waiting...%f"
|
||||||
|
# Caution: this setting can cause issues with multiline prompts in zsh < 5.7.1 (see #5765)
|
||||||
|
# COMPLETION_WAITING_DOTS="true"
|
||||||
|
|
||||||
|
# Uncomment the following line if you want to disable marking untracked files
|
||||||
|
# under VCS as dirty. This makes repository status check for large repositories
|
||||||
|
# much, much faster.
|
||||||
|
# DISABLE_UNTRACKED_FILES_DIRTY="true"
|
||||||
|
|
||||||
|
# Uncomment the following line if you want to change the command execution time
|
||||||
|
# stamp shown in the history command output.
|
||||||
|
# You can set one of the optional three formats:
|
||||||
|
# "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd"
|
||||||
|
# or set a custom format using the strftime function format specifications,
|
||||||
|
# see 'man strftime' for details.
|
||||||
|
# HIST_STAMPS="mm/dd/yyyy"
|
||||||
|
|
||||||
|
# Would you like to use another custom folder than $ZSH/custom?
|
||||||
|
# ZSH_CUSTOM=/path/to/new-custom-folder
|
||||||
|
|
||||||
|
# Which plugins would you like to load?
|
||||||
|
# Standard plugins can be found in $ZSH/plugins/
|
||||||
|
# Custom plugins may be added to $ZSH_CUSTOM/plugins/
|
||||||
|
# Example format: plugins=(rails git textmate ruby lighthouse)
|
||||||
|
# Add wisely, as too many plugins slow down shell startup.
|
||||||
|
plugins=(git pm2 gh sudo ssh ruby rust python node github rsync nvm rbenv pyenv docker docker-compose qrcode zsh-autosuggestions zsh-syntax-highlighting zsh-interactive-cd zsh-navigation-tools)
|
||||||
|
|
||||||
|
source $ZSH/oh-my-zsh.sh
|
||||||
|
|
||||||
|
# User configuration
|
||||||
|
|
||||||
|
# export MANPATH="/usr/local/man:$MANPATH"
|
||||||
|
|
||||||
|
# You may need to manually set your language environment
|
||||||
|
# export LANG=en_US.UTF-8
|
||||||
|
|
||||||
|
# Preferred editor for local and remote sessions
|
||||||
|
# if [[ -n $SSH_CONNECTION ]]; then
|
||||||
|
# export EDITOR='vim'
|
||||||
|
# else
|
||||||
|
# export EDITOR='nvim'
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# Compilation flags
|
||||||
|
# export ARCHFLAGS="-arch $(uname -m)"
|
||||||
|
|
||||||
|
# Set personal aliases, overriding those provided by Oh My Zsh libs,
|
||||||
|
# plugins, and themes. Aliases can be placed here, though Oh My Zsh
|
||||||
|
# users are encouraged to define aliases within a top-level file in
|
||||||
|
# the $ZSH_CUSTOM folder, with .zsh extension. Examples:
|
||||||
|
# - $ZSH_CUSTOM/aliases.zsh
|
||||||
|
# - $ZSH_CUSTOM/macos.zsh
|
||||||
|
# For a full list of active aliases, run `alias`.
|
||||||
|
#
|
||||||
|
# Example aliases
|
||||||
|
# alias zshconfig="mate ~/.zshrc"
|
||||||
|
# alias ohmyzsh="mate ~/.oh-my-zsh"
|
||||||
|
|
||||||
|
# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
|
||||||
|
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
|
||||||
|
|
||||||
|
|
||||||
|
# _home_pull
|
||||||
|
|
||||||
|
cd "$HOME/$(cat $HOME/.last_pwd)" &>/dev/null
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
export PNPM_HOME="/home/valknar/.local/share/pnpm"
|
||||||
|
case ":$PATH:" in
|
||||||
|
*":$PNPM_HOME:"*) ;;
|
||||||
|
*) export PATH="$PNPM_HOME:$PATH" ;;
|
||||||
|
esac
|
||||||
|
# pnpm end
|
||||||
137
CLAUDE.md
Normal file
137
CLAUDE.md
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This is a personal home directory repository managed as a git repository with selective tracking via `.gitignore`. The repository tracks dotfiles and configuration for a Debian development environment supporting Node.js, Python, Ruby, Rust, and Go development.
|
||||||
|
|
||||||
|
## Key Architecture
|
||||||
|
|
||||||
|
### Initialization System
|
||||||
|
Shell initialization is managed through `.init/init.sh`, which sources modular configuration:
|
||||||
|
- `.init/path.sh` - PATH environment setup for all language toolchains
|
||||||
|
- `.init/alias.sh` - Custom shell aliases
|
||||||
|
- `.init/functions.sh` - Custom shell functions for deployment and media processing
|
||||||
|
- `.init/export.sh`, `.init/source.sh`, `.init/eval.sh` - Additional environment setup
|
||||||
|
|
||||||
|
### Arty Configuration
|
||||||
|
`arty.yml` defines the repository structure using Arty (artifact/repository manager):
|
||||||
|
- **references**: Git subrepositories to clone into specific paths
|
||||||
|
- **envs**: Environment profiles (dev/prod) for selective repository management
|
||||||
|
- Manages both development projects and language version managers (nvm, rbenv, pyenv, gvm)
|
||||||
|
|
||||||
|
### Ansible Provisioning
|
||||||
|
`playbook.yml` is an Ansible playbook for system setup:
|
||||||
|
- Installs and configures language runtimes (Node, Python, Ruby, Rust, Go)
|
||||||
|
- Sets up Docker, PostgreSQL 18, and development tools
|
||||||
|
- Configures Zsh with Oh-My-Zsh and Powerlevel10k theme
|
||||||
|
- Manages system packages via apt
|
||||||
|
|
||||||
|
### Git Selective Tracking
|
||||||
|
The `.gitignore` uses an inverted pattern (ignore everything, then selectively allow):
|
||||||
|
- Tracks only specific dotfiles and configuration files
|
||||||
|
- Allows `.github/`, `.init/`, `.vscode/` directories
|
||||||
|
- Excludes logs, databases, and temporary files
|
||||||
|
|
||||||
|
## Development Environment
|
||||||
|
|
||||||
|
### Language Version Management
|
||||||
|
- **Node.js**: Managed by nvm, version specified in `.nvmrc`
|
||||||
|
- **Ruby**: Managed by rbenv, version in `.ruby-version`
|
||||||
|
- **Python**: Managed by pyenv, version in `.python-version`
|
||||||
|
- **Rust**: Via rustup (`.cargo/`, `.rustup/`)
|
||||||
|
- **Go**: Via gvm (`.gvm/`)
|
||||||
|
|
||||||
|
### Shell Environment
|
||||||
|
- **Shell**: Zsh with Oh-My-Zsh framework
|
||||||
|
- **Theme**: Powerlevel10k (`.p10k.zsh`)
|
||||||
|
- **Plugins**: git, pm2, gh, docker, language-specific plugins, zsh-autosuggestions, zsh-syntax-highlighting
|
||||||
|
|
||||||
|
## Common Commands
|
||||||
|
|
||||||
|
### Environment Setup
|
||||||
|
```bash
|
||||||
|
# Reinitialize shell environment
|
||||||
|
ri # alias for: source ~/.init/init.sh
|
||||||
|
|
||||||
|
# Bootstrap system (run as user, prompts for sudo)
|
||||||
|
sudo -u $USER ansible-playbook -K playbook.yml
|
||||||
|
|
||||||
|
# Run specific Ansible tags
|
||||||
|
ansible-playbook --tags node,python,ruby -K playbook.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Arty Repository Management
|
||||||
|
```bash
|
||||||
|
# Debug Arty configuration
|
||||||
|
pnpm arty debug
|
||||||
|
|
||||||
|
# Clone/update repositories based on environment
|
||||||
|
pnpm arty sync --env dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Git Workflow
|
||||||
|
```bash
|
||||||
|
# Stage all changes and check if clean
|
||||||
|
g0 # alias for: git add . && git diff --quiet && git diff --cached --quiet
|
||||||
|
|
||||||
|
# Reset to single commit
|
||||||
|
g1 # alias for: git reset $(git commit-tree "HEAD^{tree}" -m "A new start")
|
||||||
|
|
||||||
|
# Get last commit message
|
||||||
|
g2 # alias for: git log --format=%B -n 1 HEAD | head -n 1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
```bash
|
||||||
|
# Python pre-commit hooks (configured in .pre-commit-config.yaml)
|
||||||
|
pre-commit run --all-files
|
||||||
|
|
||||||
|
# Ruby style checking
|
||||||
|
rubocop
|
||||||
|
|
||||||
|
# Node.js linting
|
||||||
|
pnpm eslint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Utility Functions
|
||||||
|
Available shell functions from `.init/functions.sh`:
|
||||||
|
- `batch_file_sequence <prefix> <extension>` - Rename files with sequence numbers
|
||||||
|
- `batch_image_webp` - Convert images to WebP format
|
||||||
|
- `batch_video_x264` - Convert videos to x264 codec
|
||||||
|
- `rs` - Rsync with sudo on remote (alias for complex rsync command)
|
||||||
|
- `ss` - Serve current directory on port 8000
|
||||||
|
- `yt <url>` - Download YouTube video as MP3
|
||||||
|
|
||||||
|
## Projects Structure
|
||||||
|
|
||||||
|
The `Projects/` directory contains development projects:
|
||||||
|
- `butter-sh/` - Butter shell projects
|
||||||
|
- `docker-compose/` - Docker compose configurations
|
||||||
|
- `pivoine.art/` - Jekyll-based art portfolio site
|
||||||
|
- `docs.pivoine.art/` - Documentation site
|
||||||
|
- `sexy.pivoine.art/` - Includes Rust package (`packages/buttplug/`)
|
||||||
|
- `node.js/` - Node.js applications (awesome, awesome-app, email-pour-vous, webshot)
|
||||||
|
|
||||||
|
## Package Management
|
||||||
|
|
||||||
|
### Node.js
|
||||||
|
- **Package manager**: pnpm (enabled via corepack)
|
||||||
|
- **Global packages**: Installed to `~/node_modules/`
|
||||||
|
- **PM2**: Configured via `ecosystem.config.js` for GitHub Copilot language server
|
||||||
|
|
||||||
|
### Python
|
||||||
|
- **Installer**: pip
|
||||||
|
- **Dependencies**: Listed in `requirements.txt` (currently: pre-commit)
|
||||||
|
|
||||||
|
### Ruby
|
||||||
|
- **Bundler**: Gemfile specifies Jekyll 4.3 and rubocop
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
- This repository uses selective git tracking - most files are ignored by default
|
||||||
|
- Shell must source `.init/init.sh` for full environment setup (automatically done in `.zshrc`)
|
||||||
|
- Language runtimes are version-managed and installed via Ansible
|
||||||
|
- Docker requires user to be in `docker` group (managed by Ansible)
|
||||||
|
- The `.last_pwd` file tracks the last working directory for shell navigation
|
||||||
7
Gemfile
Normal file
7
Gemfile
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
|
|
||||||
|
gem 'jekyll', '~> 4.3'
|
||||||
|
gem 'rubocop'
|
||||||
478
README.md
Executable file
478
README.md
Executable file
@@ -0,0 +1,478 @@
|
|||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
_ _____ __ __ __ _ _____ ____ _ _____
|
||||||
|
| | / / | / / / //_// | / / | / __ ( ) ___/
|
||||||
|
| | / / /| | / / / ,< / |/ / /| | / /_/ //\__ \
|
||||||
|
| |/ / ___ |/ /___/ /| |/ /| / ___ |/ _, _/ ___/ /
|
||||||
|
|___/_/ |_/_____/_/ |_/_/ |_/_/ |_/_/ |_| /____/
|
||||||
|
|
||||||
|
__________ ____ ____________
|
||||||
|
/ ____/ __ \/ __ \/ ____/ ____/
|
||||||
|
/ /_ / / / / /_/ / / __/ __/
|
||||||
|
/ __/ / /_/ / _, _/ /_/ / /___
|
||||||
|
/_/ \____/_/ |_|\____/_____/
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
# ⚡🔥 WHERE CODE MEETS CHAOS 🔥⚡
|
||||||
|
|
||||||
|
[](https://www.debian.org/)
|
||||||
|
[](https://www.slayer.net/)
|
||||||
|
[](/)
|
||||||
|
[](LICENSE)
|
||||||
|
|
||||||
|
**My Debian home directory - forged in the fires of chaos, tempered with configuration files,**
|
||||||
|
**and wielded with the fury of a thousand riffs.**
|
||||||
|
|
||||||
|
*This is where dotfiles headbang and shell scripts scream.*
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚡ THE ARSENAL ⚡
|
||||||
|
|
||||||
|
### 🎸 **WEAPONS OF MASS DEVELOPMENT**
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────┐
|
||||||
|
│ ⚔️ NODE.JS │ Managed by nvm │
|
||||||
|
│ ⚔️ PYTHON │ Managed by pyenv │
|
||||||
|
│ ⚔️ RUBY │ Managed by rbenv │
|
||||||
|
│ ⚔️ RUST │ Managed by rustup │
|
||||||
|
│ ⚔️ GO │ Managed by gvm │
|
||||||
|
│ ⚔️ DOCKER │ Containerized destruction │
|
||||||
|
│ ⚔️ POSTGRES │ Version 18 database engine │
|
||||||
|
└─────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔴 INITIALIZATION RITUAL 🔴
|
||||||
|
|
||||||
|
### **The `.init/` System - Your Shell's Dark Ceremony**
|
||||||
|
|
||||||
|
The `.init/` directory is the beating heart of this environment. When your shell awakens, it performs a sacred ritual through `~/.init/init.sh`, summoning power from these ancient scripts:
|
||||||
|
|
||||||
|
#### 🗡️ **THE SEVEN STAGES OF POWER**
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
|
│ 1. PATH.SH │ Forges the PATH to all binaries │
|
||||||
|
│ 2. EXPORT.SH │ Exports environment variables │
|
||||||
|
│ 3. ALIAS.SH │ Summons command shortcuts │
|
||||||
|
│ 4. SOURCE.SH │ Sources external power (nvm, cargo, etc) │
|
||||||
|
│ 5. FUNCTIONS.SH │ Unleashes custom shell functions │
|
||||||
|
│ 6. EVAL.SH │ Evaluates version managers (rbenv, etc) │
|
||||||
|
│ 7. START.SH │ Executes startup commands (ssh-add) │
|
||||||
|
└──────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 📜 **DETAILED BREAKDOWN OF EACH SCRIPT**
|
||||||
|
|
||||||
|
##### **1️⃣ `path.sh` - The Path of Destruction**
|
||||||
|
Adds all binary directories to your `$PATH`:
|
||||||
|
- `~/bin` - Your personal executables
|
||||||
|
- `~/.local/bin` - Local user binaries
|
||||||
|
- `~/.rbenv/bin` - Ruby version manager
|
||||||
|
- `~/.pyenv/bin` - Python version manager
|
||||||
|
- `~/.cargo/bin` - Rust binaries
|
||||||
|
- `~/go/bin` - Go binaries
|
||||||
|
- `~/node_modules/.bin` - Node.js binaries
|
||||||
|
- `~/.init/bin` - Custom init scripts
|
||||||
|
- `~/Projects/kompose` - Kompose tooling
|
||||||
|
|
||||||
|
##### **2️⃣ `export.sh` - Environmental Warfare**
|
||||||
|
```bash
|
||||||
|
export NVM_DIR="$HOME/.nvm" # Node Version Manager home
|
||||||
|
export REPOS_DIR="$HOME/repos" # Repository directory
|
||||||
|
export CHORE_CHORE="chore: chore" # Default commit message
|
||||||
|
```
|
||||||
|
|
||||||
|
##### **3️⃣ `alias.sh` - Command Line Sorcery**
|
||||||
|
```bash
|
||||||
|
ri # Reload init: source ~/.init/init.sh
|
||||||
|
g0 # Git stage all and check if clean
|
||||||
|
g1 # Git reset to single commit (nuclear option)
|
||||||
|
g2 # Get last commit message
|
||||||
|
rs # Rsync with sudo on remote
|
||||||
|
ss # Serve static files on port 8000
|
||||||
|
yt # Download YouTube as MP3
|
||||||
|
```
|
||||||
|
|
||||||
|
##### **4️⃣ `source.sh` - External Power Summoning**
|
||||||
|
Sources critical external scripts:
|
||||||
|
- **NVM** - Node Version Manager (`$NVM_DIR/nvm.sh`)
|
||||||
|
- **RVM** - Ruby Version Manager (commented out)
|
||||||
|
- **Cargo** - Rust environment (`~/.cargo/env`)
|
||||||
|
- **Bash completion** for NVM
|
||||||
|
|
||||||
|
##### **5️⃣ `functions.sh` - The Grimoire of Bash**
|
||||||
|
Custom functions for deployment and media manipulation:
|
||||||
|
|
||||||
|
**Git Warfare:**
|
||||||
|
- `_home_push` - Commit and push changes
|
||||||
|
- `_home_pull` - Stash, pull, and pop changes
|
||||||
|
|
||||||
|
**Deployment Spells:**
|
||||||
|
- `_site_deploy_jekyll <site>` - Build & deploy Jekyll site
|
||||||
|
- `_site_deploy_nuxt <site>` - Build & deploy Nuxt site
|
||||||
|
- `_site_deploy_static <site>` - Deploy static files
|
||||||
|
|
||||||
|
**Media Alchemy:**
|
||||||
|
- `batch_file_sequence <prefix> <ext>` - Rename files with numbers
|
||||||
|
- `batch_image_webp` - Convert all images to WebP
|
||||||
|
- `batch_video_x264` - Convert videos to x264 codec
|
||||||
|
- `_image_optimize <name>` - Full image optimization pipeline
|
||||||
|
- `_video_optimize <file>` - Optimize video with ffmpeg
|
||||||
|
|
||||||
|
##### **6️⃣ `eval.sh` - Version Manager Invocation**
|
||||||
|
Initializes version managers through `eval`:
|
||||||
|
- **oh-my-posh** - Shell prompt theme engine
|
||||||
|
- **rbenv** - Ruby version manager
|
||||||
|
- **pyenv** - Python version manager
|
||||||
|
|
||||||
|
##### **7️⃣ `start.sh` - The Final Awakening**
|
||||||
|
Executes startup commands:
|
||||||
|
- `ssh-add` - Adds SSH keys to the agent silently
|
||||||
|
|
||||||
|
#### 🗂️ **Additional Directories**
|
||||||
|
|
||||||
|
- **`.init/bin/`** - Custom executable scripts (e.g., `mime_mp4_gif.sh`)
|
||||||
|
- **`.init/hooks/`** - Reserved for shell hooks (currently empty)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🩸 QUICK START RITUAL 🩸
|
||||||
|
|
||||||
|
### **Summoning the Environment**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Clone this unholy repository
|
||||||
|
git init && git remote add origin git@github.com:valknarogg/home.git
|
||||||
|
git fetch && git reset --hard origin/main
|
||||||
|
git branch --set-upstream-to=origin/main main
|
||||||
|
|
||||||
|
# 2. Install Ansible (if not already installed)
|
||||||
|
sudo apt install git ansible
|
||||||
|
|
||||||
|
# 3. Configure git
|
||||||
|
git config --global init.defaultBranch main
|
||||||
|
git config --global --add safe.directory /home/$USER
|
||||||
|
|
||||||
|
# 4. Unleash the Ansible playbook
|
||||||
|
sudo -u $USER ansible-playbook -K playbook.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Selective Provisioning**
|
||||||
|
|
||||||
|
Run specific parts of the setup using tags:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install only Node.js environment
|
||||||
|
ansible-playbook --tags node -K playbook.yml
|
||||||
|
|
||||||
|
# Install Python + Ruby
|
||||||
|
ansible-playbook --tags python,ruby -K playbook.yml
|
||||||
|
|
||||||
|
# Install everything
|
||||||
|
ansible-playbook -K playbook.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 🏷️ **Available Tags:**
|
||||||
|
`base` | `node` | `python` | `ruby` | `rust` | `zsh` | `postgres` | `docker` | `fonts` | `flatpak` | `github` | `oh-my-posh`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 ARTY - REPOSITORY ORCHESTRATION 🎯
|
||||||
|
|
||||||
|
### **What is Arty?**
|
||||||
|
|
||||||
|
**Arty.sh** is a bash-based dependency and repository manager that orchestrates git subrepositories like a conductor of chaos. It's part of the [butter.sh](https://github.com/butter-sh/butter-sh.github.io) ecosystem - a suite of bash development tools.
|
||||||
|
|
||||||
|
### **Installing Arty**
|
||||||
|
|
||||||
|
Arty is already installed globally at `/usr/local/bin/arty`. If you need to install/update it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone butter.sh ecosystem
|
||||||
|
git clone https://github.com/butter-sh/butter-sh.github.io.git ~/Projects/butter-sh
|
||||||
|
|
||||||
|
# Install arty globally (requires sudo)
|
||||||
|
cd ~/Projects/butter-sh/projects/arty.sh
|
||||||
|
sudo ./arty.sh install
|
||||||
|
```
|
||||||
|
|
||||||
|
### **The `arty.yml` Configuration**
|
||||||
|
|
||||||
|
The root `~/arty.yml` defines your entire repository ecosystem:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: "Valknar's home"
|
||||||
|
version: "1.0.0"
|
||||||
|
|
||||||
|
envs:
|
||||||
|
dev: # Development environment
|
||||||
|
prod: # Production environment
|
||||||
|
|
||||||
|
references:
|
||||||
|
# Project repositories
|
||||||
|
- url: git@github.com:valknarogg/pivoine.art.git
|
||||||
|
into: Projects/pivoine.art
|
||||||
|
env: dev
|
||||||
|
|
||||||
|
# Media repositories
|
||||||
|
- url: git@github.com:valknarogg/home-pictures.git
|
||||||
|
into: Bilder
|
||||||
|
env: dev
|
||||||
|
|
||||||
|
# Version managers
|
||||||
|
- url: https://github.com/nvm-sh/nvm.git
|
||||||
|
into: .nvm
|
||||||
|
|
||||||
|
# ... and many more
|
||||||
|
|
||||||
|
scripts:
|
||||||
|
debug: echo "$ARTY_BIN_DIR" && echo "$ARTY_LIBS_DIR"
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Using Arty**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Sync all dev environment repositories
|
||||||
|
arty sync --env dev
|
||||||
|
|
||||||
|
# Sync production repositories only
|
||||||
|
arty sync --env prod
|
||||||
|
|
||||||
|
# Install dependencies from arty.yml
|
||||||
|
arty install
|
||||||
|
|
||||||
|
# Run custom scripts defined in arty.yml
|
||||||
|
arty debug
|
||||||
|
|
||||||
|
# Show dependency tree
|
||||||
|
arty deps
|
||||||
|
|
||||||
|
# Update a specific reference
|
||||||
|
arty update pivoine.art
|
||||||
|
```
|
||||||
|
|
||||||
|
### **What Arty Manages:**
|
||||||
|
- ✅ Project repositories (pivoine.art, sexy.pivoine.art, etc.)
|
||||||
|
- ✅ Media repositories (Pictures, Videos, Music)
|
||||||
|
- ✅ Docker compose configurations
|
||||||
|
- ✅ Version managers (nvm, rbenv, pyenv, gvm)
|
||||||
|
- ✅ Oh-My-Zsh and plugins
|
||||||
|
- ✅ Shell scripts and binaries
|
||||||
|
|
||||||
|
### **Environment-Based Management**
|
||||||
|
|
||||||
|
References can be tagged with `env: dev` or `env: prod` to control which repositories are synced in different environments. This allows you to:
|
||||||
|
- Keep heavy media files out of production servers
|
||||||
|
- Separate development projects from system utilities
|
||||||
|
- Maintain clean, minimal deployments
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔥 COMMAND LINE BRUTALITY 🔥
|
||||||
|
|
||||||
|
### **Git Operations**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
g0 # Stage all changes and verify clean state
|
||||||
|
g1 # Nuclear reset to single commit
|
||||||
|
g2 # Show last commit message
|
||||||
|
git add -A && git commit -m "$(g2)" # Reuse last commit message
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Media Processing**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Convert all images in directory to WebP
|
||||||
|
batch_image_webp
|
||||||
|
|
||||||
|
# Rename files with sequence numbers
|
||||||
|
batch_file_sequence artwork webp
|
||||||
|
|
||||||
|
# Optimize video
|
||||||
|
_video_optimize input.mov
|
||||||
|
|
||||||
|
# Download YouTube video as MP3
|
||||||
|
yt "https://youtube.com/watch?v=..."
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Development Servers**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Serve current directory on port 8000
|
||||||
|
ss
|
||||||
|
|
||||||
|
# Run Jekyll site with livereload
|
||||||
|
cd ~/Projects/pivoine.art && bundle exec jekyll serve --livereload
|
||||||
|
|
||||||
|
# Run Node.js dev server
|
||||||
|
cd ~/Projects/node.js/awesome && pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Rsync Power**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Sync to remote with sudo
|
||||||
|
rs /local/path/ user@host:/remote/path/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 PROJECT STRUCTURE 📁
|
||||||
|
|
||||||
|
```
|
||||||
|
~/Projects/
|
||||||
|
├── butter-sh/ # Butter.sh ecosystem (arty, judge, myst, etc.)
|
||||||
|
├── docker-compose/ # Docker orchestration configs
|
||||||
|
├── pivoine.art/ # Jekyll art portfolio (main site)
|
||||||
|
├── docs.pivoine.art/ # Documentation site
|
||||||
|
├── sexy.pivoine.art/ # Rust + web project (includes buttplug package)
|
||||||
|
└── node.js/
|
||||||
|
├── awesome/ # GitHub Awesome lists browser
|
||||||
|
├── awesome-app/ # Awesome list application
|
||||||
|
├── email-pour-vous/ # Email templating project
|
||||||
|
└── webshot/ # Website screenshot tool
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ DOTFILE HIGHLIGHTS 🛠️
|
||||||
|
|
||||||
|
### **Shell Configuration**
|
||||||
|
- **`.zshrc`** - Oh-My-Zsh with Powerlevel10k theme
|
||||||
|
- **`.p10k.zsh`** - Powerlevel10k configuration
|
||||||
|
- **`.bashrc`** - Bash configuration (fallback)
|
||||||
|
|
||||||
|
### **Version Files**
|
||||||
|
- **`.nvmrc`** - Node.js version
|
||||||
|
- **`.ruby-version`** - Ruby version
|
||||||
|
- **`.python-version`** - Python version
|
||||||
|
|
||||||
|
### **Code Quality**
|
||||||
|
- **`.pre-commit-config.yaml`** - Pre-commit hooks (Python)
|
||||||
|
- **`.rubocop.yml`** - Ruby style enforcement
|
||||||
|
- **`eslint.config.mts`** - JavaScript/TypeScript linting
|
||||||
|
- **`.prettierrc`** - Code formatting rules
|
||||||
|
- **`biome.json`** - Fast linter/formatter
|
||||||
|
|
||||||
|
### **Package Management**
|
||||||
|
- **`requirements.txt`** - Python packages (pip)
|
||||||
|
- **`Gemfile`** - Ruby gems (bundler)
|
||||||
|
|
||||||
|
### **Git Configuration**
|
||||||
|
- **`.gitignore`** - INVERTED PATTERN (ignore all, allow specific files)
|
||||||
|
- **`.gitconfig`** - Git user configuration
|
||||||
|
|
||||||
|
### **Orchestration**
|
||||||
|
- **`arty.yml`** - Repository and dependency management
|
||||||
|
- **`playbook.yml`** - Ansible system provisioning
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ GIT SELECTIVE TRACKING ⚙️
|
||||||
|
|
||||||
|
This repository uses an **inverted `.gitignore`** pattern:
|
||||||
|
|
||||||
|
```gitignore
|
||||||
|
# Ignore everything
|
||||||
|
*
|
||||||
|
|
||||||
|
# Allow specific files
|
||||||
|
!CLAUDE.md
|
||||||
|
!README.md
|
||||||
|
!.gitignore
|
||||||
|
!.init/**
|
||||||
|
!arty.yml
|
||||||
|
!playbook.yml
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why?** To track only essential dotfiles and configurations while ignoring cache, logs, and user data. Your home directory becomes a git repository without the chaos.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎸 SHELL PLUGIN POWER 🎸
|
||||||
|
|
||||||
|
**Oh-My-Zsh Plugins Loaded:**
|
||||||
|
```
|
||||||
|
git pm2 gh sudo ssh ruby rust python node github
|
||||||
|
rsync nvm rbenv pyenv docker docker-compose qrcode
|
||||||
|
zsh-autosuggestions zsh-syntax-highlighting
|
||||||
|
zsh-interactive-cd zsh-navigation-tools
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 USEFUL RESOURCES 🔗
|
||||||
|
|
||||||
|
### System & Shell
|
||||||
|
- [Ansible Documentation](https://docs.ansible.com/)
|
||||||
|
- [Oh-My-Zsh](https://ohmyz.sh/)
|
||||||
|
- [Powerlevel10k](https://github.com/romkatv/powerlevel10k)
|
||||||
|
|
||||||
|
### Language Managers
|
||||||
|
- [nvm](https://github.com/nvm-sh/nvm) - Node Version Manager
|
||||||
|
- [rbenv](https://github.com/rbenv/rbenv) - Ruby Version Manager
|
||||||
|
- [pyenv](https://github.com/pyenv/pyenv) - Python Version Manager
|
||||||
|
- [gvm](https://github.com/moovweb/gvm) - Go Version Manager
|
||||||
|
- [rustup](https://rustup.rs/) - Rust Toolchain Manager
|
||||||
|
|
||||||
|
### Orchestration
|
||||||
|
- [Arty.sh Documentation](https://github.com/butter-sh/butter-sh.github.io)
|
||||||
|
- [Butter.sh Ecosystem](https://butter.sh)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖤 LICENSE 🖤
|
||||||
|
|
||||||
|
MIT License - Do whatever the hell you want with it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
═════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
__________ ____ ______ _________
|
||||||
|
/ ____/ __ \/ __ \/ ____/ / _/ ___/
|
||||||
|
/ / / / / / / / / __/ / / \__ \
|
||||||
|
/ /___/ /_/ / /_/ / /___ _/ / ___/ /
|
||||||
|
\____/\____/_____/_____/ /___//____/
|
||||||
|
|
||||||
|
______________ _______ ____ ____ ___ ______ __
|
||||||
|
/_ __/ ____/ |/ / __ \/ __ \/ __ \/ | / __ \ \/ /
|
||||||
|
/ / / __/ / /|_/ / /_/ / / / / /_/ / /| | / /_/ /\ /
|
||||||
|
/ / / /___/ / / / ____/ /_/ / _, _/ ___ |/ _, _/ / /
|
||||||
|
/_/ /_____/_/ /_/_/ \____/_/ |_/_/ |_/_/ |_| /_/
|
||||||
|
|
||||||
|
__ __________________ __ _________
|
||||||
|
/ |/ / ____/_ __/ | / / / _/ ___/
|
||||||
|
/ /|_/ / __/ / / / /| | / / / / \__ \
|
||||||
|
/ / / / /___ / / / ___ |/ /___ _/ / ___/ /
|
||||||
|
/_/ /_/_____/ /_/ /_/ |_/_____/ /___//____/
|
||||||
|
|
||||||
|
______________________ _ _____ __
|
||||||
|
/ ____/_ __/ ____/ __ \/ | / / | / /
|
||||||
|
/ __/ / / / __/ / /_/ / |/ / /| | / /
|
||||||
|
/ /___ / / / /___/ _, _/ /| / ___ |/ /___
|
||||||
|
/_____/ /_/ /_____/_/ |_/_/ |_/_/ |_/_____/
|
||||||
|
|
||||||
|
═════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
🔥⚡ FORGED BY VALKNAR ⚡🔥
|
||||||
|
valknar@pivoine.art
|
||||||
|
Powered by Debian | Fueled by Metal
|
||||||
|
|
||||||
|
🤘 🤘 🤘
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
**[⚔️ BACK TO THE TOP ⚔️](#)**
|
||||||
|
|
||||||
|
</div>
|
||||||
65
arty.yml
Normal file
65
arty.yml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
name: "Valknar's home"
|
||||||
|
version: "1.0.0"
|
||||||
|
description: "Valknar's home repository"
|
||||||
|
author: "valknar@pivoine.art"
|
||||||
|
license: "MIT"
|
||||||
|
|
||||||
|
envs:
|
||||||
|
dev:
|
||||||
|
prod:
|
||||||
|
|
||||||
|
|
||||||
|
references:
|
||||||
|
- url: git@github.com:butter-sh/butter-sh.github.io.git
|
||||||
|
into: Projects/butter-sh
|
||||||
|
env: dev
|
||||||
|
- url: git@github.com:valknarogg/home-pictures.git
|
||||||
|
into: Bilder
|
||||||
|
env: dev
|
||||||
|
- url: git@github.com:valknarogg/home-videos.git
|
||||||
|
into: Videos
|
||||||
|
ref: main
|
||||||
|
env: dev
|
||||||
|
- url: git@github.com:valknarogg/home-music.git
|
||||||
|
into: Musik
|
||||||
|
ref: main
|
||||||
|
env: dev
|
||||||
|
- url: git@github.com:valknarogg/docker-compose.git
|
||||||
|
into: Projects/docker-compose
|
||||||
|
env:
|
||||||
|
- dev
|
||||||
|
- prod
|
||||||
|
- url: git@github.com:valknarogg/pivoine.art.git
|
||||||
|
into: Projects/pivoine.art
|
||||||
|
ref: main
|
||||||
|
env: dev
|
||||||
|
- url: git@github.com:valknarxxx/sexy.pivoine.art.git
|
||||||
|
into: Projects/sexy.pivoine.art
|
||||||
|
env: dev
|
||||||
|
- url: git@github.com:valknarness/awesome.git
|
||||||
|
into: Projects/node.js/awesome
|
||||||
|
env:
|
||||||
|
- dev
|
||||||
|
- prod
|
||||||
|
- url: git@github.com:valknarness/awesome-app.git
|
||||||
|
into: Projects/node.js/awesome-app
|
||||||
|
env: dev
|
||||||
|
- url: https://github.com/nvm-sh/nvm.git
|
||||||
|
into: .nvm
|
||||||
|
- url: https://github.com/moovweb/gvm.git
|
||||||
|
into: .gvm
|
||||||
|
- url: https://github.com/rbenv/rbenv.git
|
||||||
|
into: .rbenv
|
||||||
|
- url: https://github.com/pyenv/pyenv.git
|
||||||
|
into: .pyenv
|
||||||
|
- url: https://github.com/ohmyzsh/ohmyzsh.git
|
||||||
|
into: .oh-my-zsh
|
||||||
|
- url: https://github.com/romkatv/powerlevel10k.git
|
||||||
|
into: .oh-my-zsh/custom/themes/powerlevel10k
|
||||||
|
- url: https://github.com/zsh-users/zsh-autosuggestions.git
|
||||||
|
into: .oh-my-zsh/custom/plugins/zsh-autosuggestions
|
||||||
|
- url: https://github.com/zsh-users/zsh-syntax-highlighting.git
|
||||||
|
into: .oh-my-zsh/custom/plugins/zsh-syntax-highlighting
|
||||||
|
|
||||||
|
scripts:
|
||||||
|
debug: echo "$ARTY_BIN_DIR" && echo "$ARTY_LIBS_DIR" && echo "$ARTY_HOME"
|
||||||
34
biome.json
Normal file
34
biome.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/2.2.4/schema.json",
|
||||||
|
"vcs": {
|
||||||
|
"enabled": true,
|
||||||
|
"clientKind": "git",
|
||||||
|
"useIgnoreFile": true
|
||||||
|
},
|
||||||
|
"files": {
|
||||||
|
"ignoreUnknown": false
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"indentStyle": "tab"
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"rules": {
|
||||||
|
"recommended": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"javascript": {
|
||||||
|
"formatter": {
|
||||||
|
"quoteStyle": "double"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"assist": {
|
||||||
|
"enabled": true,
|
||||||
|
"actions": {
|
||||||
|
"source": {
|
||||||
|
"organizeImports": "on"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
ecosystem.config.js
Normal file
9
ecosystem.config.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
module.exports = {
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: "language-server",
|
||||||
|
script:
|
||||||
|
"./node_modules/@github/copilot-language-server/dist/language-server.js",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
14
eslint.config.mts
Normal file
14
eslint.config.mts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import js from "@eslint/js";
|
||||||
|
import globals from "globals";
|
||||||
|
import tseslint from "typescript-eslint";
|
||||||
|
import { defineConfig } from "eslint/config";
|
||||||
|
|
||||||
|
export default defineConfig([
|
||||||
|
{
|
||||||
|
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
|
||||||
|
plugins: { js },
|
||||||
|
extends: ["js/recommended"],
|
||||||
|
languageOptions: { globals: globals.browser },
|
||||||
|
},
|
||||||
|
tseslint.configs.recommended,
|
||||||
|
]);
|
||||||
288
playbook.yml
Normal file
288
playbook.yml
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
- hosts: localhost
|
||||||
|
connection: local
|
||||||
|
tasks:
|
||||||
|
- name: Install base packages
|
||||||
|
become: true
|
||||||
|
|
||||||
|
ansible.builtin.apt:
|
||||||
|
pkg:
|
||||||
|
- make
|
||||||
|
- build-essential
|
||||||
|
- git
|
||||||
|
- curl
|
||||||
|
- wget
|
||||||
|
- rsync
|
||||||
|
- zsh
|
||||||
|
- imagemagick
|
||||||
|
- ffmpeg
|
||||||
|
- yt-dlp
|
||||||
|
- fzf
|
||||||
|
- icoutils
|
||||||
|
- postgresql-common
|
||||||
|
- unzip
|
||||||
|
tags:
|
||||||
|
- base
|
||||||
|
- python
|
||||||
|
- ruby
|
||||||
|
- rust
|
||||||
|
- zsh
|
||||||
|
- postgres
|
||||||
|
|
||||||
|
- name: Prepare postgresql
|
||||||
|
ansible.builtin.shell: /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
tags:
|
||||||
|
- postgres
|
||||||
|
|
||||||
|
- name: Install postgres package
|
||||||
|
become: true
|
||||||
|
ansible.builtin.apt:
|
||||||
|
pkg:
|
||||||
|
- postgresql-18
|
||||||
|
update_cache: true
|
||||||
|
tags:
|
||||||
|
- postgres
|
||||||
|
|
||||||
|
- name: Change root shell to zsh
|
||||||
|
become: true
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: root
|
||||||
|
shell: /bin/zsh
|
||||||
|
tags:
|
||||||
|
- oh-my-posh
|
||||||
|
|
||||||
|
- name: Give permissions to /root/bin
|
||||||
|
become: true
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /root/bin
|
||||||
|
state: directory
|
||||||
|
tags:
|
||||||
|
- oh-my-posh
|
||||||
|
|
||||||
|
- name: Install oh-my-posh for root
|
||||||
|
become: true
|
||||||
|
ansible.builtin.shell: curl -s https://ohmyposh.dev/install.sh | bash -s -- -d /root/bin
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
tags:
|
||||||
|
- oh-my-posh
|
||||||
|
|
||||||
|
- name: Ensure root shell loads user bin
|
||||||
|
become: true
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /root/.zshrc
|
||||||
|
line: |
|
||||||
|
export PATH="$PATH:/root/bin"
|
||||||
|
if [ "$TERM_PROGRAM" != "Apple_Terminal" ]; then
|
||||||
|
eval "$(oh-my-posh init zsh)"
|
||||||
|
fi
|
||||||
|
create: yes
|
||||||
|
tags:
|
||||||
|
- oh-my-posh
|
||||||
|
|
||||||
|
- name: Install node
|
||||||
|
ansible.builtin.shell: source ~/.init/init.sh && nvm install
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
tags:
|
||||||
|
- node
|
||||||
|
|
||||||
|
- name: Enable node corepack
|
||||||
|
ansible.builtin.shell: source ~/.init/init.sh && corepack enable
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
tags:
|
||||||
|
- node
|
||||||
|
|
||||||
|
- name: Install node packages
|
||||||
|
ansible.builtin.shell: source ~/.init/init.sh && cd ~ && pnpm install
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
tags:
|
||||||
|
- node
|
||||||
|
|
||||||
|
- name: Install python required packages
|
||||||
|
become: true
|
||||||
|
ansible.builtin.apt:
|
||||||
|
pkg:
|
||||||
|
- libssl-dev
|
||||||
|
- zlib1g-dev
|
||||||
|
- libbz2-dev
|
||||||
|
- libreadline-dev
|
||||||
|
- libsqlite3-dev
|
||||||
|
- llvm
|
||||||
|
- libncurses5-dev
|
||||||
|
tags:
|
||||||
|
- python
|
||||||
|
|
||||||
|
- name: Install python
|
||||||
|
ansible.builtin.shell: source ~/.init/init.sh && pyenv install --skip-existing
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
tags:
|
||||||
|
- python
|
||||||
|
|
||||||
|
- name: Install python packages
|
||||||
|
ansible.builtin.shell: source ~/.init/init.sh && pip install -r ~/requirements.txt
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
tags:
|
||||||
|
- python
|
||||||
|
|
||||||
|
- name: Init python pre-commit
|
||||||
|
ansible.builtin.shell: source ~/.init/init.sh && cd ~ && pre-commit install
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
tags:
|
||||||
|
- python
|
||||||
|
|
||||||
|
- name: Install ruby required packages
|
||||||
|
become: true
|
||||||
|
ansible.builtin.apt:
|
||||||
|
pkg:
|
||||||
|
- libssl-dev
|
||||||
|
- libffi-dev
|
||||||
|
- libyaml-dev
|
||||||
|
- zlib1g-dev
|
||||||
|
tags:
|
||||||
|
- ruby
|
||||||
|
|
||||||
|
- name: Install ruby
|
||||||
|
ansible.builtin.shell: source ~/.init/init.sh && rbenv install --skip-existing
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
tags:
|
||||||
|
- ruby
|
||||||
|
|
||||||
|
- name: Install ruby base packages
|
||||||
|
ansible.builtin.shell: source ~/.init/init.sh && gem install {{ item }}
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
with_items:
|
||||||
|
- bundler
|
||||||
|
tags:
|
||||||
|
- ruby
|
||||||
|
|
||||||
|
- name: Install ruby packages
|
||||||
|
ansible.builtin.shell: source ~/.init/init.sh && cd ~ && bundle install
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
tags:
|
||||||
|
- ruby
|
||||||
|
|
||||||
|
- name: Install rust required packages
|
||||||
|
become: true
|
||||||
|
ansible.builtin.apt:
|
||||||
|
pkg:
|
||||||
|
- libudev-dev
|
||||||
|
- libusb-1.0-0-dev
|
||||||
|
- libdbus-1-dev
|
||||||
|
- pkg-config
|
||||||
|
- cmake
|
||||||
|
tags:
|
||||||
|
- rust
|
||||||
|
|
||||||
|
- name: Download Installer for rust
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: https://sh.rustup.rs
|
||||||
|
dest: /tmp/sh.rustup.rs
|
||||||
|
mode: '0755'
|
||||||
|
force: 'yes'
|
||||||
|
tags:
|
||||||
|
- rust
|
||||||
|
|
||||||
|
- name: Install rust
|
||||||
|
ansible.builtin.shell: /tmp/sh.rustup.rs -y
|
||||||
|
tags:
|
||||||
|
- rust
|
||||||
|
|
||||||
|
- name: Change user shell to zsh
|
||||||
|
become: true
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: '{{ ansible_user_id }}'
|
||||||
|
shell: /bin/zsh
|
||||||
|
tags:
|
||||||
|
- zsh
|
||||||
|
|
||||||
|
- name: Update font cache
|
||||||
|
ansible.builtin.shell: fc-cache -f -v
|
||||||
|
tags:
|
||||||
|
- fonts
|
||||||
|
|
||||||
|
- name: Install flatpak required packages
|
||||||
|
become: true
|
||||||
|
ansible.builtin.apt:
|
||||||
|
pkg:
|
||||||
|
- flatpak
|
||||||
|
- gnome-software-plugin-flatpak
|
||||||
|
- libgtk-3-dev
|
||||||
|
tags:
|
||||||
|
- flatpak
|
||||||
|
|
||||||
|
- name: Add flathub repo
|
||||||
|
ansible.builtin.shell: flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||||
|
tags:
|
||||||
|
- flatpak
|
||||||
|
|
||||||
|
- name: Install github required packages
|
||||||
|
become: true
|
||||||
|
ansible.builtin.apt:
|
||||||
|
pkg:
|
||||||
|
- gh
|
||||||
|
tags:
|
||||||
|
- github
|
||||||
|
|
||||||
|
# - name: Add github copilot extension
|
||||||
|
# ansible.builtin.shell: gh extension install github/gh-copilot
|
||||||
|
# tags:
|
||||||
|
# - github
|
||||||
|
|
||||||
|
- name: Install Docker required packages
|
||||||
|
become: true
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- apt-transport-https
|
||||||
|
- ca-certificates
|
||||||
|
- curl
|
||||||
|
- gnupg2
|
||||||
|
- postgresql-client
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
- name: Add Docker repository
|
||||||
|
ansible.builtin.deb822_repository:
|
||||||
|
name: docker
|
||||||
|
uris: https://download.docker.com/linux/debian
|
||||||
|
types: deb
|
||||||
|
suites: trixie
|
||||||
|
architectures: amd64
|
||||||
|
components: stable
|
||||||
|
signed_by: https://download.docker.com/linux/debian/gpg
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
- name: Install Docker Engine
|
||||||
|
become: true
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- docker-ce
|
||||||
|
- docker-ce-cli
|
||||||
|
- containerd.io
|
||||||
|
update_cache: true
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
|
||||||
|
- name: Add user to docker group
|
||||||
|
become: true
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: '{{ ansible_user_id }}'
|
||||||
|
groups: docker
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
|
||||||
|
- name: Start Docker service
|
||||||
|
become: true
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: docker
|
||||||
|
state: started
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pre-commit
|
||||||
Reference in New Issue
Block a user