From d55248989fe4aa8b7c6f5d06ac8a89b66ba3aba8 Mon Sep 17 00:00:00 2001 From: kj-sh604 Date: Tue, 10 Jun 2025 13:32:36 -0400 Subject: refactor: multiple changes (see description) * add LICENSEs where necesary * remove *pkg scripts from repo see: https://github.com/kj-sh604/gitpkg * rename .local/src python directories * update .local/bin scripts in relation to above --- .local/bin/GUI-dateTime | 4 +- .local/bin/aria2pkg | 60 ---- .local/bin/curlpkg | 60 ---- .local/bin/playerctl_systray | 4 +- .local/bin/rainfall | 4 +- .local/bin/wgetpkg | 60 ---- .local/src/dateTimeSetter/LICENSE | 12 + .local/src/dateTimeSetter/Makefile | 4 + .local/src/dateTimeSetter/dateTime-GTK3.old.py | 87 +++++ .local/src/dateTimeSetter/dateTime.py | 360 +++++++++++++++++++++ .local/src/playerctl_systray/LICENSE | 12 + .local/src/playerctl_systray/Makefile | 4 + .local/src/playerctl_systray/playerctl_systray.py | 123 +++++++ .local/src/python-dateTimeSetter/Makefile | 4 - .../src/python-dateTimeSetter/dateTime-GTK3.old.py | 87 ----- .local/src/python-dateTimeSetter/dateTime.py | 360 --------------------- .local/src/python-playerctl_systray/Makefile | 4 - .../python-playerctl_systray/playerctl_systray.py | 123 ------- .local/src/python-rainfall/Makefile | 4 - .local/src/python-rainfall/rainfall.py | 161 --------- .local/src/rainfall/LICENSE | 21 ++ .local/src/rainfall/Makefile | 4 + .local/src/rainfall/rainfall.py | 161 +++++++++ 23 files changed, 794 insertions(+), 929 deletions(-) delete mode 100755 .local/bin/aria2pkg delete mode 100755 .local/bin/curlpkg delete mode 100755 .local/bin/wgetpkg create mode 100644 .local/src/dateTimeSetter/LICENSE create mode 100644 .local/src/dateTimeSetter/Makefile create mode 100644 .local/src/dateTimeSetter/dateTime-GTK3.old.py create mode 100644 .local/src/dateTimeSetter/dateTime.py create mode 100644 .local/src/playerctl_systray/LICENSE create mode 100644 .local/src/playerctl_systray/Makefile create mode 100644 .local/src/playerctl_systray/playerctl_systray.py delete mode 100644 .local/src/python-dateTimeSetter/Makefile delete mode 100644 .local/src/python-dateTimeSetter/dateTime-GTK3.old.py delete mode 100644 .local/src/python-dateTimeSetter/dateTime.py delete mode 100644 .local/src/python-playerctl_systray/Makefile delete mode 100644 .local/src/python-playerctl_systray/playerctl_systray.py delete mode 100644 .local/src/python-rainfall/Makefile delete mode 100644 .local/src/python-rainfall/rainfall.py create mode 100644 .local/src/rainfall/LICENSE create mode 100644 .local/src/rainfall/Makefile create mode 100644 .local/src/rainfall/rainfall.py (limited to '.local') diff --git a/.local/bin/GUI-dateTime b/.local/bin/GUI-dateTime index 23b6625..a20fd28 100755 --- a/.local/bin/GUI-dateTime +++ b/.local/bin/GUI-dateTime @@ -1,7 +1,7 @@ #!/bin/sh -BIN_PATH=~/.local/src/python-dateTimeSetter/dateTime -SCRIPT_PATH=~/.local/src/python-dateTimeSetter/dateTime.py +BIN_PATH=~/.local/src/dateTimeSetter/dateTime +SCRIPT_PATH=~/.local/src/dateTimeSetter/dateTime.py if [ -f "$BIN_PATH" ]; then if command -v lxsudo > /dev/null 2>&1; then diff --git a/.local/bin/aria2pkg b/.local/bin/aria2pkg deleted file mode 100755 index 378008c..0000000 --- a/.local/bin/aria2pkg +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh - -check_aria2c_installed() { - if ! command -v aria2c >/dev/null 2>&1; then - echo "error: aria2c is not installed :( please install aria2c to use aria2pkg." - exit 1 - fi -} - -_base_url='https://aur.archlinux.org/cgit/aur.git/snapshot' - -get_url_function() { - _pkg="$1" - _url="${_base_url}/${_pkg}.tar.gz" - - echo "$_url" -} - -run_aria2pkg_function() { - _pkg="$(echo "$1" | tr -d '[:space:]')" - _url="$(get_url_function "$_pkg")" - - aria2c --quiet --console-log-level=error "$_url" -} - -aria2pkg_function() { - for _pkg in "$@"; do - run_aria2pkg_function "$_pkg" & - done - wait -} - -usage_function() { - cat < ... - -Options: - -h, --help - print this help message -EOF -} - -check_aria2c_installed - -while [ $# -gt 0 ]; do - case "$1" in - -*) - usage_function - exit 0 - ;; - *) - aria2pkg_function "$@" - exit 0 - ;; - esac -done - -# vim: set filetype=sh foldmethod=marker foldlevel=0: diff --git a/.local/bin/curlpkg b/.local/bin/curlpkg deleted file mode 100755 index 5b48b7f..0000000 --- a/.local/bin/curlpkg +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh - -check_curl_installed() { - if ! command -v curl >/dev/null 2>&1; then - echo "error: curl is not installed :( please install curl to use curlpkg." - exit 1 - fi -} - -_base_url='https://aur.archlinux.org/cgit/aur.git/snapshot' - -get_url_function() { - _pkg="$1" - _url="${_base_url}/${_pkg}.tar.gz" - - echo "$_url" -} - -run_curlpkg_function() { - _pkg="$(echo "$1" | tr -d '[:space:]')" - _url="$(get_url_function "$_pkg")" - - curl -sSL "$_url" -o "${_pkg}.tar.gz" -} - -curlpkg_function() { - for _pkg in "$@"; do - run_curlpkg_function "$_pkg" & - done - wait -} - -usage_function() { - cat < ... - -Options: - -h, --help - print this help message -EOF -} - -check_curl_installed - -while [ $# -gt 0 ]; do - case "$1" in - -*) - usage_function - exit 0 - ;; - *) - curlpkg_function "$@" - exit 0 - ;; - esac -done - -# vim: set filetype=sh foldmethod=marker foldlevel=0: diff --git a/.local/bin/playerctl_systray b/.local/bin/playerctl_systray index f96c28a..1e57307 100755 --- a/.local/bin/playerctl_systray +++ b/.local/bin/playerctl_systray @@ -1,7 +1,7 @@ #!/bin/sh -BIN_PATH=~/.local/src/python-playerctl_systray/playerctl_systray -SCRIPT_PATH=~/.local/src/python-playerctl_systray/playerctl_systray.py +BIN_PATH=~/.local/src/playerctl_systray/playerctl_systray +SCRIPT_PATH=~/.local/src/playerctl_systray/playerctl_systray.py if ! command -v playerctl >/dev/null 2>&1; then echo "playerctl is not installed but is required." diff --git a/.local/bin/rainfall b/.local/bin/rainfall index 7d9e082..54ab525 100755 --- a/.local/bin/rainfall +++ b/.local/bin/rainfall @@ -1,7 +1,7 @@ #!/bin/sh -BIN_PATH=~/.local/src/python-rainfall/rainfall -SCRIPT_PATH=~/.local/src/python-rainfall/rainfall.py +BIN_PATH=~/.local/src/rainfall/rainfall +SCRIPT_PATH=~/.local/src/rainfall/rainfall.py if [ -f "$BIN_PATH" ]; then $BIN_PATH diff --git a/.local/bin/wgetpkg b/.local/bin/wgetpkg deleted file mode 100755 index d1738c8..0000000 --- a/.local/bin/wgetpkg +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh - -check_wget_installed() { - if ! command -v wget >/dev/null 2>&1; then - echo "error: wget is not installed :( please install wget to use wgetpkg." - exit 1 - fi -} - -_base_url='https://aur.archlinux.org/cgit/aur.git/snapshot' - -get_url_function() { - _pkg="$1" - _url="${_base_url}/${_pkg}.tar.gz" - - echo "$_url" -} - -run_wgetpkg_function() { - _pkg="$(echo "$1" | tr -d '[:space:]')" - _url="$(get_url_function "$_pkg")" - - wget --no-verbose "$_url" -} - -wgetpkg_function() { - for _pkg in "$@"; do - run_wgetpkg_function "$_pkg" & - done - wait -} - -usage_function() { - cat < ... - -Options: - -h, --help - print this help message -EOF -} - -check_wget_installed - -while [ $# -gt 0 ]; do - case "$1" in - -*) - usage_function - exit 0 - ;; - *) - wgetpkg_function "$@" - exit 0 - ;; - esac -done - -# vim: set filetype=sh foldmethod=marker foldlevel=0: diff --git a/.local/src/dateTimeSetter/LICENSE b/.local/src/dateTimeSetter/LICENSE new file mode 100644 index 0000000..1d47b15 --- /dev/null +++ b/.local/src/dateTimeSetter/LICENSE @@ -0,0 +1,12 @@ +Copyright kj_sh604 + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/.local/src/dateTimeSetter/Makefile b/.local/src/dateTimeSetter/Makefile new file mode 100644 index 0000000..91b1c6e --- /dev/null +++ b/.local/src/dateTimeSetter/Makefile @@ -0,0 +1,4 @@ +compile: + cython3 --embed -o dateTime.c -X language_level=3 dateTime.py + PYTHON_VERSION=`ls --sort version /usr/include | grep -o 'python[3-9]\+\.[0-9]\+' | tail -1` ; \ + gcc -march=native -O2 -pipe -fno-plt -I /usr/include/$$PYTHON_VERSION -o dateTime dateTime.c -l$$PYTHON_VERSION -lpthread -lm -lutil -ldl diff --git a/.local/src/dateTimeSetter/dateTime-GTK3.old.py b/.local/src/dateTimeSetter/dateTime-GTK3.old.py new file mode 100644 index 0000000..186c671 --- /dev/null +++ b/.local/src/dateTimeSetter/dateTime-GTK3.old.py @@ -0,0 +1,87 @@ +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk, GLib +import subprocess + +class dateTimeSetter(Gtk.Window): + def __init__(self): + Gtk.Window.__init__(self, title="dateTimeSetter") + self.set_border_width(10) + self.set_default_size(400, 300) + + vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) + self.add(vbox) + + # Automatic time setting checkbox + automatic_time_label = Gtk.Label(label="Set the date, time, and timezone automatically?") + vbox.pack_start(automatic_time_label, False, False, 0) + + self.automatic_time_check = Gtk.CheckButton(label="Yes") + self.automatic_time_check.connect("toggled", self.on_automatic_time_toggled) + vbox.pack_start(self.automatic_time_check, False, False, 0) + + # Date and time entry fields + date_label = Gtk.Label(label="Enter the desired date (format: YYYY-MM-DD):") + vbox.pack_start(date_label, False, False, 0) + + self.date_entry = Gtk.Entry() + vbox.pack_start(self.date_entry, False, False, 0) + + time_label = Gtk.Label(label="Enter the desired time (format: HH:MM:SS):") + vbox.pack_start(time_label, False, False, 0) + + self.time_entry = Gtk.Entry() + vbox.pack_start(self.time_entry, False, False, 0) + + # Timezone entry field + timezone_label = Gtk.Label(label="Enter the desired timezone (e.g., America/New_York):") + vbox.pack_start(timezone_label, False, False, 0) + + self.timezone_entry = Gtk.Entry() + vbox.pack_start(self.timezone_entry, False, False, 0) + + # Apply button + apply_button = Gtk.Button(label="Apply") + apply_button.connect("clicked", self.on_apply_clicked) + vbox.pack_start(apply_button, False, False, 0) + + def on_automatic_time_toggled(self, button): + if button.get_active(): + self.date_entry.set_sensitive(False) + self.time_entry.set_sensitive(False) + self.timezone_entry.set_sensitive(False) + else: + self.date_entry.set_sensitive(True) + self.time_entry.set_sensitive(True) + self.timezone_entry.set_sensitive(True) + + def on_apply_clicked(self, button): + automatic_time = self.automatic_time_check.get_active() + + if automatic_time: + subprocess.run(["timedatectl", "set-ntp", "true"]) + print("Automatic time synchronization using NTP initiated.") + + automatic_timezone_output = subprocess.run(["curl", "--fail", "https://ipapi.co/timezone"], capture_output=True, text=True) + automatic_timezone = automatic_timezone_output.stdout.strip() + + if automatic_timezone: + subprocess.run(["timedatectl", "set-timezone", automatic_timezone]) + print("Automatic timezone setting complete.") + else: + print("Automatic timezone setting failed. Please set the timezone manually.") + else: + date_input = self.date_entry.get_text() + time_input = self.time_entry.get_text() + timezone_input = self.timezone_entry.get_text() + + subprocess.run(["timedatectl", "set-ntp", "false"]) + subprocess.run(["timedatectl", "set-time", f"{date_input} {time_input}"]) + subprocess.run(["timedatectl", "set-timezone", timezone_input]) + print("Manual date, time, and timezone setting complete.") + + +win = dateTimeSetter() +win.connect("destroy", Gtk.main_quit) +win.show_all() +Gtk.main() diff --git a/.local/src/dateTimeSetter/dateTime.py b/.local/src/dateTimeSetter/dateTime.py new file mode 100644 index 0000000..4d7ab5e --- /dev/null +++ b/.local/src/dateTimeSetter/dateTime.py @@ -0,0 +1,360 @@ +import tkinter as tk +from tkinter import ttk, messagebox +import subprocess +import requests +import datetime +import pytz +import time + + +class DateTimeSetter(tk.Tk): + def __init__(self): + super().__init__() + + self.title("dateTimeSetter") + self.geometry("800x600") + self.resizable(True, True) + self.attributes("-type", "dialog") # make the window floating + + self.create_widgets() + self.populate_fields() + + def create_widgets(self): + # automatic time setting checkbox + automatic_time_label = ttk.Label( + self, text="Set the date, time, and timezone automatically?") + automatic_time_label.pack(pady=5) + + self.automatic_time_check = ttk.Checkbutton( + self, text="Yes", command=self.on_automatic_time_toggled) + self.automatic_time_check.pack(pady=5) + + # date entry fields + date_frame = ttk.LabelFrame(self, text="Date") + date_frame.pack(pady=10, padx=10, fill="x") + + ttk.Label(date_frame, text="YYYY:").grid( + row=0, column=0, padx=5, pady=5) + self.year_var = tk.StringVar() + self.year_combo = ttk.Combobox(date_frame, textvariable=self.year_var, values=[str( + year) for year in range(1970, 2039)], state="normal") + self.year_combo.grid(row=0, column=1, padx=5, pady=5) + + ttk.Label(date_frame, text="MM:").grid(row=0, column=2, padx=5, pady=5) + self.month_var = tk.StringVar() + self.month_combo = ttk.Combobox(date_frame, textvariable=self.month_var, values=[str( + month) for month in range(1, 13)], state="normal") + self.month_combo.grid(row=0, column=3, padx=5, pady=5) + + ttk.Label(date_frame, text="DD:").grid(row=0, column=4, padx=5, pady=5) + self.day_var = tk.StringVar() + self.day_combo = ttk.Combobox( + date_frame, textvariable=self.day_var, values=[str(day) for day in range(1, 32)], state="normal") + self.day_combo.grid(row=0, column=5, padx=5, pady=5) + + # time entry fields + time_frame = ttk.LabelFrame(self, text="Time (24hr)") + time_frame.pack(pady=10, padx=10, fill="x") + + ttk.Label(time_frame, text=" HH:").grid( + row=0, column=0, padx=5, pady=5) + self.hour_var = tk.StringVar() + self.hour_combo = ttk.Combobox(time_frame, textvariable=self.hour_var, values=[str( + hour) for hour in range(0, 24)], state="normal") + self.hour_combo.grid(row=0, column=1, padx=5, pady=5) + + ttk.Label(time_frame, text="MM:").grid(row=0, column=2, padx=5, pady=5) + self.minute_var = tk.StringVar() + self.minute_combo = ttk.Combobox(time_frame, textvariable=self.minute_var, values=[str( + minute) for minute in range(0, 60)], state="normal") + self.minute_combo.grid(row=0, column=3, padx=5, pady=5) + + ttk.Label(time_frame, text="SS:").grid(row=0, column=4, padx=5, pady=5) + self.second_var = tk.StringVar() + self.second_combo = ttk.Combobox(time_frame, textvariable=self.second_var, values=[str( + second) for second in range(0, 60)], state="normal") + self.second_combo.grid(row=0, column=5, padx=5, pady=5) + + # timezone entry field + timezone_frame = ttk.LabelFrame(self, text="Timezone") + timezone_frame.pack(pady=10, padx=10, fill="x") + + ttk.Label(timezone_frame, text="Timezone:").grid( + row=0, column=0, padx=5, pady=5) + self.timezone_var = tk.StringVar() + self.timezone_combo = ttk.Combobox( + timezone_frame, textvariable=self.timezone_var, values=pytz.all_timezones, state="normal") + self.timezone_combo.grid(row=0, column=1, padx=5, pady=5) + + # set-local-rtc checkbox + self.local_rtc_check = ttk.Checkbutton( + timezone_frame, text="Set local RTC") + self.local_rtc_check.grid( + row=1, column=0, columnspan=2, padx=5, pady=5) + + # apply button + button_frame = ttk.Frame(self) + button_frame.pack(pady=20) + + self.apply_button = ttk.Button( + button_frame, text="Apply All", command=self.on_apply_clicked) + self.apply_button.grid(row=0, column=0, padx=5) + + self.timezone_apply_button = ttk.Button( + button_frame, text="Apply Timezone", command=self.on_timezone_apply_clicked) + self.timezone_apply_button.grid(row=0, column=1, padx=5) + + self.date_time_apply_button = ttk.Button( + button_frame, text="Apply Date & Time", command=self.on_date_time_apply_clicked) + self.date_time_apply_button.grid(row=0, column=2, padx=5) + + self.local_rtc_apply_button = ttk.Button( + button_frame, text="Apply Local RTC", command=self.on_local_rtc_apply_clicked) + self.local_rtc_apply_button.grid(row=0, column=3, padx=5) + + self.update_apply_button_state() + + # Set trace on all variables to call update_apply_button_state when they change + self.year_var.trace_add("write", self.update_apply_button_state) + self.month_var.trace_add("write", self.update_apply_button_state) + self.day_var.trace_add("write", self.update_apply_button_state) + self.hour_var.trace_add("write", self.update_apply_button_state) + self.minute_var.trace_add("write", self.update_apply_button_state) + self.second_var.trace_add("write", self.update_apply_button_state) + self.timezone_var.trace_add("write", self.update_apply_button_state) + + def on_automatic_time_toggled(self): + if self.automatic_time_check.instate(['selected']): + self.year_combo.state(['disabled']) + self.month_combo.state(['disabled']) + self.day_combo.state(['disabled']) + self.hour_combo.state(['disabled']) + self.minute_combo.state(['disabled']) + self.second_combo.state(['disabled']) + self.timezone_combo.state(['disabled']) + else: + self.year_combo.state(['!disabled']) + self.month_combo.state(['!disabled']) + self.day_combo.state(['!disabled']) + self.hour_combo.state(['!disabled']) + self.minute_combo.state(['!disabled']) + self.second_combo.state(['!disabled']) + self.timezone_combo.state(['!disabled']) + self.update_apply_button_state() + + def update_apply_button_state(self, *_): + if self.automatic_time_check.instate(['selected']): + self.apply_button.state(['!disabled']) + self.timezone_apply_button.state(['disabled']) + self.date_time_apply_button.state(['disabled']) + self.local_rtc_apply_button.state(['disabled']) + else: + all_date_filled = all([ + self.year_combo.get(), + self.month_combo.get(), + self.day_combo.get(), + ]) + all_time_filled = all([ + self.hour_combo.get(), + self.minute_combo.get(), + self.second_combo.get(), + ]) + timezone_filled = self.timezone_combo.get() + all_filled = all_date_filled and all_time_filled and timezone_filled + + if all_filled: + self.apply_button.state(['!disabled']) + else: + self.apply_button.state(['disabled']) + + if timezone_filled and self.validate_timezone(timezone_filled): + self.timezone_apply_button.state(['!disabled']) + else: + self.timezone_apply_button.state(['disabled']) + + if all_date_filled and all_time_filled: + self.date_time_apply_button.state(['!disabled']) + else: + self.date_time_apply_button.state(['disabled']) + + self.local_rtc_apply_button.state(['!disabled']) + + def on_apply_clicked(self): + automatic_time = self.automatic_time_check.instate(['selected']) + local_rtc = self.local_rtc_check.instate(['selected']) + + if automatic_time: + subprocess.run(["timedatectl", "set-ntp", "true"]) + + try: + automatic_timezone_output = subprocess.run( + ["curl", "--fail", "https://ipinfo.io/timezone"], capture_output=True, text=True) + automatic_timezone = automatic_timezone_output.stdout.strip() + + if automatic_timezone: + subprocess.run( + ["timedatectl", "set-timezone", automatic_timezone]) + messagebox.showinfo( + "Info", "Automatic date, time, and timezone setting complete.") + else: + messagebox.showwarning( + "Warning", "Automatic date, time, and timezone setting failed. Please try again or use timedatectl.") + except requests.RequestException: + messagebox.showwarning( + "Warning", "Failed to fetch date, time, and timezone information. Please try again or use timedatectl.") + else: + try: + date_input = f"{self.year_combo.get()}-{int(self.month_combo.get()):02d}-{int(self.day_combo.get()):02d}" + time_input = f"{int(self.hour_combo.get()):02d}:{int(self.minute_combo.get()):02d}:{int(self.second_combo.get()):02d}" + timezone_input = self.timezone_combo.get() + + # check for invalid numbers in fields + if not all([ + self.validate_number(self.year_combo.get(), 1970, 2038), + self.validate_number(self.month_combo.get(), 1, 12), + self.validate_number(self.day_combo.get(), 1, 31), + self.validate_number(self.hour_combo.get(), 0, 23), + self.validate_number(self.minute_combo.get(), 0, 59), + self.validate_number(self.second_combo.get(), 0, 59), + self.validate_timezone(timezone_input) + ]): + messagebox.showerror( + "Error", "Invalid number entered in one or more fields.") + return + + subprocess.run(["timedatectl", "set-ntp", "false"]) + time.sleep(1) + subprocess.run(["timedatectl", "set-timezone", timezone_input]) + time.sleep(1) + subprocess.run(["timedatectl", "set-time", + f"{date_input} {time_input}"]) + messagebox.showinfo( + "Info", "Manual date, time, and timezone setting complete.") + except ValueError as e: + messagebox.showerror("Error", f"Error:\n{e}\n\nOne or more blank fields!") + + # handle local rtc setting + if local_rtc: + subprocess.run(["timedatectl", "set-local-rtc", "1"]) + else: + subprocess.run(["timedatectl", "set-local-rtc", "0"]) + + def on_timezone_apply_clicked(self): + timezone_input = self.timezone_combo.get() + + if not timezone_input or not self.validate_timezone(timezone_input): + messagebox.showerror("Error", "Invalid or empty timezone field.") + return + + try: + subprocess.run(["timedatectl", "set-timezone", timezone_input]) + messagebox.showinfo( + "Info", "Timezone setting complete.") + except subprocess.CalledProcessError as e: + messagebox.showerror("Error", f"Error setting timezone:\n{e}") + + def on_date_time_apply_clicked(self): + try: + date_input = f"{self.year_combo.get()}-{int(self.month_combo.get()):02d}-{int(self.day_combo.get()):02d}" + time_input = f"{int(self.hour_combo.get()):02d}:{int(self.minute_combo.get()):02d}:{int(self.second_combo.get()):02d}" + + # check for invalid numbers in fields + if not all([ + self.validate_number(self.year_combo.get(), 1970, 2038), + self.validate_number(self.month_combo.get(), 1, 12), + self.validate_number(self.day_combo.get(), 1, 31), + self.validate_number(self.hour_combo.get(), 0, 23), + self.validate_number(self.minute_combo.get(), 0, 59), + self.validate_number(self.second_combo.get(), 0, 59), + ]): + messagebox.showerror( + "Error", "Invalid number entered in one or more fields.") + return + + subprocess.run(["timedatectl", "set-ntp", "false"]) + time.sleep(1) + subprocess.run(["timedatectl", "set-time", f"{date_input} {time_input}"]) + messagebox.showinfo( + "Info", "Manual date and time setting complete.") + except ValueError as e: + messagebox.showerror("Error", f"Error:\n{e}\n\nOne or more blank fields!") + + def on_local_rtc_apply_clicked(self): + local_rtc = self.local_rtc_check.instate(['selected']) + + if local_rtc: + subprocess.run(["timedatectl", "set-local-rtc", "1"]) + messagebox.showinfo("Info", "Local RTC setting enabled.") + else: + subprocess.run(["timedatectl", "set-local-rtc", "0"]) + messagebox.showinfo("Info", "Local RTC setting disabled.") + + def validate_number(self, value, min_val, max_val): + try: + num = int(value) + return min_val <= num <= max_val + except ValueError: + return False + + def validate_timezone(self, timezone): + return timezone in pytz.all_timezones + + def populate_fields(self): + now = datetime.datetime.now() + self.year_combo.set(now.year) + self.month_combo.set(now.month) + self.day_combo.set(now.day) + self.hour_combo.set(now.hour) + self.minute_combo.set(now.minute) + self.second_combo.set(now.second) + + try: + current_timezone = subprocess.check_output( + ["timedatectl", "show", "--property=Timezone"]).decode().strip().split("=")[1] + self.timezone_combo.set(current_timezone) + except subprocess.CalledProcessError: + pass + + try: + ntp_status = subprocess.check_output( + ["timedatectl", "show", "--property=NTP"]).decode().strip().split("=")[1] + if ntp_status == "yes": + self.automatic_time_check.state(['selected']) + self.on_automatic_time_toggled() + else: + self.automatic_time_check.state(['!selected']) + self.on_automatic_time_toggled() + except subprocess.CalledProcessError: + pass + + try: + local_rtc_status = subprocess.check_output( + ["timedatectl", "show", "--property=LocalRTC"]).decode().strip().split("=")[1] + if local_rtc_status == "yes": + self.local_rtc_check.state(['selected']) + else: + self.local_rtc_check.state(['!selected']) + except subprocess.CalledProcessError: + pass + + self.year_combo.bind("<>", + self.update_apply_button_state) + self.month_combo.bind("<>", + self.update_apply_button_state) + self.day_combo.bind("<>", + self.update_apply_button_state) + self.hour_combo.bind("<>", + self.update_apply_button_state) + self.minute_combo.bind("<>", + self.update_apply_button_state) + self.second_combo.bind("<>", + self.update_apply_button_state) + self.timezone_combo.bind( + "<>", self.update_apply_button_state) + self.timezone_combo.bind( + "", self.update_apply_button_state) + + +if __name__ == "__main__": + app = DateTimeSetter() + app.mainloop() diff --git a/.local/src/playerctl_systray/LICENSE b/.local/src/playerctl_systray/LICENSE new file mode 100644 index 0000000..1d47b15 --- /dev/null +++ b/.local/src/playerctl_systray/LICENSE @@ -0,0 +1,12 @@ +Copyright kj_sh604 + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/.local/src/playerctl_systray/Makefile b/.local/src/playerctl_systray/Makefile new file mode 100644 index 0000000..a0ab881 --- /dev/null +++ b/.local/src/playerctl_systray/Makefile @@ -0,0 +1,4 @@ +compile: + cython3 --embed -o playerctl_systray.c -X language_level=3 playerctl_systray.py + PYTHON_VERSION=`ls --sort version /usr/include | grep -o 'python[3-9]\+\.[0-9]\+' | tail -1` ; \ + gcc -march=native -O2 -pipe -fno-plt -I /usr/include/$$PYTHON_VERSION -o playerctl_systray playerctl_systray.c -l$$PYTHON_VERSION -lpthread -lm -lutil -ldl `pkg-config --cflags --libs gtk+-3.0 appindicator3-0.1 dbus-1 dbus-glib-1` diff --git a/.local/src/playerctl_systray/playerctl_systray.py b/.local/src/playerctl_systray/playerctl_systray.py new file mode 100644 index 0000000..79a4c0c --- /dev/null +++ b/.local/src/playerctl_systray/playerctl_systray.py @@ -0,0 +1,123 @@ +import gi +import subprocess + +gi.require_version('Gtk', '3.0') +gi.require_version('AppIndicator3', '0.1') +gi.require_version('GLib', '2.0') +from gi.repository import Gtk, AppIndicator3, GLib + +class playerctl_systray: + def __init__(self): + self.last_instances = self.get_player_instances() + self.indicator = AppIndicator3.Indicator.new( + "media-control-app", + "audio-x-generic", + AppIndicator3.IndicatorCategory.APPLICATION_STATUS + ) + self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE) + self.indicator.set_menu(self.create_menu()) + + def create_menu(self): + menu = Gtk.Menu() + + instances = self.get_player_instances() + if instances: + for instance in instances: + instance_submenu = Gtk.Menu() + + play_item = Gtk.MenuItem(label="play-pause") + play_item.connect("activate", self.play_pause, instance) + instance_submenu.append(play_item) + + next_item = Gtk.MenuItem(label="next") + next_item.connect("activate", self.next_track, instance) + instance_submenu.append(next_item) + + prev_item = Gtk.MenuItem(label="previous") + prev_item.connect("activate", self.prev_track, instance) + instance_submenu.append(prev_item) + + instance_menu_item = Gtk.MenuItem(label=instance) + instance_menu_item.set_submenu(instance_submenu) + menu.append(instance_menu_item) + + a_submenu = Gtk.Menu() + + a_pause_item = Gtk.MenuItem(label="pause") + a_pause_item.connect("activate", self.a_pause) + a_submenu.append(a_pause_item) + + a_play_item = Gtk.MenuItem(label="play") + a_play_item.connect("activate", self.a_play) + a_submenu.append(a_play_item) + + a_next_item = Gtk.MenuItem(label="next") + a_next_item.connect("activate", self.a_next_track) + a_submenu.append(a_next_item) + + a_prev_item = Gtk.MenuItem(label="previous") + a_prev_item.connect("activate", self.a_prev_track) + a_submenu.append(a_prev_item) + + a_menu_item = Gtk.MenuItem(label="-a") + a_menu_item.set_submenu(a_submenu) + menu.append(a_menu_item) + else: + no_players_item = Gtk.MenuItem(label="no players found") + no_players_item.set_sensitive(False) # greyed out + menu.append(no_players_item) + + menu.append(Gtk.SeparatorMenuItem()) # separator + + quit_item = Gtk.MenuItem(label="quit") + quit_item.connect("activate", self.quit) + menu.append(quit_item) + + menu.show_all() + return menu + + def get_player_instances(self): + result = subprocess.run("playerctl -l", shell=True, capture_output=True, text=True) + return result.stdout.strip().split('\n') if result.stdout.strip() else [] + + def play_pause(self, _, instance): + self.run_command(f"playerctl -p {instance} play-pause") + + def next_track(self, _, instance): + self.run_command(f"playerctl -p {instance} next") + + def prev_track(self, _, instance): + self.run_command(f"playerctl -p {instance} previous") + + def a_play(self, _): + self.run_command("playerctl -a play") + + def a_pause(self, _): + self.run_command("playerctl -a pause") + + def a_next_track(self, _): + self.run_command("playerctl -a next") + + def a_prev_track(self, _): + self.run_command("playerctl -a previous") + + def run_command(self, command): + subprocess.run(command, shell=True) + + def quit(self, _): + Gtk.main_quit() + + def refresh_menu(self): + current_instances = self.get_player_instances() + if current_instances != self.last_instances: + self.indicator.set_menu(self.create_menu()) + self.last_instances = current_instances + return True # returns True so that timeout continues + +def main(): + app = playerctl_systray() + GLib.timeout_add(1024, app.refresh_menu) # probably should be event-based in the future + Gtk.main() + +if __name__ == "__main__": + main() diff --git a/.local/src/python-dateTimeSetter/Makefile b/.local/src/python-dateTimeSetter/Makefile deleted file mode 100644 index 91b1c6e..0000000 --- a/.local/src/python-dateTimeSetter/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -compile: - cython3 --embed -o dateTime.c -X language_level=3 dateTime.py - PYTHON_VERSION=`ls --sort version /usr/include | grep -o 'python[3-9]\+\.[0-9]\+' | tail -1` ; \ - gcc -march=native -O2 -pipe -fno-plt -I /usr/include/$$PYTHON_VERSION -o dateTime dateTime.c -l$$PYTHON_VERSION -lpthread -lm -lutil -ldl diff --git a/.local/src/python-dateTimeSetter/dateTime-GTK3.old.py b/.local/src/python-dateTimeSetter/dateTime-GTK3.old.py deleted file mode 100644 index 186c671..0000000 --- a/.local/src/python-dateTimeSetter/dateTime-GTK3.old.py +++ /dev/null @@ -1,87 +0,0 @@ -import gi -gi.require_version('Gtk', '3.0') -from gi.repository import Gtk, GLib -import subprocess - -class dateTimeSetter(Gtk.Window): - def __init__(self): - Gtk.Window.__init__(self, title="dateTimeSetter") - self.set_border_width(10) - self.set_default_size(400, 300) - - vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) - self.add(vbox) - - # Automatic time setting checkbox - automatic_time_label = Gtk.Label(label="Set the date, time, and timezone automatically?") - vbox.pack_start(automatic_time_label, False, False, 0) - - self.automatic_time_check = Gtk.CheckButton(label="Yes") - self.automatic_time_check.connect("toggled", self.on_automatic_time_toggled) - vbox.pack_start(self.automatic_time_check, False, False, 0) - - # Date and time entry fields - date_label = Gtk.Label(label="Enter the desired date (format: YYYY-MM-DD):") - vbox.pack_start(date_label, False, False, 0) - - self.date_entry = Gtk.Entry() - vbox.pack_start(self.date_entry, False, False, 0) - - time_label = Gtk.Label(label="Enter the desired time (format: HH:MM:SS):") - vbox.pack_start(time_label, False, False, 0) - - self.time_entry = Gtk.Entry() - vbox.pack_start(self.time_entry, False, False, 0) - - # Timezone entry field - timezone_label = Gtk.Label(label="Enter the desired timezone (e.g., America/New_York):") - vbox.pack_start(timezone_label, False, False, 0) - - self.timezone_entry = Gtk.Entry() - vbox.pack_start(self.timezone_entry, False, False, 0) - - # Apply button - apply_button = Gtk.Button(label="Apply") - apply_button.connect("clicked", self.on_apply_clicked) - vbox.pack_start(apply_button, False, False, 0) - - def on_automatic_time_toggled(self, button): - if button.get_active(): - self.date_entry.set_sensitive(False) - self.time_entry.set_sensitive(False) - self.timezone_entry.set_sensitive(False) - else: - self.date_entry.set_sensitive(True) - self.time_entry.set_sensitive(True) - self.timezone_entry.set_sensitive(True) - - def on_apply_clicked(self, button): - automatic_time = self.automatic_time_check.get_active() - - if automatic_time: - subprocess.run(["timedatectl", "set-ntp", "true"]) - print("Automatic time synchronization using NTP initiated.") - - automatic_timezone_output = subprocess.run(["curl", "--fail", "https://ipapi.co/timezone"], capture_output=True, text=True) - automatic_timezone = automatic_timezone_output.stdout.strip() - - if automatic_timezone: - subprocess.run(["timedatectl", "set-timezone", automatic_timezone]) - print("Automatic timezone setting complete.") - else: - print("Automatic timezone setting failed. Please set the timezone manually.") - else: - date_input = self.date_entry.get_text() - time_input = self.time_entry.get_text() - timezone_input = self.timezone_entry.get_text() - - subprocess.run(["timedatectl", "set-ntp", "false"]) - subprocess.run(["timedatectl", "set-time", f"{date_input} {time_input}"]) - subprocess.run(["timedatectl", "set-timezone", timezone_input]) - print("Manual date, time, and timezone setting complete.") - - -win = dateTimeSetter() -win.connect("destroy", Gtk.main_quit) -win.show_all() -Gtk.main() diff --git a/.local/src/python-dateTimeSetter/dateTime.py b/.local/src/python-dateTimeSetter/dateTime.py deleted file mode 100644 index 4d7ab5e..0000000 --- a/.local/src/python-dateTimeSetter/dateTime.py +++ /dev/null @@ -1,360 +0,0 @@ -import tkinter as tk -from tkinter import ttk, messagebox -import subprocess -import requests -import datetime -import pytz -import time - - -class DateTimeSetter(tk.Tk): - def __init__(self): - super().__init__() - - self.title("dateTimeSetter") - self.geometry("800x600") - self.resizable(True, True) - self.attributes("-type", "dialog") # make the window floating - - self.create_widgets() - self.populate_fields() - - def create_widgets(self): - # automatic time setting checkbox - automatic_time_label = ttk.Label( - self, text="Set the date, time, and timezone automatically?") - automatic_time_label.pack(pady=5) - - self.automatic_time_check = ttk.Checkbutton( - self, text="Yes", command=self.on_automatic_time_toggled) - self.automatic_time_check.pack(pady=5) - - # date entry fields - date_frame = ttk.LabelFrame(self, text="Date") - date_frame.pack(pady=10, padx=10, fill="x") - - ttk.Label(date_frame, text="YYYY:").grid( - row=0, column=0, padx=5, pady=5) - self.year_var = tk.StringVar() - self.year_combo = ttk.Combobox(date_frame, textvariable=self.year_var, values=[str( - year) for year in range(1970, 2039)], state="normal") - self.year_combo.grid(row=0, column=1, padx=5, pady=5) - - ttk.Label(date_frame, text="MM:").grid(row=0, column=2, padx=5, pady=5) - self.month_var = tk.StringVar() - self.month_combo = ttk.Combobox(date_frame, textvariable=self.month_var, values=[str( - month) for month in range(1, 13)], state="normal") - self.month_combo.grid(row=0, column=3, padx=5, pady=5) - - ttk.Label(date_frame, text="DD:").grid(row=0, column=4, padx=5, pady=5) - self.day_var = tk.StringVar() - self.day_combo = ttk.Combobox( - date_frame, textvariable=self.day_var, values=[str(day) for day in range(1, 32)], state="normal") - self.day_combo.grid(row=0, column=5, padx=5, pady=5) - - # time entry fields - time_frame = ttk.LabelFrame(self, text="Time (24hr)") - time_frame.pack(pady=10, padx=10, fill="x") - - ttk.Label(time_frame, text=" HH:").grid( - row=0, column=0, padx=5, pady=5) - self.hour_var = tk.StringVar() - self.hour_combo = ttk.Combobox(time_frame, textvariable=self.hour_var, values=[str( - hour) for hour in range(0, 24)], state="normal") - self.hour_combo.grid(row=0, column=1, padx=5, pady=5) - - ttk.Label(time_frame, text="MM:").grid(row=0, column=2, padx=5, pady=5) - self.minute_var = tk.StringVar() - self.minute_combo = ttk.Combobox(time_frame, textvariable=self.minute_var, values=[str( - minute) for minute in range(0, 60)], state="normal") - self.minute_combo.grid(row=0, column=3, padx=5, pady=5) - - ttk.Label(time_frame, text="SS:").grid(row=0, column=4, padx=5, pady=5) - self.second_var = tk.StringVar() - self.second_combo = ttk.Combobox(time_frame, textvariable=self.second_var, values=[str( - second) for second in range(0, 60)], state="normal") - self.second_combo.grid(row=0, column=5, padx=5, pady=5) - - # timezone entry field - timezone_frame = ttk.LabelFrame(self, text="Timezone") - timezone_frame.pack(pady=10, padx=10, fill="x") - - ttk.Label(timezone_frame, text="Timezone:").grid( - row=0, column=0, padx=5, pady=5) - self.timezone_var = tk.StringVar() - self.timezone_combo = ttk.Combobox( - timezone_frame, textvariable=self.timezone_var, values=pytz.all_timezones, state="normal") - self.timezone_combo.grid(row=0, column=1, padx=5, pady=5) - - # set-local-rtc checkbox - self.local_rtc_check = ttk.Checkbutton( - timezone_frame, text="Set local RTC") - self.local_rtc_check.grid( - row=1, column=0, columnspan=2, padx=5, pady=5) - - # apply button - button_frame = ttk.Frame(self) - button_frame.pack(pady=20) - - self.apply_button = ttk.Button( - button_frame, text="Apply All", command=self.on_apply_clicked) - self.apply_button.grid(row=0, column=0, padx=5) - - self.timezone_apply_button = ttk.Button( - button_frame, text="Apply Timezone", command=self.on_timezone_apply_clicked) - self.timezone_apply_button.grid(row=0, column=1, padx=5) - - self.date_time_apply_button = ttk.Button( - button_frame, text="Apply Date & Time", command=self.on_date_time_apply_clicked) - self.date_time_apply_button.grid(row=0, column=2, padx=5) - - self.local_rtc_apply_button = ttk.Button( - button_frame, text="Apply Local RTC", command=self.on_local_rtc_apply_clicked) - self.local_rtc_apply_button.grid(row=0, column=3, padx=5) - - self.update_apply_button_state() - - # Set trace on all variables to call update_apply_button_state when they change - self.year_var.trace_add("write", self.update_apply_button_state) - self.month_var.trace_add("write", self.update_apply_button_state) - self.day_var.trace_add("write", self.update_apply_button_state) - self.hour_var.trace_add("write", self.update_apply_button_state) - self.minute_var.trace_add("write", self.update_apply_button_state) - self.second_var.trace_add("write", self.update_apply_button_state) - self.timezone_var.trace_add("write", self.update_apply_button_state) - - def on_automatic_time_toggled(self): - if self.automatic_time_check.instate(['selected']): - self.year_combo.state(['disabled']) - self.month_combo.state(['disabled']) - self.day_combo.state(['disabled']) - self.hour_combo.state(['disabled']) - self.minute_combo.state(['disabled']) - self.second_combo.state(['disabled']) - self.timezone_combo.state(['disabled']) - else: - self.year_combo.state(['!disabled']) - self.month_combo.state(['!disabled']) - self.day_combo.state(['!disabled']) - self.hour_combo.state(['!disabled']) - self.minute_combo.state(['!disabled']) - self.second_combo.state(['!disabled']) - self.timezone_combo.state(['!disabled']) - self.update_apply_button_state() - - def update_apply_button_state(self, *_): - if self.automatic_time_check.instate(['selected']): - self.apply_button.state(['!disabled']) - self.timezone_apply_button.state(['disabled']) - self.date_time_apply_button.state(['disabled']) - self.local_rtc_apply_button.state(['disabled']) - else: - all_date_filled = all([ - self.year_combo.get(), - self.month_combo.get(), - self.day_combo.get(), - ]) - all_time_filled = all([ - self.hour_combo.get(), - self.minute_combo.get(), - self.second_combo.get(), - ]) - timezone_filled = self.timezone_combo.get() - all_filled = all_date_filled and all_time_filled and timezone_filled - - if all_filled: - self.apply_button.state(['!disabled']) - else: - self.apply_button.state(['disabled']) - - if timezone_filled and self.validate_timezone(timezone_filled): - self.timezone_apply_button.state(['!disabled']) - else: - self.timezone_apply_button.state(['disabled']) - - if all_date_filled and all_time_filled: - self.date_time_apply_button.state(['!disabled']) - else: - self.date_time_apply_button.state(['disabled']) - - self.local_rtc_apply_button.state(['!disabled']) - - def on_apply_clicked(self): - automatic_time = self.automatic_time_check.instate(['selected']) - local_rtc = self.local_rtc_check.instate(['selected']) - - if automatic_time: - subprocess.run(["timedatectl", "set-ntp", "true"]) - - try: - automatic_timezone_output = subprocess.run( - ["curl", "--fail", "https://ipinfo.io/timezone"], capture_output=True, text=True) - automatic_timezone = automatic_timezone_output.stdout.strip() - - if automatic_timezone: - subprocess.run( - ["timedatectl", "set-timezone", automatic_timezone]) - messagebox.showinfo( - "Info", "Automatic date, time, and timezone setting complete.") - else: - messagebox.showwarning( - "Warning", "Automatic date, time, and timezone setting failed. Please try again or use timedatectl.") - except requests.RequestException: - messagebox.showwarning( - "Warning", "Failed to fetch date, time, and timezone information. Please try again or use timedatectl.") - else: - try: - date_input = f"{self.year_combo.get()}-{int(self.month_combo.get()):02d}-{int(self.day_combo.get()):02d}" - time_input = f"{int(self.hour_combo.get()):02d}:{int(self.minute_combo.get()):02d}:{int(self.second_combo.get()):02d}" - timezone_input = self.timezone_combo.get() - - # check for invalid numbers in fields - if not all([ - self.validate_number(self.year_combo.get(), 1970, 2038), - self.validate_number(self.month_combo.get(), 1, 12), - self.validate_number(self.day_combo.get(), 1, 31), - self.validate_number(self.hour_combo.get(), 0, 23), - self.validate_number(self.minute_combo.get(), 0, 59), - self.validate_number(self.second_combo.get(), 0, 59), - self.validate_timezone(timezone_input) - ]): - messagebox.showerror( - "Error", "Invalid number entered in one or more fields.") - return - - subprocess.run(["timedatectl", "set-ntp", "false"]) - time.sleep(1) - subprocess.run(["timedatectl", "set-timezone", timezone_input]) - time.sleep(1) - subprocess.run(["timedatectl", "set-time", - f"{date_input} {time_input}"]) - messagebox.showinfo( - "Info", "Manual date, time, and timezone setting complete.") - except ValueError as e: - messagebox.showerror("Error", f"Error:\n{e}\n\nOne or more blank fields!") - - # handle local rtc setting - if local_rtc: - subprocess.run(["timedatectl", "set-local-rtc", "1"]) - else: - subprocess.run(["timedatectl", "set-local-rtc", "0"]) - - def on_timezone_apply_clicked(self): - timezone_input = self.timezone_combo.get() - - if not timezone_input or not self.validate_timezone(timezone_input): - messagebox.showerror("Error", "Invalid or empty timezone field.") - return - - try: - subprocess.run(["timedatectl", "set-timezone", timezone_input]) - messagebox.showinfo( - "Info", "Timezone setting complete.") - except subprocess.CalledProcessError as e: - messagebox.showerror("Error", f"Error setting timezone:\n{e}") - - def on_date_time_apply_clicked(self): - try: - date_input = f"{self.year_combo.get()}-{int(self.month_combo.get()):02d}-{int(self.day_combo.get()):02d}" - time_input = f"{int(self.hour_combo.get()):02d}:{int(self.minute_combo.get()):02d}:{int(self.second_combo.get()):02d}" - - # check for invalid numbers in fields - if not all([ - self.validate_number(self.year_combo.get(), 1970, 2038), - self.validate_number(self.month_combo.get(), 1, 12), - self.validate_number(self.day_combo.get(), 1, 31), - self.validate_number(self.hour_combo.get(), 0, 23), - self.validate_number(self.minute_combo.get(), 0, 59), - self.validate_number(self.second_combo.get(), 0, 59), - ]): - messagebox.showerror( - "Error", "Invalid number entered in one or more fields.") - return - - subprocess.run(["timedatectl", "set-ntp", "false"]) - time.sleep(1) - subprocess.run(["timedatectl", "set-time", f"{date_input} {time_input}"]) - messagebox.showinfo( - "Info", "Manual date and time setting complete.") - except ValueError as e: - messagebox.showerror("Error", f"Error:\n{e}\n\nOne or more blank fields!") - - def on_local_rtc_apply_clicked(self): - local_rtc = self.local_rtc_check.instate(['selected']) - - if local_rtc: - subprocess.run(["timedatectl", "set-local-rtc", "1"]) - messagebox.showinfo("Info", "Local RTC setting enabled.") - else: - subprocess.run(["timedatectl", "set-local-rtc", "0"]) - messagebox.showinfo("Info", "Local RTC setting disabled.") - - def validate_number(self, value, min_val, max_val): - try: - num = int(value) - return min_val <= num <= max_val - except ValueError: - return False - - def validate_timezone(self, timezone): - return timezone in pytz.all_timezones - - def populate_fields(self): - now = datetime.datetime.now() - self.year_combo.set(now.year) - self.month_combo.set(now.month) - self.day_combo.set(now.day) - self.hour_combo.set(now.hour) - self.minute_combo.set(now.minute) - self.second_combo.set(now.second) - - try: - current_timezone = subprocess.check_output( - ["timedatectl", "show", "--property=Timezone"]).decode().strip().split("=")[1] - self.timezone_combo.set(current_timezone) - except subprocess.CalledProcessError: - pass - - try: - ntp_status = subprocess.check_output( - ["timedatectl", "show", "--property=NTP"]).decode().strip().split("=")[1] - if ntp_status == "yes": - self.automatic_time_check.state(['selected']) - self.on_automatic_time_toggled() - else: - self.automatic_time_check.state(['!selected']) - self.on_automatic_time_toggled() - except subprocess.CalledProcessError: - pass - - try: - local_rtc_status = subprocess.check_output( - ["timedatectl", "show", "--property=LocalRTC"]).decode().strip().split("=")[1] - if local_rtc_status == "yes": - self.local_rtc_check.state(['selected']) - else: - self.local_rtc_check.state(['!selected']) - except subprocess.CalledProcessError: - pass - - self.year_combo.bind("<>", - self.update_apply_button_state) - self.month_combo.bind("<>", - self.update_apply_button_state) - self.day_combo.bind("<>", - self.update_apply_button_state) - self.hour_combo.bind("<>", - self.update_apply_button_state) - self.minute_combo.bind("<>", - self.update_apply_button_state) - self.second_combo.bind("<>", - self.update_apply_button_state) - self.timezone_combo.bind( - "<>", self.update_apply_button_state) - self.timezone_combo.bind( - "", self.update_apply_button_state) - - -if __name__ == "__main__": - app = DateTimeSetter() - app.mainloop() diff --git a/.local/src/python-playerctl_systray/Makefile b/.local/src/python-playerctl_systray/Makefile deleted file mode 100644 index a0ab881..0000000 --- a/.local/src/python-playerctl_systray/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -compile: - cython3 --embed -o playerctl_systray.c -X language_level=3 playerctl_systray.py - PYTHON_VERSION=`ls --sort version /usr/include | grep -o 'python[3-9]\+\.[0-9]\+' | tail -1` ; \ - gcc -march=native -O2 -pipe -fno-plt -I /usr/include/$$PYTHON_VERSION -o playerctl_systray playerctl_systray.c -l$$PYTHON_VERSION -lpthread -lm -lutil -ldl `pkg-config --cflags --libs gtk+-3.0 appindicator3-0.1 dbus-1 dbus-glib-1` diff --git a/.local/src/python-playerctl_systray/playerctl_systray.py b/.local/src/python-playerctl_systray/playerctl_systray.py deleted file mode 100644 index 79a4c0c..0000000 --- a/.local/src/python-playerctl_systray/playerctl_systray.py +++ /dev/null @@ -1,123 +0,0 @@ -import gi -import subprocess - -gi.require_version('Gtk', '3.0') -gi.require_version('AppIndicator3', '0.1') -gi.require_version('GLib', '2.0') -from gi.repository import Gtk, AppIndicator3, GLib - -class playerctl_systray: - def __init__(self): - self.last_instances = self.get_player_instances() - self.indicator = AppIndicator3.Indicator.new( - "media-control-app", - "audio-x-generic", - AppIndicator3.IndicatorCategory.APPLICATION_STATUS - ) - self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE) - self.indicator.set_menu(self.create_menu()) - - def create_menu(self): - menu = Gtk.Menu() - - instances = self.get_player_instances() - if instances: - for instance in instances: - instance_submenu = Gtk.Menu() - - play_item = Gtk.MenuItem(label="play-pause") - play_item.connect("activate", self.play_pause, instance) - instance_submenu.append(play_item) - - next_item = Gtk.MenuItem(label="next") - next_item.connect("activate", self.next_track, instance) - instance_submenu.append(next_item) - - prev_item = Gtk.MenuItem(label="previous") - prev_item.connect("activate", self.prev_track, instance) - instance_submenu.append(prev_item) - - instance_menu_item = Gtk.MenuItem(label=instance) - instance_menu_item.set_submenu(instance_submenu) - menu.append(instance_menu_item) - - a_submenu = Gtk.Menu() - - a_pause_item = Gtk.MenuItem(label="pause") - a_pause_item.connect("activate", self.a_pause) - a_submenu.append(a_pause_item) - - a_play_item = Gtk.MenuItem(label="play") - a_play_item.connect("activate", self.a_play) - a_submenu.append(a_play_item) - - a_next_item = Gtk.MenuItem(label="next") - a_next_item.connect("activate", self.a_next_track) - a_submenu.append(a_next_item) - - a_prev_item = Gtk.MenuItem(label="previous") - a_prev_item.connect("activate", self.a_prev_track) - a_submenu.append(a_prev_item) - - a_menu_item = Gtk.MenuItem(label="-a") - a_menu_item.set_submenu(a_submenu) - menu.append(a_menu_item) - else: - no_players_item = Gtk.MenuItem(label="no players found") - no_players_item.set_sensitive(False) # greyed out - menu.append(no_players_item) - - menu.append(Gtk.SeparatorMenuItem()) # separator - - quit_item = Gtk.MenuItem(label="quit") - quit_item.connect("activate", self.quit) - menu.append(quit_item) - - menu.show_all() - return menu - - def get_player_instances(self): - result = subprocess.run("playerctl -l", shell=True, capture_output=True, text=True) - return result.stdout.strip().split('\n') if result.stdout.strip() else [] - - def play_pause(self, _, instance): - self.run_command(f"playerctl -p {instance} play-pause") - - def next_track(self, _, instance): - self.run_command(f"playerctl -p {instance} next") - - def prev_track(self, _, instance): - self.run_command(f"playerctl -p {instance} previous") - - def a_play(self, _): - self.run_command("playerctl -a play") - - def a_pause(self, _): - self.run_command("playerctl -a pause") - - def a_next_track(self, _): - self.run_command("playerctl -a next") - - def a_prev_track(self, _): - self.run_command("playerctl -a previous") - - def run_command(self, command): - subprocess.run(command, shell=True) - - def quit(self, _): - Gtk.main_quit() - - def refresh_menu(self): - current_instances = self.get_player_instances() - if current_instances != self.last_instances: - self.indicator.set_menu(self.create_menu()) - self.last_instances = current_instances - return True # returns True so that timeout continues - -def main(): - app = playerctl_systray() - GLib.timeout_add(1024, app.refresh_menu) # probably should be event-based in the future - Gtk.main() - -if __name__ == "__main__": - main() diff --git a/.local/src/python-rainfall/Makefile b/.local/src/python-rainfall/Makefile deleted file mode 100644 index c7cdd98..0000000 --- a/.local/src/python-rainfall/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -compile: - cython3 --embed -o rainfall.c -X language_level=3 rainfall.py - PYTHON_VERSION=`ls --sort version /usr/include | grep -o 'python[3-9]\+\.[0-9]\+' | tail -1` ; \ - gcc -march=native -O2 -pipe -fno-plt -I /usr/include/$$PYTHON_VERSION -o rainfall rainfall.c -l$$PYTHON_VERSION -lpthread -lm -lutil -ldl diff --git a/.local/src/python-rainfall/rainfall.py b/.local/src/python-rainfall/rainfall.py deleted file mode 100644 index 9175022..0000000 --- a/.local/src/python-rainfall/rainfall.py +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import time -import random -import os -import sys - - -colors = { - "black": "\u001b[30m", - "red": "\u001b[31m", - "green": "\u001b[32m", - "yellow": "\u001b[33m", - "blue": "\u001b[34m", - "magenta": "\u001b[35m", - "cyan": "\u001b[36m", - "white": "\u001b[37m", - "reset": "\u001b[0m", - - "b_black": "\u001b[30;1m", - "b_red": "\u001b[31;1m", - "b_green": "\u001b[32;1m", - "b_yellow": "\u001b[33;1m", - "b_blue": "\u001b[34;1m", - "b_magenta": "\u001b[35;1m", - "b_cyan": "\u001b[36;1m", - "b_white": "\u001b[37;1m", - - "Reset": "\u001b[0m", -} - -def Colored(string, color): - return string if "-m" in sys.argv else ( colors[color] + string + colors["Reset"]) - - -def Clear_Screen(): - print("\033[2J") # erase saved lines - print("\033[3J") # erase entire screen - print("\033[H") # moves cursor to home position - - -def Get_Arguments(): - args_dict = {"colors": []} - if sys.argv: - for arg in sys.argv: - if "-i=" in arg: - args_dict["intensity"] = int(arg.split("-i=")[1]) - if "-t=" in arg: - args_dict["timing"] = float(arg.split("-t=")[1]) - if arg in colors: - args_dict["colors"].append(arg) - if not args_dict["colors"]: - del args_dict["colors"] - return args_dict - - -def New_Drop(): - for i in range(intensity): - shape = random.choice(DROPSHAPES) - color = random.choice(drop_colors) - - raindrop = { - "shape": Colored(shape, color), - "x": random.randint(0, xmax), - "y": 0, - } - rainfall.append(raindrop) - -def Rain(): - ## iterate over every line - for i in range(ymax): - line = " "*xmax - - ### to avoid splicing of ansi codes, splice in the drops from the end of the line - this_line_raindrops = [raindrop for raindrop in rainfall if raindrop["y"] == i] - this_line_raindrops.sort(key=lambda y: y["x"]) - this_line_raindrops.reverse() - - ## insert new drops and shift existing drops - for raindrop in this_line_raindrops: - x = raindrop["x"] - line = line[:x] + raindrop["shape"] +line[x:] - - print(line) - - ### update raindrop positions - for raindrop in rainfall: - raindrop["y"] += 1 - - ## once a raindrop reaches the ground, they splash - if raindrop["y"] > ymax-2: - raindrop["shape"] = Colored("o", random.choice(drop_colors)) - - # raindrops outside the window evaporate - if raindrop["y"] > ymax: - rainfall.remove(raindrop) - - New_Drop() - - - -def Weather_Forecast(): - global weather - global intensity - - weather += 1 - if weather == 100: - weather = 0 - intensity += random.choice([-1,1]) - if intensity < 1: - intensity = 1 - if intensity > 10: - intensity = 10 - - -size = os.get_terminal_size() -xmax = size.columns -ymax = int(size.lines) - -weather = 0 -rainfall = [] -DROPSHAPES =["|", "│", "┃", "╽", "╿", "║", "┆", "┇", "┊", "┋", "╵", "╹", "╻"] - -args = Get_Arguments() -intensity = args.get("intensity", 1) -timing = args.get("timing", 0.08) -drop_colors = args.get("colors", ["blue", "b_blue"]) - - - -print('\033[?25l', end="") ## hides the cursor -New_Drop() - -try: - while True: - Rain() - time.sleep(timing) - Clear_Screen() - Weather_Forecast() - -except KeyboardInterrupt: - Clear_Screen() - print('\033[?25h', end="") # makes cursor visible again - - - - - - - - - - - - - - - - - diff --git a/.local/src/rainfall/LICENSE b/.local/src/rainfall/LICENSE new file mode 100644 index 0000000..4344f2d --- /dev/null +++ b/.local/src/rainfall/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 alpin111 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.local/src/rainfall/Makefile b/.local/src/rainfall/Makefile new file mode 100644 index 0000000..c7cdd98 --- /dev/null +++ b/.local/src/rainfall/Makefile @@ -0,0 +1,4 @@ +compile: + cython3 --embed -o rainfall.c -X language_level=3 rainfall.py + PYTHON_VERSION=`ls --sort version /usr/include | grep -o 'python[3-9]\+\.[0-9]\+' | tail -1` ; \ + gcc -march=native -O2 -pipe -fno-plt -I /usr/include/$$PYTHON_VERSION -o rainfall rainfall.c -l$$PYTHON_VERSION -lpthread -lm -lutil -ldl diff --git a/.local/src/rainfall/rainfall.py b/.local/src/rainfall/rainfall.py new file mode 100644 index 0000000..9175022 --- /dev/null +++ b/.local/src/rainfall/rainfall.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import time +import random +import os +import sys + + +colors = { + "black": "\u001b[30m", + "red": "\u001b[31m", + "green": "\u001b[32m", + "yellow": "\u001b[33m", + "blue": "\u001b[34m", + "magenta": "\u001b[35m", + "cyan": "\u001b[36m", + "white": "\u001b[37m", + "reset": "\u001b[0m", + + "b_black": "\u001b[30;1m", + "b_red": "\u001b[31;1m", + "b_green": "\u001b[32;1m", + "b_yellow": "\u001b[33;1m", + "b_blue": "\u001b[34;1m", + "b_magenta": "\u001b[35;1m", + "b_cyan": "\u001b[36;1m", + "b_white": "\u001b[37;1m", + + "Reset": "\u001b[0m", +} + +def Colored(string, color): + return string if "-m" in sys.argv else ( colors[color] + string + colors["Reset"]) + + +def Clear_Screen(): + print("\033[2J") # erase saved lines + print("\033[3J") # erase entire screen + print("\033[H") # moves cursor to home position + + +def Get_Arguments(): + args_dict = {"colors": []} + if sys.argv: + for arg in sys.argv: + if "-i=" in arg: + args_dict["intensity"] = int(arg.split("-i=")[1]) + if "-t=" in arg: + args_dict["timing"] = float(arg.split("-t=")[1]) + if arg in colors: + args_dict["colors"].append(arg) + if not args_dict["colors"]: + del args_dict["colors"] + return args_dict + + +def New_Drop(): + for i in range(intensity): + shape = random.choice(DROPSHAPES) + color = random.choice(drop_colors) + + raindrop = { + "shape": Colored(shape, color), + "x": random.randint(0, xmax), + "y": 0, + } + rainfall.append(raindrop) + +def Rain(): + ## iterate over every line + for i in range(ymax): + line = " "*xmax + + ### to avoid splicing of ansi codes, splice in the drops from the end of the line + this_line_raindrops = [raindrop for raindrop in rainfall if raindrop["y"] == i] + this_line_raindrops.sort(key=lambda y: y["x"]) + this_line_raindrops.reverse() + + ## insert new drops and shift existing drops + for raindrop in this_line_raindrops: + x = raindrop["x"] + line = line[:x] + raindrop["shape"] +line[x:] + + print(line) + + ### update raindrop positions + for raindrop in rainfall: + raindrop["y"] += 1 + + ## once a raindrop reaches the ground, they splash + if raindrop["y"] > ymax-2: + raindrop["shape"] = Colored("o", random.choice(drop_colors)) + + # raindrops outside the window evaporate + if raindrop["y"] > ymax: + rainfall.remove(raindrop) + + New_Drop() + + + +def Weather_Forecast(): + global weather + global intensity + + weather += 1 + if weather == 100: + weather = 0 + intensity += random.choice([-1,1]) + if intensity < 1: + intensity = 1 + if intensity > 10: + intensity = 10 + + +size = os.get_terminal_size() +xmax = size.columns +ymax = int(size.lines) + +weather = 0 +rainfall = [] +DROPSHAPES =["|", "│", "┃", "╽", "╿", "║", "┆", "┇", "┊", "┋", "╵", "╹", "╻"] + +args = Get_Arguments() +intensity = args.get("intensity", 1) +timing = args.get("timing", 0.08) +drop_colors = args.get("colors", ["blue", "b_blue"]) + + + +print('\033[?25l', end="") ## hides the cursor +New_Drop() + +try: + while True: + Rain() + time.sleep(timing) + Clear_Screen() + Weather_Forecast() + +except KeyboardInterrupt: + Clear_Screen() + print('\033[?25h', end="") # makes cursor visible again + + + + + + + + + + + + + + + + + -- cgit v1.2.3