diff --git a/background.sh b/background.sh new file mode 100755 index 0000000..a2df235 --- /dev/null +++ b/background.sh @@ -0,0 +1,2 @@ +#!/bin/bash +DISPLAY=:0 feh --bg-max --randomize /mnt/omv3/picture/YouTube\ Pics/ diff --git a/catix b/catix new file mode 100755 index 0000000..ae17a1d --- /dev/null +++ b/catix @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +if [[ "$1" == "-g" ]]; then + GEOMETRY="$2" + shift 2 +fi +for f in "$@"; do + convert "$f" -geometry ${GEOMETRY:=800x480} sixel:- +done diff --git a/config-backup.sh b/config-backup.sh new file mode 100755 index 0000000..0b0c470 --- /dev/null +++ b/config-backup.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Set the paths for the source and destination directories +SRC="/home/belar/.config" +DST_DIR=/mnt/nas_belar/rsync/config-backup/ + +# Sync the source directory to the destination directory +/usr/bin/rsync -CERrltm --delete "${SRC}" "${DST_DIR}" + +# Change to the Git repository directory +cd $DST_DIR + +# Commit the changes with the current date as the commit message +git add . +git commit -m "$(date +%Y-%m-%d-%H-%M)" + +# Push the changes to the remote repository if one is configured +if [ "$(git remote)" ]; then + git push +fi + diff --git a/dl_image_from_web_with_tag.py b/dl_image_from_web_with_tag.py new file mode 100644 index 0000000..40c8794 --- /dev/null +++ b/dl_image_from_web_with_tag.py @@ -0,0 +1,54 @@ +import os +import random +import time +import requests +import urllib.request +from bs4 import BeautifulSoup + + +def main(): + with open('urls.txt', 'r') as file: + urls = file.readlines() + + headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0'} + for url in urls: + time.sleep(random.randint(200, 1500) / 1000) + url = url.strip() # Remove any leading/trailing whitespace + if url: + download_image(url, headers) + + +# Function to process each URL and download the image +def download_image(url, headers): + try: + session = requests.Session() + session.headers.update(headers) + + response = session.get(url) + session.cookies.update(response.cookies) + + response = session.get(url) + soup = BeautifulSoup(response.text, 'html.parser') + player_div = soup.find('div', id='player') + + if player_div: + img_tag = player_div.find('img') + if img_tag and 'src' in img_tag.attrs: + img_url = img_tag['src'] + img_name = os.path.basename(img_url) + img_response = session.get(img_url, headers=headers, cookies=session.cookies) + with open(img_name, 'wb') as img_file: + img_file.write(img_response.content) + + print(f'Image from {url} downloaded as {img_name}') + + else: + print(f'No img tag found inside the player div for {url}.') + else: + print(f'No div with id "player" found for {url}.') + except Exception as e: + print(f'Error processing {url}: {e}') + + +if __name__ == "__main__": + main() diff --git a/get_fullmoon.py b/get_fullmoon.py new file mode 100644 index 0000000..57b0335 --- /dev/null +++ b/get_fullmoon.py @@ -0,0 +1,8 @@ +from fullmoon import NextFullMoon + + +n = NextFullMoon() + + +print(n.next_full_moon()) + diff --git a/get_weather_data.py b/get_weather_data.py new file mode 100644 index 0000000..f86def9 --- /dev/null +++ b/get_weather_data.py @@ -0,0 +1,15 @@ +import os +import requests +from dotenv import load_dotenv + +def main(): + load_dotenv('.env') + apikey = os.environ.get("WEATHER_API_KEY") + + url = f"https://my.meteoblue.com/packages/basic-1h_basic-day?apikey={apikey}&lat=47.517766&lon=8.995523&asl=475&format=json" + response = requests.get(url) + data = response.json() + print(data) + +if __name__ == "__main__": + main() diff --git a/icons/tailscale.png b/icons/tailscale.png new file mode 100644 index 0000000..afcc3e0 Binary files /dev/null and b/icons/tailscale.png differ diff --git a/live-background.sh b/live-background.sh new file mode 100755 index 0000000..7fe6967 --- /dev/null +++ b/live-background.sh @@ -0,0 +1 @@ +mpv --fs --loop --no-audio ~/.background/live/Cafeshka\ [sRrDXJVjlP8].webm diff --git a/minecraft/cache/mojang_1.21.1.jar b/minecraft/cache/mojang_1.21.1.jar new file mode 100644 index 0000000..7319626 Binary files /dev/null and b/minecraft/cache/mojang_1.21.1.jar differ diff --git a/minecraft/papermc-backup.sh b/minecraft/papermc-backup.sh new file mode 100755 index 0000000..ace7fc5 --- /dev/null +++ b/minecraft/papermc-backup.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +DIR_TO_BACKUP="/home/mcserver/mc-papermc-server" +BACKUP_DEST="/opt/backups/papermc-server" +SERVICE_NAME="mcserver-papermc.service" + +systemctl is-active --quiet $SERVICE_NAME + +if [ $? -ne 0 ]; then + echo "Service not running." + echo "Skipping shutdown procedure." +else + echo "Notifying players" + /usr/local/bin/mcrcon -H 5.161.249.43 -p 5eXeERr4Tkg6kAxc4U 'say Restarting in 5 minutes for backup...' + sleep 300 + + /usr/local/bin/mcrcon -H 5.161.249.43 -p 5eXeERr4Tkg6kAxc4U 'say Restarting in 30 seconds for backup...' + sleep 30 + + echo "Stopping $SERVICE_NAME" + systemctl stop $SERVICE_NAME + if [ $? -ne 0 ]; then + echo "Couldn't stop service. Exiting." + exit 1 + fi +fi + + +CURRENT_DATE=$(date +%Y-%m-%d_%H-%M) +echo "Creating $BACKUP_DEST/$CURRENT_DATE.tar.gz" +tar -czf "$BACKUP_DEST/$CURRENT_DATE.tar.gz" "$DIR_TO_BACKUP" +if [ $? -ne 0 ]; then + echo "Couldn't create backup. Exiting." + exit 1 +fi + + +echo "Starting $SERVICE_NAME" +systemctl start $SERVICE_NAME +if [ $? -ne 0 ]; then + echo "Couldn't start service. Exiting." + exit 1 +fi + + +# Delete old backups if there are more than 10 +if [ $(ls $BACKUP_DEST/*.tar.gz | wc -l) -gt 10 ] +then + echo "Files to clean up: " + ls -t $BACKUP_DEST/*.tar.gz | tail -n 1 + ls -t $BACKUP_DEST/*.tar.gz | tail -n 1 | xargs rm +fi + + +echo "Backup successful." diff --git a/minecraft/papermc-start.sh b/minecraft/papermc-start.sh new file mode 100644 index 0000000..2f27d8a --- /dev/null +++ b/minecraft/papermc-start.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env sh + +PROJECT="paper" +MINECRAFT_VERSION="1.21.1" + +LATEST_BUILD=$(curl -s https://api.papermc.io/v2/projects/${PROJECT}/versions/${MINECRAFT_VERSION}/builds | \ + jq -r '.builds | map(select(.channel == "default") | .build) | .[-1]') + +if [ "$LATEST_BUILD" != "null" ]; then + JAR_NAME=${PROJECT}-${MINECRAFT_VERSION}-${LATEST_BUILD}.jar + PAPERMC_URL="https://api.papermc.io/v2/projects/${PROJECT}/versions/${MINECRAFT_VERSION}/builds/${LATEST_BUILD}/downloads/${JAR_NAME}" + + # Download the latest Paper version + curl -o server.jar $PAPERMC_URL + echo "Download completed" +else + echo "No stable build for version $MINECRAFT_VERSION found :(" +fi + + +java -Xms6144M -Xmx6144M -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+ParallelRefProcEnabled -XX:+PerfDisableSharedMem -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:G1HeapRegionSize=8M -XX:G1HeapWastePercent=5 -XX:G1MaxNewSizePercent=40 -XX:G1MixedGCCountTarget=4 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1NewSizePercent=30 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:G1ReservePercent=20 -XX:InitiatingHeapOccupancyPercent=15 -XX:MaxGCPauseMillis=200 -XX:MaxTenuringThreshold=1 -XX:SurvivorRatio=32 -Dusing.aikars.flags=https://mcflags.emc.gs -Daikars.new.flags=true -jar server.jar nogui diff --git a/minecraft/server.jar b/minecraft/server.jar new file mode 100644 index 0000000..9da97d3 Binary files /dev/null and b/minecraft/server.jar differ diff --git a/mkvedit.sh b/mkvedit.sh new file mode 100755 index 0000000..f02f3e9 --- /dev/null +++ b/mkvedit.sh @@ -0,0 +1,14 @@ +#!/bin/bash +disable_track=2 +enable_track=1 +enable_sub_track=4 +disable_sub_track=5 + + +for f in ./*.mkv; do + mkvpropedit "$f" --edit track:a$disable_track --set flag-default=0; + mkvpropedit "$f" --edit track:a$enable_track --set flag-default=1; + mkvpropedit "$f" --edit track:s$disable_sub_track --set flag-default=0; + mkvpropedit "$f" --edit track:s$enable_sub_track --set flag-default=1; +done + diff --git a/open_with_linux.py b/open_with_linux.py new file mode 100755 index 0000000..75079d9 --- /dev/null +++ b/open_with_linux.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 +from __future__ import print_function + +import os +import sys +import json +import struct +import subprocess + +VERSION = '7.2.6' + +try: + sys.stdin.buffer + + # Python 3.x version + # Read a message from stdin and decode it. + def getMessage(): + rawLength = sys.stdin.buffer.read(4) + if len(rawLength) == 0: + sys.exit(0) + messageLength = struct.unpack('@I', rawLength)[0] + message = sys.stdin.buffer.read(messageLength).decode('utf-8') + return json.loads(message) + + # Send an encoded message to stdout + def sendMessage(messageContent): + encodedContent = json.dumps(messageContent).encode('utf-8') + encodedLength = struct.pack('@I', len(encodedContent)) + + sys.stdout.buffer.write(encodedLength) + sys.stdout.buffer.write(encodedContent) + sys.stdout.buffer.flush() + +except AttributeError: + # Python 2.x version (if sys.stdin.buffer is not defined) + print('Python 3.2 or newer is required.') + sys.exit(-1) + + +def install(): + home_path = os.getenv('HOME') + + manifest = { + 'name': 'open_with', + 'description': 'Open With native host', + 'path': os.path.realpath(__file__), + 'type': 'stdio', + } + locations = { + 'chrome': os.path.join(home_path, '.config', 'google-chrome', 'NativeMessagingHosts'), + 'chrome-beta': os.path.join(home_path, '.config', 'google-chrome-beta', 'NativeMessagingHosts'), + 'chrome-unstable': os.path.join(home_path, '.config', 'google-chrome-unstable', 'NativeMessagingHosts'), + 'chromium': os.path.join(home_path, '.config', 'chromium', 'NativeMessagingHosts'), + 'firefox': os.path.join(home_path, '.mozilla', 'native-messaging-hosts'), + 'thunderbird': os.path.join(home_path, '.thunderbird', 'native-messaging-hosts'), + } + filename = 'open_with.json' + + for browser, location in locations.items(): + if os.path.exists(os.path.dirname(location)): + if not os.path.exists(location): + os.mkdir(location) + + browser_manifest = manifest.copy() + if browser in ['firefox', 'thunderbird']: + browser_manifest['allowed_extensions'] = ['openwith@darktrojan.net'] + else: + browser_manifest['allowed_origins'] = [ + 'chrome-extension://cogjlncmljjnjpbgppagklanlcbchlno/', # Chrome + 'chrome-extension://fbmcaggceafhobjkhnaakhgfmdaadhhg/', # Opera + ] + + with open(os.path.join(location, filename), 'w') as file: + file.write( + json.dumps(browser_manifest, indent=2, separators=(',', ': '), sort_keys=True).replace(' ', '\t') + '\n' + ) + + +def _read_desktop_file(path): + with open(path, 'r') as desktop_file: + current_section = None + name = None + command = None + for line in desktop_file: + if line[0] == '[': + current_section = line[1:-2] + if current_section != 'Desktop Entry': + continue + + if line.startswith('Name='): + name = line[5:].strip() + elif line.startswith('Exec='): + command = line[5:].strip() + + return { + 'name': name, + 'command': command + } + + +def find_browsers(): + apps = [ + 'Chrome', + 'Chromium', + 'chromium', + 'chromium-browser', + 'firefox', + 'Firefox', + 'Google Chrome', + 'google-chrome', + 'opera', + 'Opera', + 'SeaMonkey', + 'seamonkey', + ] + paths = [ + os.path.join(os.getenv('HOME'), '.local/share/applications'), + '/usr/local/share/applications', + '/usr/share/applications' + ] + suffix = '.desktop' + + results = [] + for p in paths: + for a in apps: + fp = os.path.join(p, a) + suffix + if os.path.exists(fp): + results.append(_read_desktop_file(fp)) + return results + + +def listen(): + receivedMessage = getMessage() + if receivedMessage == 'ping': + sendMessage({ + 'version': VERSION, + 'file': os.path.realpath(__file__) + }) + elif receivedMessage == 'find': + sendMessage(find_browsers()) + else: + for k, v in os.environ.items(): + if k.startswith('MOZ_'): + try: + os.unsetenv(k) + except: + os.environ[k] = '' + + devnull = open(os.devnull, 'w') + subprocess.Popen(receivedMessage, stdout=devnull, stderr=devnull) + sendMessage(None) + + +if __name__ == '__main__': + if len(sys.argv) == 2: + if sys.argv[1] == 'install': + install() + sys.exit(0) + elif sys.argv[1] == 'find_browsers': + print(find_browsers()) + sys.exit(0) + + allowed_extensions = [ + 'openwith@darktrojan.net', + 'chrome-extension://cogjlncmljjnjpbgppagklanlcbchlno/', + 'chrome-extension://fbmcaggceafhobjkhnaakhgfmdaadhhg/', + ] + for ae in allowed_extensions: + if ae in sys.argv: + listen() + sys.exit(0) + + print('This is the Open With native helper, version %s.' % VERSION) + print('Run this script again with the word "install" after the file name to install.') diff --git a/playbooks/config-backup.yml b/playbooks/config-backup.yml new file mode 100644 index 0000000..b4ffd5f --- /dev/null +++ b/playbooks/config-backup.yml @@ -0,0 +1,17 @@ +- name: Backup config to git repo@nas + hosts: localhost + + vars: + src_dirs: + - "/home/belar/.config/" + - "/etc" + dst_dir: "/home/belar/nas_belar/backup/hotaru/" + commit_msg: "Config backup {{ ansible_date_time.iso8601 }}" + + tasks: + - name: Copy files to destination + copy: + src: "{{ item }}" + dest: "{{ dst_dir }}/{{ item | basename }}" + with_items: + - "{{ src_dirs }}" diff --git a/playbooks/ios_cfgback.yml b/playbooks/ios_cfgback.yml new file mode 100644 index 0000000..033d488 --- /dev/null +++ b/playbooks/ios_cfgback.yml @@ -0,0 +1,103 @@ +# Playbook to backup running configs from (Cisco IOS) network devices to Git +# +# Gather the config via ios_facts, store it in the local directory {{ config_path }} +# Sanitize config files / remove lines with timestamps like {{ timestamp_line_identifier }} +# Commit to git, only if neccessary +# Report all steps to {{ syslog_host }} +# +# You might want to change the vars config_path, syslog_host and timestamp_line_identifier +# Uncomment the line 'git push -f origin master' if you want to push to a central repo like GitHub/Lab + + +--- +- name: CONFIG BACKUP TO LOCAL DIRECTORY + hosts: all + connection: network_cli + ignore_errors: yes + gather_facts: no + + vars: + config_path: /home/nwmichl/configs + syslog_host: 192.168.1.12 + timestamp_line_identifier: "! Last configuration" + + tasks: + + - name: GATHER FACTS VIA SSH + ios_facts: + gather_subset: + - config + register: ios_facts_result + when: ansible_network_os == 'ios' + + - name: SYSLOG MESSAGE - GATHER FACTS ERROR + shell: | + logger -n {{ syslog_host }} -p local0.error --udp Config Backup of "{{ inventory_hostname }}" GATHER FACTS FAILED because "{{ ios_facts_result.msg }}" + when: "ansible_network_os == 'ios' and ios_facts_result.failed" + + - name: SAVE CONFIG TO FILE + local_action: copy content={{ ansible_net_config }} dest={{ config_path }}/{{ inventory_hostname }}.txt + register: save_result + when: "ansible_network_os == 'ios' and not ios_facts_result.failed" + + - name: SYSLOG MESSAGE - SAVE CONFIG ERROR + shell: | + logger -n {{ syslog_host }} -p local0.error --udp Config Backup of "{{ inventory_hostname }}" SAVE FAILED because "{{ save_result.msg }}" + when: "ansible_network_os == 'ios' and save_result.failed" + + - name: SYSLOG MESSAGE - SUCCESSFUL + shell: | + logger -n {{ syslog_host }} -p local0.notice --udp Config Backup of "{{ inventory_hostname }}" successful + when: "ansible_network_os == 'ios' and not ios_facts_result.failed and not save_result.failed" + + - name: REMOVE CONFIG LINES WITH TIMESTAMPS + lineinfile: + path: "{{ config_path }}/{{ inventory_hostname }}.txt" + state: absent + regexp: '^{{ timestamp_line_identifier }}' + delegate_to: localhost + +# +# The following tasks will only be executed once +# + + - name: GIT - ADD ALL (NEW) FILES AND CHECK IF WORKING DIRECTORY IS DIRTY => FAILED + shell: | + cd {{ config_path }}/ + git add --all . + git diff-index --quiet HEAD #Return code = 0 if working directory is clean and 1 if dirty + delegate_to: localhost + register: git_result + run_once: true + + - name: SYSLOG MESSAGE - Git Dir clean - Nothing to commit + shell: | + logger -n {{ syslog_host }} -p local0.notice --udp Config Backup - GIT Working Directory {{ config_path }} is clean - Nothing to commit + when: not git_result.failed + delegate_to: localhost + run_once: true + + - name: GIT - COMMIT/PUSH ONLY IF WORKING DIRECTORY IS DIRTY + shell: | + cd {{ config_path }}/ + git commit -m "Config backup taken $(date +"%Y-%m-%d %H:%M:%S")" +# git push -f origin master + delegate_to: localhost + register: gitcommit_result + run_once: true + when: git_result.failed + + - name: SYSLOG MESSAGE - GIT COMMIT/PUSH SUCCESSFUL + shell: | + logger -n {{ syslog_host }} -p local0.notice --udp Config Backup - GIT Commit / Push successful + when: gitcommit_result.failed is defined and not gitcommit_result.failed + delegate_to: localhost + run_once: true + + - name: SYSLOG MESSAGE - GIT COMMIT/PUSH ERROR + shell: | + logger -n {{ syslog_host }} -p local0.error --udp Config Backup - GIT Commit / Push FAILED ! + when: gitcommit_result.failed is defined and gitcommit_result.failed + delegate_to: localhost + run_once: true + diff --git a/random_name.sh b/random_name.sh new file mode 100644 index 0000000..e55eede --- /dev/null +++ b/random_name.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Directory containing the MP4 files +directory="/mnt/red/porn/HydraFXX/uniform" + +# Find all MP4 files and rename them with random names +find "$directory" -type f -name "*.mp4" | while read -r file; do + # Generate a random name + random_name=$(uuidgen) + # Get the directory of the file + dir=$(dirname "$file") + # Rename the file + mv "$file" "$dir/$random_name.mp4" +done + diff --git a/shell-mommy.sh b/shell-mommy.sh new file mode 100644 index 0000000..3e0d52d --- /dev/null +++ b/shell-mommy.sh @@ -0,0 +1,143 @@ +# sudofox/shell-mommy.sh + +mommy() ( + + # SHELL_MOMMYS_LITTLE - what to call you~ (default: "girl") + # SHELL_MOMMYS_PRONOUNS - what pronouns mommy will use for themself~ (default: "her") + # SHELL_MOMMYS_ROLES - what role mommy will have~ (default "mommy") + + COLORS_LIGHT_PINK='\e[38;5;217m' + COLORS_LIGHT_BLUE='\e[38;5;117m' + COLORS_FAINT='\e[2m' + COLORS_RESET='\e[0m' + + DEF_WORDS_LITTLE="girl" + DEF_WORDS_PRONOUNS="her" + DEF_WORDS_ROLES="mommy" + DEF_MOMMY_COLOR="${COLORS_LIGHT_PINK}" + DEF_ONLY_NEGATIVE="false" + + NEGATIVE_RESPONSES="do you need MOMMYS_ROLE's help~? ❤️ +Don't give up, my love~ ❤️ +Don't worry, MOMMYS_ROLE is here to help you~ ❤️ +I believe in you, my sweet AFFECTIONATE_TERM~ ❤️ +It's okay to make mistakes, my dear~ ❤️ +just a little further, sweetie~ ❤️ +Let's try again together, okay~? ❤️ +MOMMYS_ROLE believes in you, and knows you can overcome this~ ❤️ +MOMMYS_ROLE believes in you~ ❤️ +MOMMYS_ROLE is always here for you, no matter what~ ❤️ +MOMMYS_ROLE is here to help you through it~ ❤️ +MOMMYS_ROLE is proud of you for trying, no matter what the outcome~ ❤️ +MOMMYS_ROLE knows it's tough, but you can do it~ ❤️ +MOMMYS_ROLE knows MOMMYS_PRONOUN little AFFECTIONATE_TERM can do better~ ❤️ +MOMMYS_ROLE knows you can do it, even if it's tough~ ❤️ +MOMMYS_ROLE knows you're feeling down, but you'll get through it~ ❤️ +MOMMYS_ROLE knows you're trying your best~ ❤️ +MOMMYS_ROLE loves you, and is here to support you~ ❤️ +MOMMYS_ROLE still loves you no matter what~ ❤️ +You're doing your best, and that's all that matters to MOMMYS_ROLE~ ❤️ +MOMMYS_ROLE is always here to encourage you~ ❤️" + + POSITIVE_RESPONSES="*pets your head* +awe, what a good AFFECTIONATE_TERM~\nMOMMYS_ROLE knew you could do it~ ❤️ +good AFFECTIONATE_TERM~\nMOMMYS_ROLE's so proud of you~ ❤️ +Keep up the good work, my love~ ❤️ +MOMMYS_ROLE is proud of the progress you've made~ ❤️ +MOMMYS_ROLE is so grateful to have you as MOMMYS_PRONOUN little AFFECTIONATE_TERM~ ❤️ +I'm so proud of you, my love~ ❤️ +MOMMYS_ROLE is so proud of you~ ❤️ +MOMMYS_ROLE loves seeing MOMMYS_PRONOUN little AFFECTIONATE_TERM succeed~ ❤️ +MOMMYS_ROLE thinks MOMMYS_PRONOUN little AFFECTIONATE_TERM earned a big hug~ ❤️ +that's a good AFFECTIONATE_TERM~ ❤️ +you did an amazing job, my dear~ ❤️ +you're such a smart cookie~ ❤️" + + # allow for overriding of default words (IF ANY SET) + + if [ -n "$SHELL_MOMMYS_LITTLE" ]; then + DEF_WORDS_LITTLE="${SHELL_MOMMYS_LITTLE}" + fi + if [ -n "$SHELL_MOMMYS_PRONOUNS" ]; then + DEF_WORDS_PRONOUNS="${SHELL_MOMMYS_PRONOUNS}" + fi + if [ -n "$SHELL_MOMMYS_ROLES" ]; then + DEF_WORDS_ROLES="${SHELL_MOMMYS_ROLES}" + fi + if [ -n "$SHELL_MOMMYS_COLOR" ]; then + DEF_MOMMY_COLOR="${SHELL_MOMMYS_COLOR}" + fi + # allow overriding to true + if [ "$SHELL_MOMMYS_ONLY_NEGATIVE" = "true" ]; then + DEF_ONLY_NEGATIVE="true" + fi + # if the variable is set for positive/negative responses, overwrite it + if [ -n "$SHELL_MOMMYS_POSITIVE_RESPONSES" ]; then + POSITIVE_RESPONSES="$SHELL_MOMMYS_POSITIVE_RESPONSES" + fi + if [ -n "$SHELL_MOMMYS_NEGATIVE_RESPONSES" ]; then + NEGATIVE_RESPONSES="$SHELL_MOMMYS_NEGATIVE_RESPONSES" + fi + + # split a string on forward slashes and return a random element + pick_word() { + echo "$1" | tr '/' '\n' | shuf | sed 1q + } + + pick_response() { # given a response type, pick an entry from the list + + if [ "$1" = "positive" ]; then + element=$(echo "$POSITIVE_RESPONSES" | shuf | sed 1q) + elif [ "$1" = "negative" ]; then + element=$(echo "$NEGATIVE_RESPONSES" | shuf | sed 1q) + else + echo "Invalid response type: $1" + exit 1 + fi + + # Return the selected response + echo "$element" + + } + + sub_terms() { # given a response, sub in the appropriate terms + response="$1" + # pick_word for each term + affectionate_term="$(pick_word "${DEF_WORDS_LITTLE}")" + pronoun="$(pick_word "${DEF_WORDS_PRONOUNS}")" + role="$(pick_word "${DEF_WORDS_ROLES}")" + # sub in the terms, store in variable + response="$(echo "$response" | sed "s/AFFECTIONATE_TERM/$affectionate_term/g")" + response="$(echo "$response" | sed "s/MOMMYS_PRONOUN/$pronoun/g")" + response="$(echo "$response" | sed "s/MOMMYS_ROLE/$role/g")" + # we have string literal newlines in the response, so we need to printf it out + # print faint and colorcode + printf "${DEF_MOMMY_COLOR}$response${COLORS_RESET}\n" + } + + success() { + ( + # if we're only supposed to show negative responses, return + if [ "$DEF_ONLY_NEGATIVE" = "true" ]; then + return 0 + fi + # pick_response for the response type + response="$(pick_response "positive")" + sub_terms "$response" >&2 + ) + return 0 + } + failure() { + rc=$? + ( + response="$(pick_response "negative")" + sub_terms "$response" >&2 + ) + return $rc + } + # eval is used here to allow for alias resolution + + # TODO: add a way to check if we're running from PROMPT_COMMAND to use the previous exit code instead of doing things this way + eval "$@" && success || failure + return $? +) diff --git a/sixcat b/sixcat new file mode 100755 index 0000000..3ba1d95 --- /dev/null +++ b/sixcat @@ -0,0 +1,283 @@ +#!/bin/bash + +# sixcat: Use sixel graphics to show an image inside a terminal. +# sixgif: Use sixel graphics to play an animation inside a terminal. + +# Version 1.0 +# hackerb9, June 2017 + +# Sixel graphics are supported by terminals such as the DEC VT340 and +# emulators, such as 'xterm -ti vt340'. + +# ImageMagick is required. (apt-get install imagemagick) + +# The heart of this program is really just one line: +# +# convert foo.jpg sixel:- +# +# All the other lines are bells and whistles, mostly to make the image +# look better by increasing the number of colors available. + + +###################################################################### +# Configuration +###################################################################### + +# Number of colors in the terminal's sixel palette. +# (But also see the -x and -n options). +default_numcolors=16 # Genuine vt340's had a 16-color palette. + +# Maximum image size is terminal dependent, so we have to guess. +geometry="-geometry 800x480>" # this was the actual vt340 resolution +#geometry="-geometry 800x800>" # allows for portrait orientation +#geometry="-geometry 1000x1000>" # maximum allowed in xterm322 + +# Should ImageMagick dither the image to make it look better? +# (Use dither="" to disable.) +dither="-dither floyd-steinberg" + +# Maximum number of seconds to wait for a response from the terminal +# after a color escape sequence request. Usually, terminals respond +# much faster than 0.1 seconds, but I could imagine it needing to be +# increased for slow links (e.g., RS232C). +timeout=0.1 + + +###################################################################### +# Helper functions +###################################################################### + +usage() { + cat < + + -x: Force the use of xterm escape sequences to detect and + change the palette size instead of defaulting to $default_numcolors. + If the palette is smaller than 1024, it is set to 1024. + + Note that -x is the default if \$TERM is "xterm". + + -X: Just assume palette size is $default_numcolors. + Does not use xterm escape sequences regardless of \$TERM. + + -n INTEGER: + Assume pallete size is INTEGER. + Does not use xterm escape sequences regardless of \$TERM. + +Note: if this program is called sixgif, it will play GIF animations +in the top left instead of scrolling all the frames as multiple images. + +EOF +} + + +# Some functions to deal with checking and changing the number of +# colors the terminal can show. Likely xterm specific, but YMMV. + +getnumcolors() { + # Query xterm for the palette size and print it. + # (Negative numbers indicate errors.) + colors 1 0 +} + +resetnumcolors() { + # Reset xterm back to its default number of colors. + # Print the new number of colors (negative if an error occurred.) + colors 2 0 +} + +setnumcolors() { + # Request xterm to change the number of colors in its palette. + # Print the new number of colors (negative if an error occurred.) + colors 3 $1 +} + +colors() { + # Send an xterm escape code request in the form: ^[[?1;3;1024S + # Print the response value (or a negative number if an error occurs) + csi=$'\e[' + action=$1 # Action. 1 to get, 2 to reset, 3 to set + value=$2 # Number of colors to set + returnvalue=-1 + + # Raw response is in the same form as request: ^[[?1;0;1024S + # Let's parse it to be more manageable. + IFS=";" \ + read -a REPLY -s -t $timeout -d "S" \ + -p "${csi}?1;${action};${value}S" + + if [[ $? != 0 || ${#REPLY} == 0 ]]; then + # No response to VT escape sequence. Maybe you are not an xterm? + # Or, perhaps timeout is too short? + returnvalue=-2 + elif [[ "${REPLY[1]}" == "3" ]]; then + # Response code 3 means error. Likely too many colors requested. + returnvalue=-3 + elif [[ "${REPLY[1]}" == "0" ]] ; then + # 0 means okay. Yay! + returnvalue=${REPLY[2]} + else + # If we get here, response was not in the format we expected. + # Perhaps user typed during xterm response? Or cosmic rays? + returnvalue=-4 + fi + + echo $returnvalue +} + +waitforterminal() { + # Send an escape sequence and wait for a response from the terminal. + # This routine will let us know when an image transfer has finished + # and it's okay to send escape sequences that request results. + # (E.g., if we want to run resetnumcolors at the end of the program.) + # WARNING. While this should work with any terminal, if it fails, + # it'll end up waiting for approximately *forever* (i.e., 60 seconds). + read -s -t 60 -d "c" -p $'\e[c' +} + + +debugeta() { + # Given a number of bytes, estimate the amount of time its going + # to take to send at the current TTY baud rate. + # Mostly for larks as this will be completely bogus on terminal emulators. + + len=$1 + + # Static variables to store TTY type and STTY speed. + [[ "$TTY" ]] || TTY=$(tty) + [[ "$SPEED" ]] || SPEED=$(stty speed) || SPEED=0 + + echo "sixel command length is $len bytes" + + if [[ "$SPEED" -gt 0 ]]; then + if [[ "$TTY" =~ /pt || "$TTY" =~ ttyp ]]; then + echo "pseudoterminal detected (speed estimates only valid for real hardware)" + fi + echo "terminal speed is $SPEED bps" + echo "estimated time to send: $((len*8/SPEED)) seconds" + fi +} + + +# If the user hits ^C, we don't want them stuck in SIXEL mode +cleanup() { + echo -n $'\e[?80h' # Reenable sixel scrolling + echo -n $'\e\\' # Escape sequence to stop SIXEL + exit 0 +} +trap cleanup SIGINT SIGHUP SIGABRT + + +###################################################################### +# MAIN BEGINS HERE +###################################################################### + +if [ $# -eq 0 ]; then + usage + exit 1 +else + case "$1" in + -n|--num-colors) shift + nflag="$1" + shift + # Just assume the palette is n colors. Do not bother checking or changing. + # (Might be needed for some terminal emulators. I do not know.) + if [[ "$nflag" -gt 0 ]]; then + default_numcolors=$nflag + else + usage + exit 1 + fi + ;; + -x|--force-xterm-colors) shift + # Force xterm palette manipulation, regardless of $TERM + # (Might be needed for some terminal emulators. I do not know.) + xflag=yup + ;; + -X|--disable-xterm-colors) shift + # Disable xterm palette manipulation, regardless of $TERM + # (Might be needed for some terminal emulators. I do not know.) + Xflag=yup + ;; + -*) + usage + exit 1 + ;; + esac +fi + + + +numcolors=$default_numcolors + +# Optionally detect and set the number of palette colors +if [[ "$xflag" || -z "$Xflag" && -z "$nflag" && "$TERM" =~ ^xterm ]]; then + # Since the VT340 only had a palette of 16 colors, we can vastly + # improve the image if we tell xterm to increase it to 1024. + # This would fail on a real VT340. + palettechanged=yup + oldnumcolors=$(getnumcolors) + if [[ $oldnumcolors -lt 1024 ]]; then + numcolors=$(setnumcolors 1024) + if [[ $numcolors -le 0 ]]; then + echo -e "\rTerminal did not accept escape sequence to increase color palette. Are you really an xterm?" >&2 + numcolors=$default_numcolors + fi + else + # At least 1024 colors, so do not change anything + numcolors=$oldnumcolors + palettechanged= + fi +fi + + +# Small optimization (saves half a second) +if [[ $numcolors == 1024 ]]; then + # Imagemagick already defaults to 1024 colors for sixel + colors="" +else + colors="-colors $numcolors" +fi + + +# Print image filename after showing it? Yes, if multiple files. +if [[ $# -gt 1 ]]; then + showname=yup +else + showname="" +fi + + +# PAST IS PROLOGUE... NOW TO THE MEAT. +for f; do + x=$(convert "$f" $geometry $colors sixel:- 2>/dev/null) + [[ ${#x} != 0 ]] || continue # The sixel command length better be >0 + + : debugeta ${#x} + + case $0 in + *sixgif) + # If this program is named "sixgif" play files as animations, + # instead of displaying each frame and scrolling down. + echo -n $'\e[?80l' # Disable sixel scrolling + for t in {1..3}; do + echo -n "$x" # sixgif plays repeatedly + done + echo -n $'\e[?80h' # Reenable sixel scrolling + ;; + + *) + echo -n "$x" # sixcat just shows once + [[ "$showname" ]] && echo "$f" + ;; + esac +done + + +# TIDY UP +waitforterminal +if [[ "$palettechanged" ]]; then + # Reset color palette + numcolors=$(resetnumcolors) + : echo Number of colors reset to $numcolors >&2 +fi diff --git a/startup_gns3.sh b/startup_gns3.sh new file mode 100644 index 0000000..813a7f1 --- /dev/null +++ b/startup_gns3.sh @@ -0,0 +1,4 @@ +sudo systemctl start docker +sudo systemctl start virtqemud +sudo systemctl start libvirtd +sudo systemctl start gns3-server@belar diff --git a/toggle-tailscale-exit-node.sh b/toggle-tailscale-exit-node.sh new file mode 100644 index 0000000..08231c8 --- /dev/null +++ b/toggle-tailscale-exit-node.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +EXIT_NODE=tailscale-jumphost +STATE=$(tailscale status | grep "$EXIT_NODE" | awk -F ';' '{print $2}' | tr -d ' ') + +if [ "$STATE" == "offersexitnode" ]; then + sudo tailscale set --exit-node=tailscale-jumphost.tailf6c9a.ts.net. + if ping -c 192.168.0.1 > /dev/null 2>&1; then + notify-send -i ${HOME}/.scripts/icons/tailscale.png "Tailscale Exit Node" "Tunnel Activated: $EXIT_NODE" + else + notify-send --urgency=critical -i ${HOME}/.scripts/icons/tailscale.png "Tailscale Exit Node" "Error" + fi +fi + +if [ "$STATE" == "exitnode" ]; then + sudo tailscale set --exit-node= + if ping -c 1 1.1.1.1 > /dev/null 2>&1; then + notify-send -i ${HOME}/.scripts/icons/tailscale.png "Tailscale Exit Node" "Tunnel Deactivated" + else + notify-send --urgency=critical -i ${HOME}/.scripts/icons/tailscale.png "Tailscale Exit Node" "Error" + fi +fi