This commit is contained in:
ciomek committed 2025-08-09 14:41:44 +02:00
1 parent b57943ee4b
commit d23df8df84
25 files changed
+463 -159

No files matched your search

+1
View File
@@ -0,0 +1 @@
__pycache__/
+107 -81
View File
@@ -1,115 +1,141 @@
#!/bin/sh
set -e
ORIG_PWD=$(pwd)
# Elevate to root if needed
# === Colors ===
RED="\033[1;31m"
GREEN="\033[1;32m"
YELLOW="\033[1;33m"
BLUE="\033[1;34m"
MAGENTA="\033[1;35m"
CYAN="\033[1;36m"
RESET="\033[0m"
log_info() { printf "${CYAN}[*]${RESET} %s\n" "$1"; }
log_success() { printf "${GREEN}[✓]${RESET} %s\n" "$1"; }
log_warn() { printf "${YELLOW}[!]${RESET} %s\n" "$1"; }
log_error() { printf "${RED}[✗]${RESET} %s\n" "$1"; }
ORIG_PWD=$(pwd)
ORIG_USER=$(logname)
ORIG_HOME=$(getent passwd "$ORIG_USER" | cut -d: -f6)
# === Elevate to root if needed ===
if [ "$(id -u)" -ne 0 ]; then
exec sudo "$0" "$@"
fi
ORIG_USER=$(logname)
ORIG_HOME=$(getent passwd "$ORIG_USER" | cut -d: -f6)
# === Update system ===
echo "Updating system..."
pacman -Syu --noconfirm
# === Essential tools ===
# === Package groups ===
ESSENTIAL_PACKAGES="
python3
vim
neovim
ranger
firefox
base-devel python3 vim neovim ranger firefox
"
# === Display manager ===
DISPLAY_MANAGER="
sddm
sddm qt5-graphicaleffects
"
# === Wayland & Hyprland environment ===
WAYLAND_ENVIRONMENT="
hyprland
hyprpaper
waybar
kitty
wofi
mako
libnotify
grim
slurp
wl-clipboard
wayland-utils
xorg-xwayland
hyprland hyprpaper waybar kitty wofi mako libnotify grim slurp
wl-clipboard wl-clip-persist wayland-utils xorg-xwayland
"
# === Audio ===
AUDIO_PACKAGES="
pipewire
wireplumber
pipewire-pulse
pavucontrol
pipewire wireplumber pipewire-pulse pavucontrol
"
# === Fonts & theming ===
FONTS_AND_THEME="
otf-font-awesome
noto-fonts
noto-fonts-cjk
ttf-jetbrains-mono
orchis-theme
otf-font-awesome noto-fonts noto-fonts-cjk ttf-jetbrains-mono orchis-theme
"
# === Multimedia ===
MEDIA_PACKAGES="
mpv
eog
ffmpeg
mpv eog ffmpeg
"
# === Install all packages ===
echo "Installing packages..."
pacman -S --noconfirm --needed \
$ESSENTIAL_PACKAGES \
$DISPLAY_MANAGER \
$WAYLAND_ENVIRONMENT \
$AUDIO_PACKAGES \
$FONTS_AND_THEME \
$MEDIA_PACKAGES
# === Functions ===
update_system() {
log_info "Updating system..."
pacman -Syu --noconfirm
}
# === Enable display manager ===
echo "Enabling SDDM..."
systemctl enable sddm
# === Apply GTK settings for theme and color scheme ===
echo "Applying GTK settings..."
install_packages() {
log_info "Installing packages..."
pacman -S --noconfirm --needed \
$ESSENTIAL_PACKAGES \
$DISPLAY_MANAGER \
$WAYLAND_ENVIRONMENT \
$AUDIO_PACKAGES \
$FONTS_AND_THEME \
$MEDIA_PACKAGES
}
# Extract DBus address from the user's environment
USER_DBUS_ENV=$(sudo -u "$ORIG_USER" -- dbus-launch)
eval "$USER_DBUS_ENV"
apply_gtk_settings() {
log_info "Applying GTK settings..."
export XDG_RUNTIME_DIR="/run/user/$(id -u "$ORIG_USER")"
DBUS_ADDR="unix:path=${XDG_RUNTIME_DIR}/bus"
export DBUS_SESSION_BUS_ADDRESS
export XDG_RUNTIME_DIR="/run/user/$(id -u $ORIG_USER)"
for setting in \
"org.gnome.desktop.interface gtk-theme Orchis-Dark-Compact" \
"org.gnome.desktop.interface icon-theme Orchis-Dark-Compact" \
"org.gnome.desktop.interface color-scheme prefer-dark"
do
if sudo -u "$ORIG_USER" \
DBUS_SESSION_BUS_ADDRESS="$DBUS_ADDR" \
gsettings set $setting; then
log_success "Set $setting"
else
log_warn "Failed to set $setting"
fi
done
}
sudo -u "$ORIG_USER" DBUS_SESSION_BUS_ADDRESS="$DBUS_SESSION_BUS_ADDRESS" \
XDG_RUNTIME_DIR="$XDG_RUNTIME_DIR" \
gsettings set org.gnome.desktop.interface gtk-theme "Orchis-Dark-Compact"
enable_sddm() {
log_info "Enabling SDDM..."
systemctl enable sddm
}
sudo -u "$ORIG_USER" DBUS_SESSION_BUS_ADDRESS="$DBUS_SESSION_BUS_ADDRESS" \
XDG_RUNTIME_DIR="$XDG_RUNTIME_DIR" \
gsettings set org.gnome.desktop.interface icon-theme "Orchis-Dark-Compact"
install_sddm_theme() {
log_info "Installing SDDM theme..."
if pacman -Q where-is-my-sddm-theme-git >/dev/null 2>&1; then
log_success "SDDM theme already installed."
return
fi
sudo -u "$ORIG_USER" DBUS_SESSION_BUS_ADDRESS="$DBUS_SESSION_BUS_ADDRESS" \
XDG_RUNTIME_DIR="$XDG_RUNTIME_DIR" \
gsettings set org.gnome.desktop.interface color-scheme "prefer-dark"
sudo -u "$ORIG_USER" mkdir -p "$ORIG_HOME/Repositories"
cd "$ORIG_HOME/Repositories"
echo "GTK settings applied successfully."
if [ ! -d "where-is-my-sddm-theme" ]; then
sudo -u "$ORIG_USER" git clone https://aur.archlinux.org/where-is-my-sddm-theme-git.git where-is-my-sddm-theme
else
log_warn "Theme repo already exists, skipping clone."
fi
# === Run dotfiles setup ===
echo "Running dotfiles setup as $ORIG_USER..."
cd "$ORIG_PWD" || exit 1
sudo -u "$ORIG_USER" HOME="$ORIG_HOME" python3 setup.py
sudo -E -u "$ORIG_USER" HOME="$ORIG_HOME" mkdir -p "$ORIG_HOME/Downloads" "$ORIG_HOME/Documents" "$ORIG_HOME/Pictures" "$ORIG_HOME/Videos" "$ORIG_HOME/Repositories"
cd "$ORIG_HOME/Repositories/where-is-my-sddm-theme"
sudo -u "$ORIG_USER" makepkg -si --noconfirm
}
echo "Dotfiles installed successfully."
run_dotfiles_setup() {
log_info "Running dotfiles setup..."
cd "$ORIG_PWD"
[ -f "setup_user.py" ] && sudo -u "$ORIG_USER" HOME="$ORIG_HOME" python3 setup_user.py \
|| log_warn "setup_user.py not found."
[ -f "setup_system.py" ] && python3 setup_system.py \
|| log_warn "setup_system.py not found."
sudo -u "$ORIG_USER" mkdir -p \
"$ORIG_HOME/Downloads" \
"$ORIG_HOME/Documents" \
"$ORIG_HOME/Pictures" \
"$ORIG_HOME/Videos" \
"$ORIG_HOME/Repositories"
}
# === Main flow ===
update_system
install_packages
apply_gtk_settings
enable_sddm
install_sddm_theme
run_dotfiles_setup
log_success "Setup completed successfully."
View File
File renamed without changes.
File renamed without changes.
@@ -24,7 +24,7 @@ $screenshot = grim -g "$(slurp -d)" - | wl-copy
#################
# Autostart necessary processes (like notifications daemons, status bars, etc.)
exec-once=waybar & hyprpaper
exec-once=waybar & hyprpaper & wl-clip-persist --clipboard both & mako
# & mako --config=$HOME/.config/mako/config
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
View File
File renamed without changes.
+25
View File
@@ -0,0 +1,25 @@
<!DOCTYPE NETSCAPE-Bookmark-file-1>
<!-- This is an automatically generated file.
It will be read and overwritten.
DO NOT EDIT! -->
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'none'; img-src data: *; object-src 'none'"></meta>
<TITLE>Bookmarks</TITLE>
<H1>Bookmarks Menu</H1>
<DL><p>
<DT><H3 ADD_DATE="1754672030" LAST_MODIFIED="1754672030">Mozilla Firefox</H3>
<DL><p>
<DT><A HREF="https://support.mozilla.org/products/firefox" ADD_DATE="1754672030" LAST_MODIFIED="1754672030" ICON_URI="fake-favicon-uri:https://support.mozilla.org/products/firefox" ICON="data:image/png;base64,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">Get Help</A>
<DT><A HREF="https://support.mozilla.org/kb/customize-firefox-controls-buttons-and-toolbars?utm_source=firefox-browser&utm_medium=default-bookmarks&utm_campaign=customize" ADD_DATE="1754672030" LAST_MODIFIED="1754672030" ICON_URI="fake-favicon-uri:https://support.mozilla.org/kb/customize-firefox-controls-buttons-and-toolbars?utm_source=firefox-browser&utm_medium=default-bookmarks&utm_campaign=customize" ICON="data:image/png;base64,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">Customize Firefox</A>
<DT><A HREF="https://www.mozilla.org/contribute/" ADD_DATE="1754672030" LAST_MODIFIED="1754672030" ICON_URI="fake-favicon-uri:https://www.mozilla.org/contribute/" ICON="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxNicgaGVpZ2h0PScxNic+IDxwYXRoIGQ9J00wIDBoMTZ2MTZIMHonLz4gPHBhdGggZD0nTTEzLjk5NCAxMC4zNTZIMTVWMTJoLTMuMTcxVjcuNzQxYzAtMS4zMDgtLjQzNS0xLjgxLTEuMjktMS44MS0xLjA0IDAtMS40Ni43MzctMS40NiAxLjh2Mi42M2gxLjAwNlYxMkg2LjkxOFY3Ljc0MWMwLTEuMzA4LS40MzUtMS44MS0xLjI5MS0xLjgxLTEuMDM5IDAtMS40NTkuNzM3LTEuNDU5IDEuOHYyLjYzaDEuNDQxVjEySDF2LTEuNjQ0aDEuMDA2VjYuMDc5SDFWNC40MzVoMy4xNjh2MS4xMzlhMi41MDcgMi41MDcgMCAwIDEgMi4zLTEuMjlBMi40NTIgMi40NTIgMCAwIDEgOC45MzEgNS45MSAyLjUzNSAyLjUzNSAwIDAgMSAxMS40IDQuMjg0IDIuNDQ4IDIuNDQ4IDAgMCAxIDE0IDYuOXYzLjQ1OHonIGZpbGw9JyNmZmYnLz4gPC9zdmc+">Get Involved</A>
<DT><A HREF="https://www.mozilla.org/about/" ADD_DATE="1754672030" LAST_MODIFIED="1754672030" ICON_URI="fake-favicon-uri:https://www.mozilla.org/about/" ICON="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxNicgaGVpZ2h0PScxNic+IDxwYXRoIGQ9J00wIDBoMTZ2MTZIMHonLz4gPHBhdGggZD0nTTEzLjk5NCAxMC4zNTZIMTVWMTJoLTMuMTcxVjcuNzQxYzAtMS4zMDgtLjQzNS0xLjgxLTEuMjktMS44MS0xLjA0IDAtMS40Ni43MzctMS40NiAxLjh2Mi42M2gxLjAwNlYxMkg2LjkxOFY3Ljc0MWMwLTEuMzA4LS40MzUtMS44MS0xLjI5MS0xLjgxLTEuMDM5IDAtMS40NTkuNzM3LTEuNDU5IDEuOHYyLjYzaDEuNDQxVjEySDF2LTEuNjQ0aDEuMDA2VjYuMDc5SDFWNC40MzVoMy4xNjh2MS4xMzlhMi41MDcgMi41MDcgMCAwIDEgMi4zLTEuMjlBMi40NTIgMi40NTIgMCAwIDEgOC45MzEgNS45MSAyLjUzNSAyLjUzNSAwIDAgMSAxMS40IDQuMjg0IDIuNDQ4IDIuNDQ4IDAgMCAxIDE0IDYuOXYzLjQ1OHonIGZpbGw9JyNmZmYnLz4gPC9zdmc+">About Us</A>
</DL><p>
<DT><H3 ADD_DATE="1754672030" LAST_MODIFIED="1754737301" PERSONAL_TOOLBAR_FOLDER="true">Bookmarks Toolbar</H3>
<DL><p>
<DT><A HREF="https://app.tuta.com/mail" ADD_DATE="1754737203" LAST_MODIFIED="1754737301" ICON_URI="https://app.tuta.com/images/logo-favicon-192.png" ICON="data:image/png;base64,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 truncated
<DT><A HREF="https://www.youtube.com/" ADD_DATE="1754676928" LAST_MODIFIED="1754676928" ICON_URI="https://www.youtube.com/s/desktop/3ad23781/img/logos/favicon.ico" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAqklEQVQ4T2NkoBAwUqifAW7AfwYGAaBhBlADHXAYfAAqfgGo8QOIDTYAqDmBgcF4PmmuOZsI1LyAEagZaKvxedI0w1SfNQQZEAA0YD2ZBiSCDGgAGlCP1YAHa4GeA/ruwGcc5p9txG/A/zMQjRs3At3ZjMUQYg04eJCBwaGYDANAXigoYGDY8BivFygORMqikeKEBPMcWlIGJWlQ0kYH2JMyeYkIoovi3AgApww7KRWVvS0AAAAASUVORK5CYII="></A>
<DT><A HREF="https://www.facebook.com/messages" ADD_DATE="1754737292" LAST_MODIFIED="1754737292" ICON_URI="https://static.xx.fbcdn.net/rsrc.php/y1/r/ay1hV6OlegS.ico" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABr0lEQVQ4T41TTS8DURQ9t0Snw6LxlVQkamOJLQshFlbCqivCqu2iiYofYCRsGRufGws/ALWxqthYGjtWRiSaSCSV0CLV590+U9NR5SWTmbn3nXPPO/c+gmc1JcSwKGDyQ2ACAmFO+wCr6IOlaVjKmmS7IeT8hA0RzGSwSAJJL6n7XxDMUABLtklZjpcIGPxwj3QR6K8FdnKsqF3HCJOUCPwxsVatcmIU4KerRUFTFhDZVN+s5G2b5imYFOHXHG68lacGgN3ZyujZNTC2+h2rb8AI6VGxJ6XPeAlOFoChHhU9kpW5+lNevZ1VR1gnf1RcyHP8OPvVipTeqraG5oFsroo7BJu0qBDVjHMTBGK/W/uDYEceZnqwOmA5BawcV+ZIi4kbZ2A4VYsgsiE9uPwmkNItki00ZQvnnPC4dKO3U7UvqKsoV+a1fw7cProU+LBHTXExXCgi7RX9Hw80Hd3OIFWoYLK/CLiFL9uUVHchKYL+HNLudtYiKI1yhxxl42uUyyR5GI4fvxFw5bYQDAYzrnwbHQ94tN9zMO5W0dfcqAYsEIctgYdy88HzFp26/foEPRCR1pBdDIQAAAAASUVORK5CYII="></A>
</DL><p>
</DL>
File renamed without changes.
-77
View File
@@ -1,77 +0,0 @@
import os
import shutil
SRC_DIR = "src"
HOME_DIR = os.path.expanduser("~")
CHOICES = {
'.config/hypr/monitors.conf': ['.config/hypr/monitors-1.conf', '.config/hypr/monitors-2.conf']
}
def ask_override(path):
resp = input(f"'{path}' already exists. Override? (Y/N): ").strip().lower()
return resp == 'y'
def choice_files(src_root, dst_root, choices_map, override_all=False):
for final_name, options in choices_map.items():
existing_options = [f for f in options if os.path.exists(os.path.join(src_root, f))]
if not existing_options:
print(f"No source file found among options for {final_name}. Skipping.")
continue
if len(existing_options) == 1:
chosen = existing_options[0]
else:
print(f"Choose which file to copy as '{final_name}':")
for idx, opt in enumerate(existing_options, 1):
print(f"{idx}: {opt}")
while True:
try:
choice_idx = int(input(f"Enter number (1-{len(existing_options)}): "))
if 1 <= choice_idx <= len(existing_options):
chosen = existing_options[choice_idx - 1]
break
except ValueError:
pass
print("Invalid choice, try again.")
src_file = os.path.join(src_root, chosen)
dst_file = os.path.join(dst_root, final_name)
if os.path.exists(dst_file):
if not override_all and not ask_override(dst_file):
print(f"Skipped overriding {dst_file}")
continue
shutil.copy2(src_file, dst_file)
print(f"Copied {chosen} -> {final_name}")
def copy_with_structure(src_root, dst_root, override_all=False):
for root, dirs, files in os.walk(src_root):
rel_path = os.path.relpath(root, src_root)
target_dir = os.path.join(dst_root, rel_path)
os.makedirs(target_dir, exist_ok=True)
for file in files:
src_file = os.path.join(root, file)
dst_file = os.path.join(target_dir, file)
if os.path.exists(dst_file):
if not override_all and not ask_override(dst_file):
continue
shutil.copy2(src_file, dst_file)
print(f"Copied: {src_file} -> {dst_file}")
def main():
override_all = input('Override all existing files? (Y/N): ').strip().lower() == 'y'
choice_files(SRC_DIR, HOME_DIR, CHOICES, override_all)
copy_with_structure(SRC_DIR, HOME_DIR, override_all)
if __name__ == '__main__':
main()
+17
View File
@@ -0,0 +1,17 @@
import sys
from utils import choice_files, copy_with_structure, require_root, log_info, log_error, CYAN, RESET
SRC_DIR = "system_files"
DST_DIR = "/"
CHOICES = {}
def main():
require_root()
override_all = input(f"{CYAN}Override all existing system files? (Y/N): {RESET}").strip().lower() == 'y'
choice_files(SRC_DIR, DST_DIR, CHOICES, override_all)
copy_with_structure(SRC_DIR, DST_DIR, override_all)
if __name__ == '__main__':
main()
+22
View File
@@ -0,0 +1,22 @@
import os
from utils import choice_files, copy_with_structure, CYAN, RESET
SRC_DIR = "home"
HOME_DIR = os.path.expanduser("~")
CHOICES = {
'.config/hypr/monitors.conf': [
'.config/hypr/monitors-1.conf',
'.config/hypr/monitors-2.conf'
]
}
def main():
override_all = input(f"{CYAN}Override all existing files for user (mainly .config)? (Y/N): {RESET}").strip().lower() == 'y'
choice_files(SRC_DIR, HOME_DIR, CHOICES, override_all)
copy_with_structure(SRC_DIR, HOME_DIR, override_all)
if __name__ == '__main__':
main()
@@ -0,0 +1,139 @@
[Autologin]
# Whether sddm should automatically log back into sessions when they exit
Relogin=false
# Name of session file for autologin session (if empty try last logged in)
Session=
# Username for autologin session
User=
[General]
# Which display server should be used.
# Valid values are: x11, x11-user, wayland. Wayland support is experimental
DisplayServer=x11
# Comma-separated list of environment variables to be set
GreeterEnvironment=
# Halt command
HaltCommand=/usr/bin/systemctl poweroff
# Input method module
InputMethod=
# Comma-separated list of Linux namespaces for user session to enter
Namespaces=
# Initial NumLock state. Can be on, off or none.
# If property is set to none, numlock won't be changed
# NOTE: Currently ignored if autologin is enabled.
Numlock=none
# Reboot command
RebootCommand=/usr/bin/systemctl reboot
[Theme]
# Current theme name
Current=where_is_my_sddm_theme
# Cursor size used in the greeter
CursorSize=
# Cursor theme used in the greeter
CursorTheme=
# Number of users to use as threshold
# above which avatars are disabled
# unless explicitly enabled with EnableAvatars
DisableAvatarsThreshold=7
# Enable display of custom user avatars
EnableAvatars=true
# Global directory for user avatars
# The files should be named <username>.face.icon
FacesDir=/usr/share/sddm/faces
# Font used in the greeter
Font=
# Theme directory path
ThemeDir=/usr/share/sddm/themes
[Users]
# Default $PATH for logged in users
DefaultPath=/usr/local/sbin:/usr/local/bin:/usr/bin
# Comma-separated list of shells.
# Users with these shells as their default won't be listed
HideShells=
# Comma-separated list of users that should not be listed
HideUsers=
# Maximum user id for displayed users
MaximumUid=60513
# Minimum user id for displayed users
MinimumUid=1000
# Remember the session of the last successfully logged in user
RememberLastSession=true
# Remember the last successfully logged in user
RememberLastUser=true
# When logging in as the same user twice, restore the original session, rather than create a new one
ReuseSession=true
[Wayland]
# Path of the Wayland compositor to execute when starting the greeter
CompositorCommand=weston --shell=kiosk
# Enable Qt's automatic high-DPI scaling
EnableHiDPI=true
# Path to a script to execute when starting the desktop session
SessionCommand=/usr/share/sddm/scripts/wayland-session
# Comma-separated list of directories containing available Wayland sessions
SessionDir=/usr/local/share/wayland-sessions,/usr/share/wayland-sessions
# Path to the user session log file
SessionLogFile=.local/share/sddm/wayland-session.log
[X11]
# Path to a script to execute when starting the display server
DisplayCommand=/usr/share/sddm/scripts/Xsetup
# Path to a script to execute when stopping the display server
DisplayStopCommand=/usr/share/sddm/scripts/Xstop
# Enable Qt's automatic high-DPI scaling
EnableHiDPI=true
# Arguments passed to the X server invocation
ServerArguments=-nolisten tcp
# Path to X server binary
ServerPath=/usr/bin/X
# Path to a script to execute when starting the desktop session
SessionCommand=/usr/share/sddm/scripts/Xsession
# Comma-separated list of directories containing available X sessions
SessionDir=/usr/local/share/xsessions,/usr/share/xsessions
# Path to the user session log file
SessionLogFile=.local/share/sddm/xorg-session.log
# Path to Xephyr binary
XephyrPath=/usr/bin/Xephyr
@@ -0,0 +1,68 @@
[General]
# Password mask character
passwordCharacter=*
# Mask password characters or not ("true" or "false")
passwordMask=true
# value "1" is all display width, "0.5" is a half of display width etc.
passwordInputWidth=0.5
# Background color of password input
passwordInputBackground=
# Radius of password input corners
passwordInputRadius=
# Width of the border for the password input
passwordInputBorderWidth=0
# Border color for the password input
passwordInputBorderColor=
# "true" for visible cursor, "false"
passwordInputCursorVisible=true
# Font size of password (in points)
passwordFontSize=96
passwordCursorColor=random
passwordTextColor=
# Allow blank password (e.g., if authentication is done by another PAM module)
passwordAllowEmpty=false
# Radius of the border which is displayed upon wrong authentication attempt
wrongPasswordBorderRadius=
# Color of the border which is displayed upon wrong authentication attempt
wrongPasswordBorderColor=
# Enable or disable cursor blink animation ("true" or "false")
cursorBlinkAnimation=true
# Show or not sessions choose label
showSessionsByDefault=false
# Font size of sessions choose label (in points).
sessionsFontSize=24
# Show or not users choose label
showUsersByDefault=false
# Font size of users choose label (in points)
usersFontSize=48
# Show user real name on label by default
showUserRealNameByDefault=true
# Path to background image
background=
# Or use just one color
backgroundFill=#000000
# Fill mode for image background
# Value must be on of: aspect, fill, tile, pad
backgroundFillMode=aspect
# Default text color for all labels
basicTextColor=#ffffff
# Blur radius for background image
blurRadius=0
# Hide cursor
hideCursor=false
# Default font
font=monospace
# Font of help message
helpFont=monospace
# Font size of help message (in points)
helpFontSize=18
+83
View File
@@ -0,0 +1,83 @@
import os
import shutil
import sys
RED = "\033[1;31m"
GREEN = "\033[1;32m"
YELLOW = "\033[1;33m"
CYAN = "\033[1;36m"
RESET = "\033[0m"
def log_info(msg): print(f"{CYAN}[*]{RESET} {msg}")
def log_success(msg): print(f"{GREEN}[✓]{RESET} {msg}")
def log_warn(msg): print(f"{YELLOW}[!]{RESET} {msg}")
def log_error(msg): print(f"{RED}[✗]{RESET} {msg}")
def ask_override(path):
resp = input(f"{YELLOW}'{path}' already exists. Override? (Y/N): {RESET}").strip().lower()
return resp == 'y'
def choice_files(src_root, dst_root, choices_map, override_all=False):
for final_name, options in choices_map.items():
existing_options = [
f for f in options
if os.path.exists(os.path.join(src_root, f.lstrip('/')))
]
if not existing_options:
log_warn(f"No source file found among options for {final_name}. Skipping.")
continue
if len(existing_options) == 1:
chosen = existing_options[0]
else:
log_info(f"Choose which file to copy as '{final_name}':")
for idx, opt in enumerate(existing_options, 1):
print(f"{idx}: {opt}")
while True:
try:
choice_idx = int(input(f"{CYAN}Enter number (1-{len(existing_options)}): {RESET}"))
if 1 <= choice_idx <= len(existing_options):
chosen = existing_options[choice_idx - 1]
break
except ValueError:
pass
log_warn("Invalid choice, try again.")
src_file = os.path.join(src_root, chosen.lstrip('/'))
dst_file = os.path.join(dst_root, final_name.lstrip('/'))
if os.path.exists(dst_file):
if not override_all and not ask_override(dst_file):
log_warn(f"Skipped overriding {dst_file}")
continue
shutil.copy2(src_file, dst_file)
log_success(f"Copied {chosen} -> {final_name}")
def copy_with_structure(src_root, dst_root, override_all=False):
for root, dirs, files in os.walk(src_root):
rel_path = os.path.relpath(root, src_root)
target_dir = os.path.join(dst_root, rel_path) if rel_path != '.' else dst_root
os.makedirs(target_dir, exist_ok=True)
for file in files:
src_file = os.path.join(root, file)
dst_file = os.path.join(target_dir, file)
if os.path.exists(dst_file):
if not override_all and not ask_override(dst_file):
log_warn(f"Skipped overriding {dst_file}")
continue
shutil.copy2(src_file, dst_file)
log_success(f"Copied: {src_file} -> {dst_file}")
def require_root():
if os.geteuid() != 0:
log_error("This script must be run as root (sudo). Exiting.")
sys.exit(1)