Compare commits
12 Commits
8511d528ed
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
e0f6105dc2
|
|||
|
2f66d3191c
|
|||
|
04a1729781
|
|||
|
6640664a69
|
|||
|
1b62414392
|
|||
|
c1718bc086
|
|||
|
8e19d89ba2
|
|||
| b931f47e07 | |||
| d1f3def242 | |||
| 5a73db92c9 | |||
|
609880fd07
|
|||
| 4fe3199161 |
171
change-wallpaper.go
Normal file
171
change-wallpaper.go
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
wallhavenAPI = "https://wallhaven.cc/api/v1"
|
||||||
|
wallpaperDir = "Pictures/wallpapers/wallhaven"
|
||||||
|
)
|
||||||
|
|
||||||
|
var topics = []string{
|
||||||
|
"132262 - Mobuseka",
|
||||||
|
"konosuba",
|
||||||
|
"bunny girl senpai",
|
||||||
|
"oshi no ko",
|
||||||
|
"kill la kill",
|
||||||
|
"lofi",
|
||||||
|
"eminence in shadow",
|
||||||
|
}
|
||||||
|
|
||||||
|
type WallhavenResponse struct {
|
||||||
|
Data []struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Initialize random source
|
||||||
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
|
||||||
|
// Check if a file path was provided as argument
|
||||||
|
if len(os.Args) > 1 {
|
||||||
|
imgPath := os.Args[1]
|
||||||
|
if _, err := os.Stat(imgPath); err == nil {
|
||||||
|
changeWallpaper(imgPath, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create wallpaper directory if it doesn't exist
|
||||||
|
homeDir, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error getting home directory: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
wallpaperPath := filepath.Join(homeDir, wallpaperDir)
|
||||||
|
if err := os.MkdirAll(wallpaperPath, 0755); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error creating wallpaper directory: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download and set new wallpaper
|
||||||
|
newWallpaper, topic := downloadRandomWallpaper(wallpaperPath, r)
|
||||||
|
if newWallpaper != "" {
|
||||||
|
changeWallpaper(newWallpaper, topic)
|
||||||
|
} else {
|
||||||
|
notify("Failed to download new wallpaper", "critical")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadRandomWallpaper(wallpaperPath string, r *rand.Rand) (string, string) {
|
||||||
|
// Select random topic
|
||||||
|
topic := topics[r.Intn(len(topics))]
|
||||||
|
var query string
|
||||||
|
var displayName string
|
||||||
|
|
||||||
|
// Check if the topic is a tag ID with name
|
||||||
|
if tagRegex := regexp.MustCompile(`^(\d+)\s*-\s*(.+)$`); tagRegex.MatchString(topic) {
|
||||||
|
matches := tagRegex.FindStringSubmatch(topic)
|
||||||
|
query = fmt.Sprintf("id:%s", matches[1])
|
||||||
|
displayName = strings.TrimSpace(matches[2])
|
||||||
|
} else {
|
||||||
|
query = url.QueryEscape(topic)
|
||||||
|
displayName = topic
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, "Searching for wallpapers related to: %s\n", displayName)
|
||||||
|
|
||||||
|
// Get wallpapers from Wallhaven API
|
||||||
|
resp, err := http.Get(fmt.Sprintf("%s/search?q=%s&purity=100&categories=110&sorting=random", wallhavenAPI, query))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error fetching from Wallhaven: %v\n", err)
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// Parse response
|
||||||
|
var wallhavenResp WallhavenResponse
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&wallhavenResp); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error parsing response: %v\n", err)
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(wallhavenResp.Data) == 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "No wallpapers found for topic: %s\n", displayName)
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select a random image from the results
|
||||||
|
randomIndex := r.Intn(len(wallhavenResp.Data))
|
||||||
|
wallpaperURL := wallhavenResp.Data[randomIndex].Path
|
||||||
|
filename := filepath.Base(wallpaperURL)
|
||||||
|
filepath := filepath.Join(wallpaperPath, filename)
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, "Downloading: %s\n", filename)
|
||||||
|
|
||||||
|
resp, err = http.Get(wallpaperURL)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error downloading wallpaper: %v\n", err)
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
file, err := os.Create(filepath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error creating file: %v\n", err)
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if _, err := io.Copy(file, resp.Body); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error saving wallpaper: %v\n", err)
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath, displayName
|
||||||
|
}
|
||||||
|
|
||||||
|
func changeWallpaper(wallpaperPath, topic string) {
|
||||||
|
// Save current wallpaper path
|
||||||
|
homeDir, _ := os.UserHomeDir()
|
||||||
|
wallpaperFile := filepath.Join(homeDir, ".wallpaper")
|
||||||
|
if err := os.WriteFile(wallpaperFile, []byte(wallpaperPath), 0644); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error saving wallpaper path: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change wallpaper using hyprctl
|
||||||
|
cmd := exec.Command("hyprctl", "hyprpaper", "reload", ","+wallpaperPath)
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error changing wallpaper: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send notification
|
||||||
|
filename := filepath.Base(wallpaperPath)
|
||||||
|
message := fmt.Sprintf("Wallpaper changed to %s", filename)
|
||||||
|
if topic != "" {
|
||||||
|
message += fmt.Sprintf(" (%s)", topic)
|
||||||
|
}
|
||||||
|
notify(message, "normal")
|
||||||
|
}
|
||||||
|
|
||||||
|
func notify(message, urgency string) {
|
||||||
|
cmd := exec.Command("notify-send", "-i", "hyprpaper", "-u", urgency, "change-wallpaper.go", message)
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error sending notification: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +1,90 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
IMG="$1"
|
# Wallhaven API configuration
|
||||||
|
WALLHAVEN_API="https://wallhaven.cc/api/v1"
|
||||||
|
WALLPAPER_DIR="$HOME/Pictures/wallpapers"
|
||||||
|
TOPICS=(
|
||||||
|
"konosuba"
|
||||||
|
"bunny girl senpai"
|
||||||
|
"oshi no ko"
|
||||||
|
"kill la kill"
|
||||||
|
"lofi"
|
||||||
|
"eminence in shadow"
|
||||||
|
"132262 - Mobuseka"
|
||||||
|
)
|
||||||
|
|
||||||
if [[ -f "$IMG" ]]; then
|
# Create wallpaper directory if it doesn't exist
|
||||||
echo "Changing wallpaper to $IMG"
|
mkdir -p "$WALLPAPER_DIR"
|
||||||
echo "$IMG" > "$HOME/.wallpaper"
|
|
||||||
hyprctl hyprpaper reload ,"$IMG"
|
# Function to download a random wallpaper from Wallhaven
|
||||||
notify-send -i hyprpaper -u normal "change-wallpaper.sh" "Wallpaper changed to ${IMG##*/variety/}"
|
download_random_wallpaper() {
|
||||||
|
# Select random topic
|
||||||
|
local random_topic="${TOPICS[$RANDOM % ${#TOPICS[@]}]}"
|
||||||
|
local query
|
||||||
|
local display_name
|
||||||
|
|
||||||
|
# Check if the topic is a tag ID with name
|
||||||
|
if [[ "$random_topic" =~ ^([0-9]+)[[:space:]]*-[[:space:]]*(.+)$ ]]; then
|
||||||
|
query="id:${BASH_REMATCH[1]}"
|
||||||
|
display_name="${BASH_REMATCH[2]}"
|
||||||
|
else
|
||||||
|
query=$(echo "$random_topic" | sed 's/ /+/g')
|
||||||
|
display_name="$random_topic"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Searching for wallpapers related to: $display_name" >&2
|
||||||
|
|
||||||
|
# Get wallpapers from Wallhaven API
|
||||||
|
local response=$(curl -s "$WALLHAVEN_API/search?q=$query&purity=100&categories=110&sorting=random")
|
||||||
|
|
||||||
|
# Get all image URLs and select a random one
|
||||||
|
local urls=($(echo "$response" | jq -r '.data[].path'))
|
||||||
|
if [ ${#urls[@]} -eq 0 ]; then
|
||||||
|
echo "No wallpapers found for topic: $display_name" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local random_index=$((RANDOM % ${#urls[@]}))
|
||||||
|
local url="${urls[$random_index]}"
|
||||||
|
|
||||||
|
if [ -n "$url" ] && [ "$url" != "null" ]; then
|
||||||
|
local filename=$(basename "$url")
|
||||||
|
echo "Downloading: $filename" >&2
|
||||||
|
curl -s "$url" -o "$WALLPAPER_DIR/$filename"
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "$WALLPAPER_DIR/$filename"
|
||||||
|
echo "$display_name" > "$WALLPAPER_DIR/.last_topic"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "No wallpapers found for topic: $display_name" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle direct image file input
|
||||||
|
if [[ -f "$1" ]]; then
|
||||||
|
echo "Changing wallpaper to $1"
|
||||||
|
echo "$1" > "$HOME/.wallpaper"
|
||||||
|
hyprctl hyprpaper reload ,"$1"
|
||||||
|
notify-send -i hyprpaper -u normal "change-wallpaper.sh" "Wallpaper changed to ${1##*/}"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
WALLPAPER_DIR="$HOME/Pictures/variety/"
|
# Download a new random wallpaper
|
||||||
CURRENT_WALL=$(hyprctl hyprpaper listloaded)
|
new_wallpaper=$(download_random_wallpaper)
|
||||||
|
|
||||||
# Get a random wallpaper that is not the current one
|
if [ -n "$new_wallpaper" ] && [ -f "$new_wallpaper" ]; then
|
||||||
WALLPAPER=$(find "$WALLPAPER_DIR" -type f ! -name "$(basename "$CURRENT_WALL")" ! -name "*.json" | shuf -n 1)
|
echo "Changing wallpaper to $new_wallpaper"
|
||||||
# remove double slashes that's there for some reason
|
echo "$new_wallpaper" > "$HOME/.wallpaper"
|
||||||
WALLPAPER="${WALLPAPER//\/\///}"
|
|
||||||
|
|
||||||
echo "Changing wallpaper to $WALLPAPER"
|
# Get the topic used for this wallpaper
|
||||||
echo "$WALLPAPER" > "$HOME/.wallpaper"
|
topic=$(cat "$WALLPAPER_DIR/.last_topic")
|
||||||
|
|
||||||
# Apply the selected wallpaper
|
# Apply the selected wallpaper
|
||||||
hyprctl hyprpaper reload ,"$WALLPAPER"
|
hyprctl hyprpaper reload ,"$new_wallpaper"
|
||||||
notify-send -i hyprpaper -u normal "change-wallpaper.sh" "Wallpaper changed to ${WALLPAPER##*/variety/}"
|
notify-send -i hyprpaper -u normal "change-wallpaper.sh" "Wallpaper changed to ${new_wallpaper##*/wallpapers/} ($topic)"
|
||||||
|
else
|
||||||
|
notify-send -i hyprpaper -u critical "change-wallpaper.sh" "Failed to download new wallpaper"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|||||||
93
record-audio.sh
Normal file
93
record-audio.sh
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Version 1.2
|
||||||
|
# shoutout to https://gist.github.com/Cephian/f849e326e3522be9a4386b60b85f2f23 for the original script,
|
||||||
|
# https://github.com/xythh/ added the ankiConnect functionality
|
||||||
|
# toggle record computer audio (run once to start, run again to stop)
|
||||||
|
# dependencies: ffmpeg, pulseaudio, curl
|
||||||
|
|
||||||
|
# where recording gets saved, gets deleted after being imported to anki
|
||||||
|
DIRECTORY="$HOME/.cache/"
|
||||||
|
FORMAT="mp3" # ogg or mp3
|
||||||
|
# cut file since it glitches a bit at the end sometimes
|
||||||
|
CUT_DURATION="0.1"
|
||||||
|
#port used by ankiconnect
|
||||||
|
ankiConnectPort="8765"
|
||||||
|
# gets the newest created card, so make sure to create the card first with yomichan
|
||||||
|
newestNoteId=$(curl -s localhost:$ankiConnectPort -X POST -d '{"action": "findNotes", "version": 6, "params": { "query": "is:new"}}' | jq '.result[-1]')
|
||||||
|
#Audio field name
|
||||||
|
audioFieldName="SentenceAudio"
|
||||||
|
|
||||||
|
#if there is no newest note, you either have a complete empty anki or ankiconnect isn't running
|
||||||
|
if [ "$newestNoteId" = "" ]; then
|
||||||
|
notify-send "anki connect not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if pgrep -f "parec"; then
|
||||||
|
pkill -f "parec"
|
||||||
|
else
|
||||||
|
time=$(date +%s)
|
||||||
|
name="$DIRECTORY/$time"
|
||||||
|
wav_file="$name.wav"
|
||||||
|
out_file="$name.$FORMAT"
|
||||||
|
|
||||||
|
if ! [ -d "$DIRECTORY" ]; then
|
||||||
|
mkdir "$DIRECTORY"
|
||||||
|
fi
|
||||||
|
notify-send -t 1000 "Audio recording started"
|
||||||
|
#timeout 1m arecord -t wav -f cd "$wav_file"
|
||||||
|
|
||||||
|
# just grabs last running source... may not always work if your pulseaudio setup is complicated
|
||||||
|
if ! timeout 1m parec -d"$(pactl list sinks | grep -B1 'State: RUNNING' | sed -nE 's/Sink #(.*)/\1/p' | tail -n 1)" --file-format=wav "$wav_file"; then
|
||||||
|
|
||||||
|
notify-send "Error recording " "most likely no audio playing"
|
||||||
|
rm "$wav_file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
input_duration=$(ffprobe -v error -select_streams a:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 "$wav_file")
|
||||||
|
output_duration=$(echo "$input_duration"-"$CUT_DURATION" | bc)
|
||||||
|
|
||||||
|
# encode file and delete OG
|
||||||
|
if [ $FORMAT = "ogg" ]; then
|
||||||
|
ffmpeg -i "$wav_file" -vn -codec:a libvorbis -b:a 64k -t "$output_duration" "$out_file"
|
||||||
|
elif [ $FORMAT = "mp3" ]; then
|
||||||
|
ffmpeg -i "$wav_file" -vn -codec:a libmp3lame -qscale:a 1 -t "$output_duration" "$out_file"
|
||||||
|
else
|
||||||
|
notify-send "Record Error" "Unknown format $FORMAT"
|
||||||
|
fi
|
||||||
|
rm "$wav_file"
|
||||||
|
|
||||||
|
# Update newest note with recorded audio
|
||||||
|
curl -s localhost:$ankiConnectPort -X POST -d '{
|
||||||
|
|
||||||
|
"action": "updateNoteFields",
|
||||||
|
"version": 6,
|
||||||
|
"params": {
|
||||||
|
"note": {
|
||||||
|
"id": '"$newestNoteId"',
|
||||||
|
"fields": {
|
||||||
|
"'$audioFieldName'": ""
|
||||||
|
},
|
||||||
|
"audio": [{
|
||||||
|
"path": "'"$out_file"'",
|
||||||
|
"filename": "'"$time"'.'$FORMAT'",
|
||||||
|
"fields": [
|
||||||
|
"'$audioFieldName'"
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
# opens changed note, comment if you don't want it.
|
||||||
|
curl -s localhost:$ankiConnectPort -X POST -d '{
|
||||||
|
"action": "guiBrowse",
|
||||||
|
"version": 6,
|
||||||
|
"params": {
|
||||||
|
"query": "nid:'"$newestNoteId"'"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
notify-send -t 1000 "Audio recording copied"
|
||||||
|
rm "$out_file"
|
||||||
|
fi
|
||||||
75
screenshot-anki.sh
Normal file
75
screenshot-anki.sh
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Version 1.2
|
||||||
|
# click and drag to screenshot dragged portion
|
||||||
|
# click on specific window to screenshot window area
|
||||||
|
# dependencies: imagemagick, xclip,curl maybe xdotool (see comment below)
|
||||||
|
# shoutout to https://gist.github.com/Cephian/f849e326e3522be9a4386b60b85f2f23 for the original script,
|
||||||
|
# https://github.com/xythh/ added the ankiConnect functionality
|
||||||
|
# if anki is running the image is added to your latest note as a jpg, if anki is not running it's added to your clipboard as a png
|
||||||
|
time=$(date +%s)
|
||||||
|
tmp_file="$HOME/.cache/$time"
|
||||||
|
ankiConnectPort="8765"
|
||||||
|
pictureField="Picture"
|
||||||
|
quality="90"
|
||||||
|
|
||||||
|
# This gets your notes marked as new and returns the newest one.
|
||||||
|
newestNoteId=$(curl -s localhost:$ankiConnectPort -X POST -d '{"action": "findNotes", "version": 6, "params": { "query": "is:new"}}' | jq '.result[-1]')
|
||||||
|
|
||||||
|
# you can remove these two lines if you don't have software which
|
||||||
|
# makes your mouse disappear when you use the keyboard (e.g. xbanish, unclutter)
|
||||||
|
# https://github.com/ImageMagick/ImageMagick/issues/1745#issuecomment-777747494
|
||||||
|
xdotool mousemove_relative 1 1
|
||||||
|
xdotool mousemove_relative -- -1 -1
|
||||||
|
|
||||||
|
# if anki connect is running it will return your latest note id, and the following code will run, if anki connect is not running nothing is return.
|
||||||
|
if [ "$newestNoteId" != "" ]; then
|
||||||
|
if ! import -quality $quality "$tmp_file.jpg"; then
|
||||||
|
# most likley reason this returns a error, is for fullscreen applications that take full control which does not allowing imagemagick to select the area, use windowed fullscreen or if running wine use a virtual desktop to avoid this.
|
||||||
|
notify-send "Error screenshoting " "most likely unable to find selection"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -s localhost:$ankiConnectPort -X POST -d '{
|
||||||
|
"action": "updateNoteFields",
|
||||||
|
"version": 6,
|
||||||
|
"params": {
|
||||||
|
"note": {
|
||||||
|
"id": '"$newestNoteId"',
|
||||||
|
"fields": {
|
||||||
|
"'$pictureField'": ""
|
||||||
|
},
|
||||||
|
"picture": [{
|
||||||
|
"path": "'"$tmp_file"'.jpg",
|
||||||
|
"filename": "paste-'"$time"'.jpg",
|
||||||
|
"fields": [
|
||||||
|
"'$pictureField'"
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
|
||||||
|
#remove if you don't want anki to show you the card you just edited
|
||||||
|
curl -s localhost:$ankiConnectPort -X POST -d '{
|
||||||
|
"action": "guiBrowse",
|
||||||
|
"version": 6,
|
||||||
|
"params": {
|
||||||
|
"query": "nid:'"$newestNoteId"'"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
|
||||||
|
#you can comment this if you do not use notifcations.
|
||||||
|
notify-send "Screenshot Taken" "Added to note"
|
||||||
|
rm "$tmp_file.jpg"
|
||||||
|
else
|
||||||
|
if ! import -quality $quality "$tmp_file.png"; then
|
||||||
|
notify-send "Error screenshoting " "most likely unable to find selection"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# we use pngs when copying to clipboard because they have greater support when pasting.
|
||||||
|
xclip -selection clipboard -target image/png -i "$tmp_file.png"
|
||||||
|
rm "$tmp_file.png"
|
||||||
|
#you can comment this if you do not use notifcations.
|
||||||
|
notify-send "Screenshot Taken" "Copied to clipboard"
|
||||||
|
fi
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
#
|
|
||||||
# GUI Screenshot Tool for Wayland Using Zenity, Grim, Slurp, and Rofi
|
# GUI Screenshot Tool for Wayland Using Zenity, Grim, Slurp, and Rofi
|
||||||
|
|
||||||
SCRIPT_NAME=$(basename "$0")
|
SCRIPT_NAME=$(basename "$0")
|
||||||
@@ -8,14 +8,7 @@ DEFAULT_FILENAME=screenshot.png
|
|||||||
TMP_SCREENSHOT="$TMP_DIR/$DEFAULT_FILENAME"
|
TMP_SCREENSHOT="$TMP_DIR/$DEFAULT_FILENAME"
|
||||||
HYPRLAND_REGEX='.at[0],(.at[1]) .size[0]x(.size[1])'
|
HYPRLAND_REGEX='.at[0],(.at[1]) .size[0]x(.size[1])'
|
||||||
REQUIREMENTS=(grim slurp rofi zenity wl-copy)
|
REQUIREMENTS=(grim slurp rofi zenity wl-copy)
|
||||||
|
USE_NOTIFICATIONS=1
|
||||||
for cmd in "${REQUIREMENTS[@]}"; do
|
|
||||||
if ! command -v "$cmd" &> /dev/null; then
|
|
||||||
echo "Error: $cmd is not installed. Please install it first."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
CHOICES=(
|
CHOICES=(
|
||||||
"1. Select a region and save - slurp | grim -g - \"$TMP_SCREENSHOT\""
|
"1. Select a region and save - slurp | grim -g - \"$TMP_SCREENSHOT\""
|
||||||
"2. Select a region and copy to clipboard - slurp | grim -g - - | wl-copy"
|
"2. Select a region and copy to clipboard - slurp | grim -g - - | wl-copy"
|
||||||
@@ -24,7 +17,6 @@ CHOICES=(
|
|||||||
"5. Edit - slurp | grim -g - - | swappy -f -"
|
"5. Edit - slurp | grim -g - - | swappy -f -"
|
||||||
"6. Quit - exit 0"
|
"6. Quit - exit 0"
|
||||||
)
|
)
|
||||||
USE_NOTIFICATIONS=0
|
|
||||||
|
|
||||||
notify() {
|
notify() {
|
||||||
local body="$1"
|
local body="$1"
|
||||||
@@ -36,9 +28,8 @@ notify() {
|
|||||||
if [[ -z "$title" ]]; then
|
if [[ -z "$title" ]]; then
|
||||||
title="$SCRIPT_NAME"
|
title="$SCRIPT_NAME"
|
||||||
fi
|
fi
|
||||||
local use_notification="${3:-$USE_NOTIFICATIONS}"
|
|
||||||
|
|
||||||
if ((use_notification)); then
|
if ((USE_NOTIFICATIONS)); then
|
||||||
notify-send "$title" "$body"
|
notify-send "$title" "$body"
|
||||||
else
|
else
|
||||||
printf "%s\n%s\n" "$title" "$body"
|
printf "%s\n%s\n" "$title" "$body"
|
||||||
@@ -46,6 +37,16 @@ notify() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_deps() {
|
||||||
|
for cmd in "${REQUIREMENTS[@]}"; do
|
||||||
|
if ! command -v "$cmd" &> /dev/null; then
|
||||||
|
echo "Error: $cmd is not installed. Please install it first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
CHOICE="$(rofi -dmenu -i -p "Enter option or select from the list" \
|
CHOICE="$(rofi -dmenu -i -p "Enter option or select from the list" \
|
||||||
-mesg "Select a Screenshot Option" \
|
-mesg "Select a Screenshot Option" \
|
||||||
-a 0 -no-custom -location 0 \
|
-a 0 -no-custom -location 0 \
|
||||||
@@ -102,3 +103,7 @@ case "$?" in
|
|||||||
notify "An unexpected error has occurred."
|
notify "An unexpected error has occurred."
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
check_deps
|
||||||
|
main
|
||||||
|
|||||||
2
teppei/.gitignore
vendored
Normal file
2
teppei/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
env
|
||||||
|
.git
|
||||||
10
teppei/open.sh
Executable file
10
teppei/open.sh
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
EP="$1"
|
||||||
|
DIR="/truenas/sudacode/japanese/nihongo-con-teppei/Nihongo-Con-Teppei-E$EP.mp3"
|
||||||
|
export FONTCONFIG_FILE="$HOME/.config/mpv/mpv-fonts.conf"
|
||||||
|
if mpv --profile=builtin-pseudo-gui --vid=1 --external-file=pod/cover.jpg "$DIR"; then
|
||||||
|
echo "Finished playing Nihongo Con Teppei E$EP"
|
||||||
|
else
|
||||||
|
echo "Failed to play Nihongo Con Teppei E$EP"
|
||||||
|
fi
|
||||||
92
teppei/teppei.py
Executable file
92
teppei/teppei.py
Executable file
@@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import logging
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
|
from requests import get
|
||||||
|
from selenium import webdriver
|
||||||
|
from selenium.webdriver.chrome.options import Options
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.support import expected_conditions as EC
|
||||||
|
from selenium.webdriver.support.ui import WebDriverWait
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
AUDIO_BASE_URL = (
|
||||||
|
"https://www.heypera.com/listen/nihongo-con-teppei-for-beginners/{}/next"
|
||||||
|
)
|
||||||
|
SUB_BASE_URL = "https://storage.googleapis.com/pera-transcripts/nihongo-con-teppei-for-beginners/transcripts/{}.vtt"
|
||||||
|
|
||||||
|
|
||||||
|
def get_audio_url(episode_num: int):
|
||||||
|
chrome_options = Options()
|
||||||
|
chrome_options.add_argument("--headless")
|
||||||
|
chrome_options.add_argument("--disable-gpu")
|
||||||
|
chrome_options.add_argument("--no-sandbox")
|
||||||
|
|
||||||
|
driver = webdriver.Chrome(options=chrome_options)
|
||||||
|
|
||||||
|
try:
|
||||||
|
driver.get(AUDIO_BASE_URL.format(episode_num))
|
||||||
|
|
||||||
|
# Wait for the audio element to be present
|
||||||
|
audio_element = WebDriverWait(driver, 10).until(
|
||||||
|
EC.presence_of_element_located((By.TAG_NAME, "audio"))
|
||||||
|
)
|
||||||
|
audio_url = audio_element.get_attribute("src")
|
||||||
|
if audio_url:
|
||||||
|
logger.info(f"Audio URL: {audio_url}")
|
||||||
|
else:
|
||||||
|
logger.error("No audio URL found")
|
||||||
|
return audio_url
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error: {e}")
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
driver.quit()
|
||||||
|
|
||||||
|
|
||||||
|
def get_sub_url(episode_num: int):
|
||||||
|
return SUB_BASE_URL.format(episode_num)
|
||||||
|
|
||||||
|
|
||||||
|
def download_file(url: str, filename: str):
|
||||||
|
response = get(url, timeout=10)
|
||||||
|
if response.status_code != 200:
|
||||||
|
logger.error(f"Failed to download {filename}")
|
||||||
|
return
|
||||||
|
with open(filename, "wb") as file:
|
||||||
|
file.write(response.content)
|
||||||
|
logger.info(f"Downloaded {filename}")
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
parser = ArgumentParser(description="Get the audio URL for a given episode number")
|
||||||
|
parser.add_argument(
|
||||||
|
"episode_num", type=int, help="The episode number to get the audio URL for"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-d", "--download", action="store_true", help="Download the audio file"
|
||||||
|
)
|
||||||
|
parser.add_argument("-o", "--output", help="Output directory name")
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = parse_args()
|
||||||
|
if args.episode_num < 1:
|
||||||
|
logger.error("Episode number must be greater than 0")
|
||||||
|
episode = args.episode_num
|
||||||
|
audio = get_audio_url(episode)
|
||||||
|
sub = get_sub_url(episode)
|
||||||
|
if args.download:
|
||||||
|
if args.output:
|
||||||
|
download_file(audio, f"{args.output}/Nihongo-Con-Teppei-E{episode:0>2}.mp3")
|
||||||
|
download_file(sub, f"{args.output}/Nihongo-Con-Teppei-E{episode:0>2}.vtt")
|
||||||
|
else:
|
||||||
|
download_file(audio, f"Nihongo-Con-Teppei-E{episode:0>2}.mp3")
|
||||||
|
download_file(sub, f"Nihongo-Con-Teppei-E{episode:0>2}.vtt")
|
||||||
|
else:
|
||||||
|
print(f"Audio URL: {audio}")
|
||||||
|
print(f"Subtitle URL: {sub}")
|
||||||
@@ -127,7 +127,10 @@ class PlayerManager:
|
|||||||
player_name = player.props.player_name
|
player_name = player.props.player_name
|
||||||
artist = player.get_artist()
|
artist = player.get_artist()
|
||||||
title = player.get_title()
|
title = player.get_title()
|
||||||
|
if title is not None:
|
||||||
title = title.replace("&", "&")
|
title = title.replace("&", "&")
|
||||||
|
else:
|
||||||
|
title = "No title"
|
||||||
|
|
||||||
track_info = ""
|
track_info = ""
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
STATUS="$(playerctl -p firefox status)"
|
PLAYER="$1"
|
||||||
|
|
||||||
|
if [ -z "$PLAYER" ]; then
|
||||||
|
echo "Usage: $0 <player>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
STATUS="$(playerctl -p "$PLAYER" status)"
|
||||||
|
|
||||||
if [ -z "$STATUS" ] || [ "$STATUS" = "Stopped" ]; then
|
if [ -z "$STATUS" ] || [ "$STATUS" = "Stopped" ]; then
|
||||||
exit 0
|
exit 0
|
||||||
@@ -12,7 +19,7 @@ else
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
TITLE="$(playerctl -p firefox metadata title)"
|
TITLE="$(playerctl -p "$PLAYER" metadata title)"
|
||||||
ARTIST="$(playerctl -p firefox metadata artist)"
|
ARTIST="$(playerctl -p "$PLAYER" metadata artist)"
|
||||||
|
|
||||||
printf "%s\n" "$STATUS$TITLE - $ARTIST"
|
printf "%s\n" "$STATUS$TITLE - $ARTIST"
|
||||||
19
waybar/reload-waybar
Executable file
19
waybar/reload-waybar
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if pgrep -af "waybar -c /home/sudacode/.config/waybar/catppuccin-macchiato/config-battery.jsonc -s /home/sudacode/.config/waybar/catppuccin-macchiato/style.css" ||
|
||||||
|
pgrep -af "waybar -c /home/sudacode/.config/waybar/catppuccin-macchiato/config.jsonc -s /home/sudacode/.config/waybar/catppuccin-macchiato/style.css"; then
|
||||||
|
killall waybar
|
||||||
|
fi
|
||||||
|
|
||||||
|
BASE_DIR="$HOME/.config/waybar/catppuccin-macchiato"
|
||||||
|
NODE_NAME="$(hyprctl systeminfo | grep -i "node name" | sed 's/Node name: //')"
|
||||||
|
|
||||||
|
if [[ "$NODE_NAME" = "sc-arch" ]]; then
|
||||||
|
CONFIG="$BASE_DIR/config.jsonc"
|
||||||
|
else
|
||||||
|
CONFIG="$BASE_DIR/config-laptop.jsonc"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
waybar -c "$CONFIG" -s "$BASE_DIR/style.css" &>/dev/null &
|
||||||
@@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
zscroll -p ' | ' --delay 0.2 \
|
zscroll -p ' | ' --delay 0.2 \
|
||||||
--length 30 \
|
--length 30 \
|
||||||
--match-command "$HOME/.config/waybar/scripts/firefox-status.sh" \
|
--match-command "$HOME/.config/waybar/scripts/playerctl.sh firefox" \
|
||||||
--match-text ' ' "" \
|
--match-text ' ' "" \
|
||||||
--match-text ' ' "--scroll 0" \
|
--match-text ' ' "--scroll 0" \
|
||||||
|
--match-text "^volume:" "--before-text '' --scroll 0 --after-text ''" \
|
||||||
--update-interval 1 \
|
--update-interval 1 \
|
||||||
--update-check true "$HOME/.config/waybar/scripts/firefox-status.sh" &
|
--update-check true "$HOME/.config/waybar/scripts/playerctl.sh firefox" &
|
||||||
wait
|
wait
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
zscroll -p ' | ' --delay 0.2 \
|
zscroll -p ' | ' --delay 0.2 \
|
||||||
--length 30 \
|
--length 30 \
|
||||||
--match-command "$HOME/.config/waybar/scripts/escape-mpc-pango.sh 'mpc status'" \
|
--match-command "$HOME/.config/waybar/scripts/escape-pango.sh 'mpc status'" \
|
||||||
--match-text "playing" "--before-text ' '" \
|
--match-text "playing" "--before-text ' '" \
|
||||||
--match-text "paused" "--before-text ' ' --scroll 0" \
|
--match-text "paused" "--before-text ' ' --scroll 0" \
|
||||||
--match-text "^volume:" "--before-text '' --scroll 0 --after-text ''" \
|
--match-text "^volume:" "--before-text '' --scroll 0 --after-text ''" \
|
||||||
--update-interval 1 \
|
--update-interval 1 \
|
||||||
--update-check true "$HOME/.config/waybar/scripts/escape-mpc-pango.sh 'mpc current'" &
|
--update-check true "$HOME/.config/waybar/scripts/escape-pango.sh 'mpc current'" &
|
||||||
wait
|
wait
|
||||||
|
|||||||
11
waybar/scroll-mpv.sh
Executable file
11
waybar/scroll-mpv.sh
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
zscroll -p ' | ' --delay 0.2 \
|
||||||
|
--length 30 \
|
||||||
|
--match-command "$HOME/.config/waybar/scripts/playerctl.sh mpv" \
|
||||||
|
--match-text ' ' "" \
|
||||||
|
--match-text ' ' "--scroll 0" \
|
||||||
|
--match-text "^volume:" "--before-text '' --scroll 0 --after-text ''" \
|
||||||
|
--update-interval 1 \
|
||||||
|
--update-check true "$HOME/.config/waybar/scripts/playerctl.sh mpv" &
|
||||||
|
wait
|
||||||
Reference in New Issue
Block a user