diff --git a/autoclicker-enhanced.sh b/autoclicker-enhanced.sh
new file mode 100755
index 0000000..2a4e53f
--- /dev/null
+++ b/autoclicker-enhanced.sh
@@ -0,0 +1,235 @@
+#!/bin/bash
+
+# Enhanced Autoclicker script for Sway with improved antiban features
+# Uses ydotool for Wayland/Sway environments
+# Features human-like timing patterns and CSV logging for visualization
+# Press Ctrl+C to stop (standard shell interrupt)
+# Requires ydotool and ydotoold daemon running
+
+# Configuration
+MIN_DELAY=50 # Minimum delay in milliseconds
+MAX_DELAY=700 # Maximum delay in milliseconds
+MIN_CLICKS_BEFORE_BREAK=30 # Minimum clicks before break
+MAX_CLICKS_BEFORE_BREAK=200 # Maximum clicks before break
+MIN_BREAK=3 # Minimum break duration in seconds
+MAX_BREAK=15 # Maximum break duration in seconds
+
+# Human-like timing parameters
+FASTIGUE_FACTOR=0.95 # Gradually slow down over time (0.95 = 5% slower)
+REACTION_VARIATION=0.3 # 30% variation in reaction times
+PATTERN_BREAK_CHANCE=0.05 # 5% chance to break pattern
+
+# File paths
+STATE_FILE="/tmp/autoclicker_running"
+LOCK_FILE="/tmp/autoclicker_lock"
+LOG_DIR="/tmp/autoclicker_logs"
+LOG_FILE="$LOG_DIR/click_timings_$(date +%Y%m%d_%H%M%S).csv"
+
+# Create log directory if it doesn't exist
+mkdir -p "$LOG_DIR"
+
+# Initialize CSV log file with header
+echo "click_number,delay_ms,timestamp" > "$LOG_FILE"
+
+# Check if ydotool is available
+if ! command -v ydotool &> /dev/null; then
+ echo "Error: ydotool is not installed. Install it with: sudo pacman -S ydotool"
+ exit 1
+fi
+
+# Check if bc is available (needed for calculations)
+if ! command -v bc &> /dev/null; then
+ echo "Error: bc is not installed. Install it with: sudo pacman -S bc"
+ exit 1
+fi
+
+# Check if script is already running (prevent multiple instances)
+if [ -f "$LOCK_FILE" ]; then
+ echo "Autoclicker is already running!"
+ echo "Press Ctrl+C in the terminal where it's running to stop it."
+ # Clean up the incomplete log file that was just created
+ rm -f "$LOG_FILE"
+ exit 0
+fi
+
+# Create lock file
+echo $$ > "$LOCK_FILE"
+
+# Global exit flag
+EXIT_REQUESTED=0
+
+# Clean up on exit
+cleanup() {
+ EXIT_REQUESTED=1
+ rm -f "$LOCK_FILE"
+ rm -f "$STATE_FILE"
+ echo ""
+ echo "Autoclicker stopped."
+ exit 0
+}
+
+# Set up traps for cleanup
+trap cleanup INT TERM
+
+# Check if ydotoold daemon is running
+if ! pgrep -x "ydotoold" > /dev/null; then
+ echo "Starting ydotoold daemon..."
+ sudo ydotoold &
+ sleep 1
+fi
+
+# Create state file to indicate running
+echo "running" > "$STATE_FILE"
+
+# Function to log click timing to CSV
+log_click_timing() {
+ local click_number=$1
+ local delay_ms=$2
+ local timestamp=$(date +%s%3N) # Milliseconds since epoch
+ echo "$click_number,$delay_ms,$timestamp" >> "$LOG_FILE"
+}
+
+# Function to generate random delay with human-like distribution
+get_human_delay() {
+ local min=$1
+ local max=$2
+ local base_delay=$((min + RANDOM % (max - min + 1)))
+
+ # Apply reaction time variation (30% up or down)
+ local variation=$(echo "scale=3; $base_delay * $REACTION_VARIATION * (2 * $RANDOM / 32767 - 1)" | bc)
+ local varied_delay=$(echo "$base_delay + $variation" | bc)
+
+ # Ensure we stay within reasonable bounds
+ if (( $(echo "$varied_delay < $min" | bc -l) )); then
+ varied_delay=$min
+ elif (( $(echo "$varied_delay > $max" | bc -l) )); then
+ varied_delay=$max
+ fi
+
+ # Convert to seconds for sleep function
+ echo "scale=3; $varied_delay / 1000" | bc
+}
+
+# Function to generate random number of clicks before break
+get_random_clicks() {
+ local min=$1
+ local max=$2
+ echo $((min + RANDOM % (max - min + 1)))
+}
+
+# Function to sleep with interrupt checking
+interruptible_sleep() {
+ local duration=$1
+ local start_time=$(date +%s.%N)
+ local end_time=$(echo "$start_time + $duration" | bc)
+
+ while true; do
+ if [ $EXIT_REQUESTED -eq 1 ]; then
+ return 1 # Exit requested
+ fi
+
+ local current_time=$(date +%s.%N)
+ if (( $(echo "$current_time >= $end_time" | bc -l) )); then
+ return 0 # Sleep completed
+ fi
+
+ sleep 0.1
+ done
+}
+
+# Function to apply fatigue effect (gradually slow down)
+apply_fatigue() {
+ local current_delay=$1
+ local click_count=$2
+ local fatigue_effect=$(echo "scale=3; $current_delay * (1 + $FASTIGUE_FACTOR * $click_count / 1000)" | bc)
+ echo "$fatigue_effect"
+}
+
+# Function to randomly break pattern (5% chance)
+should_break_pattern() {
+ local threshold=$(echo "$PATTERN_BREAK_CHANCE * 32767" | bc | cut -d'.' -f1)
+ [ $RANDOM -lt $threshold ]
+}
+
+echo "=========================================="
+echo "Enhanced Autoclicker started!"
+echo "=========================================="
+echo "Configuration:"
+echo " - Click delay: ${MIN_DELAY}-${MAX_DELAY}ms (human-like variation)"
+echo " - Break every: ${MIN_CLICKS_BEFORE_BREAK}-${MAX_CLICKS_BEFORE_BREAK} clicks (random)"
+echo " - Break duration: ${MIN_BREAK}-${MAX_BREAK}s"
+echo " - Fatigue factor: ${FASTIGUE_FACTOR} (gradual slowdown)"
+echo " - Pattern break chance: ${PATTERN_BREAK_CHANCE} (5%)"
+echo " - Logging to: $LOG_FILE"
+echo ""
+echo "Press Ctrl+C to stop"
+echo "=========================================="
+echo ""
+
+click_count=0
+total_clicks=0
+clicks_before_break=$(get_random_clicks $MIN_CLICKS_BEFORE_BREAK $MAX_CLICKS_BEFORE_BREAK)
+echo "Next break will be after $clicks_before_break clicks"
+echo ""
+
+while true; do
+ if [ $EXIT_REQUESTED -eq 1 ]; then
+ echo "Exit signal received!"
+ break
+ fi
+
+ # Generate base random delay
+ base_delay=$(get_human_delay $MIN_DELAY $MAX_DELAY)
+
+ # Apply fatigue effect (gradually slow down)
+ final_delay=$(apply_fatigue "$base_delay" "$click_count")
+
+ # Randomly break pattern (5% chance)
+ if should_break_pattern; then
+ # Add a longer, unpredictable delay
+ pattern_break_delay=$(echo "scale=3; ($MAX_DELAY * 2 + $RANDOM % 1000) / 1000" | bc)
+ echo "[Pattern Break] Adding unpredictable delay of $(echo "$pattern_break_delay * 1000" | bc | cut -d'.' -f1)ms"
+
+ if ! interruptible_sleep "$pattern_break_delay"; then
+ break
+ fi
+ fi
+
+ # Perform click (suppress ydotool output)
+ ydotool click 0xC0 2>/dev/null
+ click_count=$((click_count + 1))
+ total_clicks=$((total_clicks + 1))
+
+ # Convert delay to milliseconds for display
+ delay_ms=$(echo "$final_delay * 1000" | bc | cut -d'.' -f1)
+
+ # Log click timing to CSV
+ log_click_timing "$total_clicks" "$delay_ms"
+
+ # Show each click with its delay
+ echo "Click #$total_clicks (delay: ${delay_ms}ms, next break in $((clicks_before_break - click_count)) clicks)"
+
+ # Check if it's time for a break
+ if [ $click_count -ge $clicks_before_break ]; then
+ break_duration=$(get_human_delay $((MIN_BREAK * 1000)) $((MAX_BREAK * 1000)))
+ echo ""
+ echo "[Break] Completed $clicks_before_break clicks (total: $total_clicks). Taking a break for ${break_duration}s..."
+
+ if ! interruptible_sleep "$break_duration"; then
+ break
+ fi
+
+ click_count=0
+ # Generate new random click count for next cycle
+ clicks_before_break=$(get_random_clicks $MIN_CLICKS_BEFORE_BREAK $MAX_CLICKS_BEFORE_BREAK)
+ echo "[Resumed] Next break will be after $clicks_before_break clicks"
+ echo ""
+ else
+ # Wait the calculated delay before next click
+ if ! interruptible_sleep "$final_delay"; then
+ break
+ fi
+ fi
+done
+
+echo "Click timings saved to: $LOG_FILE"
\ No newline at end of file
diff --git a/autoclicker.sh b/autoclicker.sh
index 00c55e1..6fd25e5 100755
--- a/autoclicker.sh
+++ b/autoclicker.sh
@@ -133,4 +133,3 @@ while true; do
sleep "$delay"
fi
done
-
diff --git a/click-visualizer.html b/click-visualizer.html
new file mode 100644
index 0000000..03d6b57
--- /dev/null
+++ b/click-visualizer.html
@@ -0,0 +1,619 @@
+
+
+
+
+
+ Autoclicker Timing Visualizer
+
+
+
+
+
🖱️ Autoclicker Timing Visualizer
+
+
+
📊 Real-time Data Server
+
This visualizer connects to a local Python server that serves real log files from /tmp/autoclicker_logs/
+
Make sure to run: python3 click_server.py in a separate terminal
+
+
+
+ Testing API connection...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Click Timing Distribution
+
+
+
+
+
+
+
Delay Over Time
+
+
+
+
+
+
+
Available Log Files
+
+
Loading log files from server...
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/click_server.py b/click_server.py
new file mode 100755
index 0000000..dbb7059
--- /dev/null
+++ b/click_server.py
@@ -0,0 +1,183 @@
+#!/usr/bin/env python3
+
+"""
+Simple web server for autoclicker visualization
+Serves the HTML visualizer and provides API endpoints for CSV log files
+Converts CSV to JSON for the frontend
+"""
+
+import os
+import json
+import csv
+import http.server
+import socketserver
+from urllib.parse import urlparse, parse_qs
+from datetime import datetime
+
+PORT = 8661
+LOG_DIR = "/tmp/autoclicker_logs"
+
+class ClickServerHandler(http.server.SimpleHTTPRequestHandler):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, directory=".", **kwargs)
+
+ def do_GET(self):
+ # Handle API requests
+ if self.path.startswith('/api/'):
+ self.handle_api_request()
+ return
+
+ # Serve the visualizer HTML for root path
+ if self.path == '/' or self.path == '/index.html':
+ self.path = '/click-visualizer.html'
+
+ # Serve static files normally
+ return super().do_GET()
+
+ def handle_api_request(self):
+ """Handle API endpoints for log file operations"""
+ try:
+ if self.path.startswith('/api/logs'):
+ self.handle_logs_request()
+ elif self.path.startswith('/api/log/'):
+ self.handle_log_file_request()
+ else:
+ self.send_error(404, "API endpoint not found")
+ except Exception as e:
+ self.send_error(500, f"Server error: {str(e)}")
+
+ def handle_logs_request(self):
+ """Return list of available log files"""
+ if not os.path.exists(LOG_DIR):
+ self.send_json_response({"error": "Log directory not found", "logs": []})
+ return
+
+ try:
+ files = []
+ for filename in sorted(os.listdir(LOG_DIR), reverse=True):
+ if filename.endswith('.csv'):
+ filepath = os.path.join(LOG_DIR, filename)
+ stat = os.stat(filepath)
+
+ # Check if CSV is valid
+ if self.is_valid_csv(filepath):
+ files.append({
+ "name": filename,
+ "size": self.format_file_size(stat.st_size),
+ "date": datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S'),
+ "path": filename,
+ "valid": True
+ })
+ else:
+ files.append({
+ "name": filename,
+ "size": self.format_file_size(stat.st_size),
+ "date": datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S'),
+ "path": filename,
+ "valid": False,
+ "error": "Invalid CSV format"
+ })
+
+ self.send_json_response({"logs": files})
+ except Exception as e:
+ self.send_json_response({"error": str(e), "logs": []})
+
+ def handle_log_file_request(self):
+ """Return contents of a specific log file as JSON"""
+ # Extract filename from path
+ parts = self.path.split('/')
+ if len(parts) < 4:
+ self.send_error(400, "Invalid log file request")
+ return
+
+ filename = parts[3]
+ filepath = os.path.join(LOG_DIR, filename)
+
+ if not os.path.exists(filepath):
+ self.send_error(404, "Log file not found")
+ return
+
+ try:
+ if filename.endswith('.csv'):
+ data = self.csv_to_json(filepath)
+ if data is None:
+ self.send_json_response({
+ "error": "Failed to parse CSV file",
+ "filename": filename,
+ "valid": False
+ })
+ return
+
+ self.send_json_response({
+ "data": data,
+ "filename": filename,
+ "valid": True
+ })
+ else:
+ self.send_error(400, "Unsupported file format")
+ except Exception as e:
+ self.send_error(500, f"Error reading log file: {str(e)}")
+
+ def csv_to_json(self, filepath):
+ """Convert CSV file to JSON array"""
+ try:
+ data = []
+ with open(filepath, 'r') as f:
+ reader = csv.DictReader(f)
+ for row in reader:
+ data.append({
+ "click": int(row["click_number"]),
+ "delay_ms": int(row["delay_ms"]),
+ "timestamp": int(row["timestamp"])
+ })
+ return data
+ except Exception as e:
+ print(f"Error parsing CSV {filepath}: {str(e)}")
+ return None
+
+ def is_valid_csv(self, filepath):
+ """Check if a file contains valid CSV"""
+ try:
+ with open(filepath, 'r') as f:
+ reader = csv.DictReader(f)
+ # Try to read first row
+ next(reader)
+ return True
+ except Exception:
+ return False
+
+ def send_json_response(self, data):
+ """Send JSON response with proper headers"""
+ response = json.dumps(data, indent=2)
+ self.send_response(200)
+ self.send_header('Content-type', 'application/json')
+ self.send_header('Access-Control-Allow-Origin', '*')
+ self.send_header('Content-Length', str(len(response)))
+ self.end_headers()
+ self.wfile.write(response.encode())
+
+ def format_file_size(self, size_bytes):
+ """Format file size in human-readable format"""
+ for unit in ['B', 'KB', 'MB', 'GB']:
+ if size_bytes < 1024.0:
+ return f"{size_bytes:.1f} {unit}"
+ size_bytes /= 1024.0
+ return f"{size_bytes:.1f} TB"
+
+def run_server():
+ """Start the web server"""
+ print(f"Starting autoclicker visualization server on port {PORT}")
+ print(f"Log directory: {LOG_DIR}")
+ print("Open your browser to: http://localhost:8661")
+ print("Press Ctrl+C to stop the server")
+
+ try:
+ with socketserver.TCPServer(("", PORT), ClickServerHandler) as httpd:
+ httpd.serve_forever()
+ except KeyboardInterrupt:
+ print("\nServer stopped")
+ except Exception as e:
+ print(f"Server error: {str(e)}")
+
+if __name__ == "__main__":
+ run_server()
\ No newline at end of file
diff --git a/home_dotfiles/.config/sway/config b/home_dotfiles/.config/sway/config
index 7e66c41..4117cf3 100644
--- a/home_dotfiles/.config/sway/config
+++ b/home_dotfiles/.config/sway/config
@@ -74,24 +74,24 @@ output * bg /home/raga/.config/sway/wallpaper.jpg fill
# Multi-monitor setup
# You can get your output names by running: swaymsg -t get_outputs
# DP-2 is the primary monitor on the left, and DP-1 is on the right.
-output HDMI-A-1 {
+output DP-1 {
position 0 0
-# ECO
-# mode 2560x1440@60Hz
+ # ECO
+ # mode 2560x1440@60Hz
-# FULL
- mode 2560x1440@120Hz
+ # FULL
+ mode 3840x2160@165Hz
}
-output DP-1 {
- position 2560 0
+output DP-2 {
+ position 3840 0
-# ECO
-# mode 2560x1440@60Hz
+ # ECO
+ mode 2560x1440@60Hz
-# FULL
- modeline 586.59 2560 2568 2600 2640 1440 1529 1537 1543 +hsync -vsync
+ # FULL
+# modeline 586.59 2560 2568 2600 2640 1440 1529 1537 1543 +hsync -vsync
}
###############################################################################
@@ -457,10 +457,10 @@ mode "Resize Mode" {
bindsym Up resize shrink height 6 px or 6 ppt
bindsym Right resize grow width 6 px or 6 ppt
- bindsym Shift+Left resize shrink width 24 px or 24 ppt
- bindsym Shift+Down resize grow height 24 px or 24 ppt
- bindsym Shift+Up resize shrink height 24 px or 24 ppt
- bindsym Shift+Right resize grow width 24 px or 24 ppt
+ bindsym Shift+Left resize shrink width 48 px or 48 ppt
+ bindsym Shift+Down resize grow height 48 px or 48 ppt
+ bindsym Shift+Up resize shrink height 48 px or 48 ppt
+ bindsym Shift+Right resize grow width 48 px or 48 ppt
## Resize // Resize Window // k j h l ##
bindsym $left resize shrink width 6 px or 6 ppt
@@ -468,10 +468,10 @@ mode "Resize Mode" {
bindsym $up resize shrink height 6 px or 6 ppt
bindsym $right resize grow width 6 px or 6 ppt
- bindsym Shift+$left resize shrink width 24 px or 24 ppt
- bindsym Shift+$down resize grow height 24 px or 24 ppt
- bindsym Shift+$up resize shrink height 24 px or 24 ppt
- bindsym Shift+$right resize grow width 24 px or 24 ppt
+ bindsym Shift+$left resize shrink width 48 px or 48 ppt
+ bindsym Shift+$down resize grow height 48 px or 48 ppt
+ bindsym Shift+$up resize shrink height 48 px or 48 ppt
+ bindsym Shift+$right resize grow width 48 px or 48 ppt
## Resize // Exit Resize Mode // Escape or Enter ##
bindsym Return mode "default"
@@ -546,6 +546,7 @@ exec lxqt-policykit-agent # Authentication agent (comment out if not needed)
exec --no-startup-id blueman-applet
exec --no-startup-id nm-applet
+#exec --no-startup-id home_dotfiles/.config/sway/set_random_bg.sh
# Include additional config files if they exist
include /etc/sway/config.d/*
diff --git a/home_dotfiles/.config/sway/i3status-rust.toml b/home_dotfiles/.config/sway/i3status-rust.toml
index f48d615..423379e 100644
--- a/home_dotfiles/.config/sway/i3status-rust.toml
+++ b/home_dotfiles/.config/sway/i3status-rust.toml
@@ -10,6 +10,15 @@ click = [
{button = "left", cmd = "~/.config/sway/osrs-mode-toggle.sh", update = true}
]
+[[block]]
+block = "custom"
+command = "echo ''"
+format = " $text "
+interval = 1
+click = [
+ {button = "left", cmd = "~/.config/sway/set_random_bg.sh", update = false},
+]
+
#[[block]]
#block = "custom"
#command = "~/.config/sway/get-focused-window.sh"
diff --git a/home_dotfiles/.config/sway/set_random_bg.sh b/home_dotfiles/.config/sway/set_random_bg.sh
new file mode 100755
index 0000000..7e1a383
--- /dev/null
+++ b/home_dotfiles/.config/sway/set_random_bg.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Find a random image file
+#IMAGE=$(find /run/media/raga/970/qBittorrent/nsfw/xd -type f \( -name '*.png' -o -name '*.jpg' -o -name '*.jpeg' \) | shuf -n 1)
+IMAGE=$(find /run/media/raga/970/images/cars/wallpaper -type f \( -name '*.png' -o -name '*.jpg' -o -name '*.jpeg' \) | shuf -n 1)
+
+if [ -n "$IMAGE" ]; then
+ echo "Image: $IMAGE"
+
+ # Try to get image dimensions using identify (ImageMagick)
+ DIMENSIONS=$(identify -format "%wx%h" "$IMAGE" 2>/dev/null)
+
+ if [ -n "$DIMENSIONS" ]; then
+ echo "Dimensions: $DIMENSIONS"
+ WIDTH=$(echo "$DIMENSIONS" | cut -d'x' -f1)
+ HEIGHT=$(echo "$DIMENSIONS" | cut -d'x' -f2)
+
+ # Determine if portrait (height > width) or landscape
+ if [ "$HEIGHT" -gt "$WIDTH" ]; then
+ # Portrait image - use "fit" to maintain aspect ratio
+ echo "Portrait image - using fit"
+ swaymsg "output * bg \"$IMAGE\" fit"
+ else
+ # Landscape image - use "fill" to fill the screen
+ echo "Landscape image - using fill"
+ swaymsg "output * bg \"$IMAGE\" fill"
+ fi
+ else
+ # Fallback to fill if we can't determine dimensions
+ echo "Could not determine dimensions - using fill"
+ swaymsg "output * bg \"$IMAGE\" fill"
+ fi
+fi
diff --git a/home_dotfiles/.config/sway/weather-sway.sh b/home_dotfiles/.config/sway/weather-sway.sh
index bedbc99..bd604a7 100755
--- a/home_dotfiles/.config/sway/weather-sway.sh
+++ b/home_dotfiles/.config/sway/weather-sway.sh
@@ -2,12 +2,12 @@
set -Eeu -o pipefail
-# Simplified weather script for i3status-rust
-# Based on the original weather script but adapted for Sway/i3status-rust
+# Improved weather script for i3status-rust using JSON API
+# Based on the original weather script but optimized for Sway/i3status-rust
-# Information on the various formats: https://github.com/chubin/wttr.in
-VALUE_WEATHER_FORMAT=${weather_format:-"%c%f"}
-VALUE_WEATHER_FORMAT="?format=${VALUE_WEATHER_FORMAT}"
+# Location (defaults to Pärnu as in your original script)
+VALUE_WEATHER_LOCATION=${weather_location:-"Pärnu"}
+VALUE_WEATHER_ERROR_MESSAGE=${error_message:-"⛔"}
# Determine units to use for temperature
# We don't supply a default here because wttr.in is "smart" enough to choose for us
@@ -16,40 +16,100 @@ if [ -n "${WEATHER_UNIT}" ]; then
WEATHER_UNIT="&${WEATHER_UNIT}"
fi
-# Location (defaults to Pärnu as in your original script)
-VALUE_WEATHER_LOCATION=${weather_location:-"Pärnu"}
-VALUE_WEATHER_ERROR_MESSAGE=${error_message:-"⛔"}
-VALUE_FETCH_WEATHER_URL="https://wttr.in/${VALUE_WEATHER_LOCATION}${VALUE_WEATHER_FORMAT}${WEATHER_UNIT}"
+# Use JSON API to get all data in a single request
+VALUE_FETCH_WEATHER_URL="https://wttr.in/${VALUE_WEATHER_LOCATION}?format=j1"
-# Get weather data
-WEATHER=$(curl -sS "$VALUE_FETCH_WEATHER_URL" 2>/dev/null || echo "${VALUE_WEATHER_ERROR_MESSAGE}")
-
-# Get sunrise/sunset data
-VALUE_SUNSET_SUNRISE_FORMAT="?format=%S-%s%20%m+"
-SUNRISE_SUNSET=$(curl -sS "https://wttr.in/${VALUE_WEATHER_LOCATION}${VALUE_SUNSET_SUNRISE_FORMAT}${WEATHER_UNIT}" 2>/dev/null || echo "")
-
-if [ -n "$SUNRISE_SUNSET" ]; then
- SUNRISE_VALUE=$(echo ${SUNRISE_SUNSET} | cut -c 1-5)
- SUNSET_VALUE=$(echo ${SUNRISE_SUNSET} | cut -c 10-14)
- SUNRISE_SUNSET_TEXT=" (${SUNRISE_VALUE}-${SUNSET_VALUE})"
-else
- SUNRISE_SUNSET_TEXT=""
-fi
+# Get weather data using JSON API
+WEATHER_JSON=$(curl -sS "$VALUE_FETCH_WEATHER_URL" 2>/dev/null || echo "{}")
# Check for errors
-if echo "${WEATHER}" | grep -q -P "Unknown\slocation"; then
- WEATHER=${VALUE_WEATHER_ERROR_MESSAGE}
+if echo "$WEATHER_JSON" | grep -q "Unknown location"; then
+ echo "${VALUE_WEATHER_ERROR_MESSAGE}"
+ exit 0
fi
-# Output for i3status-rust (plain text)
-echo "${WEATHER}${SUNRISE_SUNSET_TEXT}"
+# Extract data using jq (should be available on most systems)
+if command -v jq &>/dev/null; then
+ # Extract current weather condition and temperature
+ WEATHER_CONDITION=$(echo "$WEATHER_JSON" | jq -r '.current_condition[0].weatherDesc[0].value' 2>/dev/null || echo "")
+ TEMP_C=$(echo "$WEATHER_JSON" | jq -r '.current_condition[0].temp_C' 2>/dev/null || echo "")
+
+ # Extract sunrise and sunset times
+ SUNRISE=$(echo "$WEATHER_JSON" | jq -r '.weather[0].astronomy[0].sunrise' 2>/dev/null || echo "")
+ SUNSET=$(echo "$WEATHER_JSON" | jq -r '.weather[0].astronomy[0].sunset' 2>/dev/null || echo "")
+
+ # Convert to simple format if we have data
+ if [ -n "$WEATHER_CONDITION" ] && [ -n "$TEMP_C" ]; then
+ # Map weather conditions to icons (simplified)
+ case "$WEATHER_CONDITION" in
+ *"Sunny"*|*"Clear"*) ICON="☀️";;
+ *"Partly cloudy"*|*"Cloudy"*) ICON="⛅";;
+ *"Overcast"*) ICON="☁️";;
+ *"Rain"*|*"Drizzle"*) ICON="🌧️";;
+ *"Snow"*) ICON="❄️";;
+ *"Thunder"*) ICON="⛈️";;
+ *"Fog"*|*"Mist"*) ICON="🌫️";;
+ *) ICON="🌤️";;
+ esac
+
+ WEATHER="${ICON} ${TEMP_C}°C"
+
+ # Format sunrise/sunset times (convert from "09:10 AM" to "09:10")
+ if [ -n "$SUNRISE" ] && [ -n "$SUNSET" ]; then
+ # Remove AM/PM and convert to 24-hour format
+ SUNRISE_24=$(echo "$SUNRISE" | sed 's/ AM//;s/ PM//;s/^0//' | awk -F: '{if($1==12) print "00:"$2; else if($1<12) print $1":"$2; else print $1":"$2}')
+ SUNSET_24=$(echo "$SUNSET" | sed 's/ AM//;s/ PM//;s/^0//' | awk -F: '{if($1==12) print "00:"$2; else if($1<12) print $1":"$2; else print $1":"$2}')
+
+ # Remove leading zeros from hours for consistency
+ SUNRISE_24=$(echo "$SUNRISE_24" | sed 's/^0//')
+ SUNSET_24=$(echo "$SUNSET_24" | sed 's/^0//')
+
+ SUNRISE_SUNSET_TEXT=" (${SUNRISE_24}-${SUNSET_24})"
+ else
+ SUNRISE_SUNSET_TEXT=""
+ fi
+
+ # Output for i3status-rust (plain text)
+ echo "${WEATHER}${SUNRISE_SUNSET_TEXT}"
+ else
+ echo "${VALUE_WEATHER_ERROR_MESSAGE}"
+ fi
+else
+ # Fallback to original method if jq is not available
+ echo "⚠️ jq not found, using fallback method"
+
+ # Get basic weather data
+ VALUE_WEATHER_FORMAT=${weather_format:-"%c%f"}
+ VALUE_WEATHER_FORMAT="?format=${VALUE_WEATHER_FORMAT}"
+ WEATHER=$(curl -sS "https://wttr.in/${VALUE_WEATHER_LOCATION}${VALUE_WEATHER_FORMAT}${WEATHER_UNIT}" 2>/dev/null || echo "${VALUE_WEATHER_ERROR_MESSAGE}")
+
+ # Get sunrise/sunset data
+ VALUE_SUNSET_SUNRISE_FORMAT="?format=%S-%s"
+ SUNRISE_SUNSET=$(curl -sS "https://wttr.in/${VALUE_WEATHER_LOCATION}${VALUE_SUNSET_SUNRISE_FORMAT}${WEATHER_UNIT}" 2>/dev/null || echo "")
+
+ if [ -n "$SUNRISE_SUNSET" ]; then
+ SUNRISE_VALUE=$(echo ${SUNRISE_SUNSET} | cut -c 1-5)
+ SUNSET_VALUE=$(echo ${SUNRISE_SUNSET} | cut -c 7-11)
+ SUNRISE_SUNSET_TEXT=" (${SUNRISE_VALUE}-${SUNSET_VALUE})"
+ else
+ SUNRISE_SUNSET_TEXT=""
+ fi
+
+ # Check for errors
+ if echo "${WEATHER}" | grep -q -P "Unknown\slocation"; then
+ WEATHER=${VALUE_WEATHER_ERROR_MESSAGE}
+ fi
+
+ # Output for i3status-rust (plain text)
+ echo "${WEATHER}${SUNRISE_SUNSET_TEXT}"
+fi
# Handle click events (for i3status-rust custom block)
if [ "${BLOCK_BUTTON:-}" = "1" ]; then
- # Left click - show detailed weather
- FULL_WEATHER=$(curl -sS "https://wttr.in/${VALUE_WEATHER_LOCATION}?format=%l:+%c+%f+%h+%p+%P+%m+%w+%S+%s" 2>/dev/null || echo "${VALUE_WEATHER_ERROR_MESSAGE}")
- notify-send "Weather Details" "$FULL_WEATHER" -t 10000
+ # Left click - show detailed weather using JSON
+ DETAILED_WEATHER=$(curl -sS "https://wttr.in/${VALUE_WEATHER_LOCATION}?format=%l:+%c+%f+%h+%p+%P+%m+%w+%S-%s" 2>/dev/null || echo "${VALUE_WEATHER_ERROR_MESSAGE}")
+ notify-send "Weather Details" "$DETAILED_WEATHER" -t 10000
elif [ "${BLOCK_BUTTON:-}" = "3" ]; then
# Right click - open weather website
xdg-open "https://wttr.in/${VALUE_WEATHER_LOCATION}" >/dev/null 2>&1 &
-fi
\ No newline at end of file
+fi
\ No newline at end of file
diff --git a/home_dotfiles/wallpapers/1742471076220983.jpg b/home_dotfiles/wallpapers/1742471076220983.jpg
new file mode 100755
index 0000000..0f4142c
Binary files /dev/null and b/home_dotfiles/wallpapers/1742471076220983.jpg differ
diff --git a/install-arch-sway.sh b/install-arch-sway.sh
index 18cc1f0..9452f97 100755
--- a/install-arch-sway.sh
+++ b/install-arch-sway.sh
@@ -60,6 +60,13 @@ for script in osrs-mode-status.sh osrs-mode-toggle.sh get-focused-window.sh; do
fi
done
+# === CHANGE WALLPAPER SCRIPT ===
+echo ""
+echo "Installing change wallpaper script..."
+cp $SCRIPT_DIR/home_dotfiles/.config/sway/set_random_bg.sh ~/.config/sway/set_random_bg.sh
+chmod +x ~/.config/sway/set_random_bg.sh
+echo "✓ Change wallpaper script installed to ~/.config/sway/set_random_bg.sh"
+
# === WEATHER SCRIPT ===
# Comment out this section if you don't want the weather script
echo ""
@@ -103,8 +110,9 @@ echo "✓ swayimg set as default image viewer"
# === SET WALLPAPER ===
echo ""
echo "Setting wallpaper..."
-#WALLPAPER_NAME="chris-czermak-PamFFHL6fVY-unsplash.jpg"
-WALLPAPER_NAME="lucas-gallone-2dClJIAR404-unsplash.jpg"
+WALLPAPER_NAME="chris-czermak-PamFFHL6fVY-unsplash.jpg"
+#WALLPAPER_NAME="lucas-gallone-2dClJIAR404-unsplash.jpg"
+#WALLPAPER_NAME="1742471076220983.jpg"
WALLPAPER_PATH="$SCRIPT_DIR/home_dotfiles/wallpapers/$WALLPAPER_NAME"
cp $WALLPAPER_PATH ~/.config/sway/wallpaper.jpg
echo "✓ Wallpaper installed to ~/.config/sway/wallpaper.jpg"
diff --git a/visualize-clicks.sh b/visualize-clicks.sh
new file mode 100755
index 0000000..1ec927d
--- /dev/null
+++ b/visualize-clicks.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+
+# Script to visualize autoclicker log files
+# Starts Python server and opens the HTML visualization tool
+
+VISUALIZER_FILE="click-visualizer.html"
+LOG_DIR="/tmp/autoclicker_logs"
+SERVER_SCRIPT="click_server.py"
+SERVER_PORT=8661
+
+# Check if visualization file exists
+if [ ! -f "$VISUALIZER_FILE" ]; then
+ echo "Error: Visualization tool not found at $VISUALIZER_FILE"
+ exit 1
+fi
+
+# Check if server script exists
+if [ ! -f "$SERVER_SCRIPT" ]; then
+ echo "Error: Server script not found at $SERVER_SCRIPT"
+ exit 1
+fi
+
+# Check if Python is available
+if ! command -v python3 &> /dev/null; then
+ echo "Error: Python 3 is not installed. Install it with: sudo pacman -S python"
+ exit 1
+fi
+
+# Check if we have any log files
+if [ ! -d "$LOG_DIR" ] || [ -z "$(ls -A "$LOG_DIR")" ]; then
+ echo "No autoclicker log files found in $LOG_DIR"
+ echo "Run the enhanced autoclicker first to generate data."
+ echo ""
+ echo "Starting server anyway (you can generate logs while it's running)..."
+fi
+
+echo "Starting autoclicker visualization server..."
+echo "Server will be available at: http://localhost:$SERVER_PORT"
+echo "Log directory: $LOG_DIR"
+echo ""
+
+# Start the Python server in the background
+python3 "$SERVER_SCRIPT" &
+SERVER_PID=$!
+
+# Give the server a moment to start
+sleep 2
+
+# Check if server started successfully
+if ! ps -p $SERVER_PID > /dev/null; then
+ echo "Error: Failed to start server"
+ exit 1
+fi
+
+# Open browser
+if command -v xdg-open &> /dev/null; then
+ xdg-open "http://localhost:$SERVER_PORT"
+elif command -v open &> /dev/null; then
+ open "http://localhost:$SERVER_PORT"
+else
+ echo "Server started successfully!"
+ echo "Open your browser and navigate to: http://localhost:$SERVER_PORT"
+fi
+
+echo ""
+echo "Server is running in the background (PID: $SERVER_PID)"
+echo "Press Ctrl+C to stop the server when you're done"
+echo ""
+
+# Wait for server to finish (it will run until manually stopped)
+wait $SERVER_PID
\ No newline at end of file