Initial commit

This commit is contained in:
2026-07-02 15:56:21 +02:00
commit 4529a3c472
92 changed files with 13593 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
# build output
/out/
# secrets payload — only README.md and run.sh are tracked
/04-secrets/*
!/04-secrets/README.md
!/04-secrets/run.sh
+17
View File
@@ -0,0 +1,17 @@
# Partition DISK: GPT, 512M EFI + rest ext4 root. Mounts root at /mnt, ESP at /mnt/boot.
# Sourced by run.sh (DISK comes from system.conf).
part() { case "$DISK" in *nvme*|*mmcblk*) echo "${DISK}p$1" ;; *) echo "${DISK}$1" ;; esac; }
EFI="$(part 1)"; ROOT="$(part 2)"
info "partitioning $DISK"
sgdisk --zap-all "$DISK"
sgdisk -n1:0:+512M -t1:ef00 -c1:EFI "$DISK"
sgdisk -n2:0:0 -t2:8300 -c2:root "$DISK"
partprobe "$DISK"; sleep 1
mkfs.fat -F32 "$EFI"
mkfs.ext4 -F "$ROOT"
mount "$ROOT" /mnt
mount --mkdir "$EFI" /mnt/boot # ESP at /boot so the kernel + initramfs land on it
+12
View File
@@ -0,0 +1,12 @@
# Install a minimal base system, generate fstab, copy this repo into the new root.
# Sourced by run.sh. The FULL package set is installed later by 02-system/run.sh.
pacstrap -K /mnt \
base linux linux-firmware intel-ucode amd-ucode \
mkinitcpio networkmanager sudo git base-devel vim efibootmgr terminus-font
genfstab -U /mnt >> /mnt/etc/fstab
# carry the repo into the installed system so provisioning can run after reboot
mkdir -p /mnt/root
cp -a "$REPO_ROOT" /mnt/root/arch-system-th
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
# Runs INSIDE arch-chroot. systemd-boot + mkinitcpio with STATIC loader entries.
# mkinitcpio already built /boot/initramfs-linux*.img during pacstrap, and its
# pacman hooks rebuild them on every kernel update — nothing to regenerate here
# or later. The kernel cmdline lives in the loader entry's `options` line.
set -euo pipefail
bootctl install # ESP is mounted at /boot
ROOT_UUID="$(findmnt -no UUID /)"
# microcode image matching this CPU (both packages are installed)
case "$(grep -m1 -oE 'Intel|AMD' /proc/cpuinfo)" in
Intel) UCODE="initrd /intel-ucode.img" ;;
AMD) UCODE="initrd /amd-ucode.img" ;;
*) UCODE="" ;;
esac
mkdir -p /boot/loader/entries
cat > /boot/loader/loader.conf <<EOF
default arch.conf
timeout 3
console-mode keep
EOF
cat > /boot/loader/entries/arch.conf <<EOF
title Arch Linux
linux /vmlinuz-linux
$UCODE
initrd /initramfs-linux.img
options root=UUID=$ROOT_UUID rw
EOF
cat > /boot/loader/entries/arch-fallback.conf <<EOF
title Arch Linux (fallback initramfs)
linux /vmlinuz-linux
$UCODE
initrd /initramfs-linux-fallback.img
options root=UUID=$ROOT_UUID rw
EOF
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Runs INSIDE arch-chroot. Locale, time, hostname, user, network.
set -euo pipefail
source /root/arch-system-th/system.conf
# time + locale
ln -sf "/usr/share/zoneinfo/$TIMEZONE" /etc/localtime
hwclock --systohc
sed -i "s/^#\s*\($LOCALE\)/\1/" /etc/locale.gen
locale-gen
echo "LANG=$LOCALE" > /etc/locale.conf
echo "KEYMAP=$KEYMAP" > /etc/vconsole.conf
# hostname
echo "$HOSTNAME" > /etc/hostname
# user + sudo (wheel)
useradd -m -G wheel -s /bin/bash "$USERNAME" 2>/dev/null || true
echo "%wheel ALL=(ALL:ALL) ALL" > /etc/sudoers.d/10-wheel
chmod 440 /etc/sudoers.d/10-wheel
echo "Set passwords for root and $USERNAME:"
passwd root
passwd "$USERNAME"
# move the repo into the user's home so provisioning runs as them after reboot
cp -a /root/arch-system-th "/home/$USERNAME/arch-system-th"
chown -R "$USERNAME:$USERNAME" "/home/$USERNAME/arch-system-th"
# network up on first boot
systemctl enable NetworkManager.service
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Base Arch install, run from the live ISO (as root, UEFI).
# Partitions DISK, installs a minimal base, sets up systemd-boot + mkinitcpio, then
# hands off to the system + user provisioning layers after first boot.
#
# ./run.sh # reads ../system.conf
set -euo pipefail
cd "$(dirname "$0")"
source ../02-system/lib.sh
source ../system.conf
REPO_ROOT="$(cd .. && pwd)"
# Safety net: if the repo arrived without exec bits (USB on exFAT, or the optional
# custom ISO which strips modes), restore +x so the copies we propagate to the
# installed system are runnable. Harmless when git already preserved them.
find "$REPO_ROOT" -name '*.sh' -exec chmod +x {} + 2>/dev/null || true
[ "$(id -u)" -eq 0 ] || die "run as root from the live ISO"
[ -d /sys/firmware/efi ] || die "not booted in UEFI mode"
[ -b "$DISK" ] || die "DISK '$DISK' is not a block device — edit system.conf"
echo "About to ERASE $DISK and install Arch (host=$HOSTNAME user=$USERNAME)."
read -rp "Type ERASE to continue: " ans
[ "$ans" = ERASE ] || die "aborted"
source ./00-partition.sh # partitions + mounts /mnt, /mnt/boot
source ./10-pacstrap.sh # base system + fstab + copy repo to /mnt/root
# in-chroot steps (the whole repo, incl. system.conf, was copied by 10-pacstrap)
arch-chroot /mnt bash /root/arch-system-th/01-install/20-boot.sh
arch-chroot /mnt bash /root/arch-system-th/01-install/30-finalize.sh
info "Base install done. Reboot, remove the ISO, then as your user run:"
info " sudo ~/arch-system-th/02-system/run.sh"
info " ~/arch-system-th/03-user/run.sh"
+16
View File
@@ -0,0 +1,16 @@
# Enable the [multilib] repo (needed for lib32-* and steam) — disabled by default
# on a fresh Arch install. Idempotent.
if ! grep -q '^\[multilib\]' /etc/pacman.conf; then
info "enabling [multilib] repo"
sed -i '/^#\[multilib\]/,/^#Include/ s/^#//' /etc/pacman.conf
pacman -Sy
fi
# Install the base package set + the GPU vendor group for this host.
pac_file packages/pacman.txt
case "$GPU" in
amd) pac_file packages/graphics-amd.txt ;;
intel) pac_file packages/graphics-intel.txt ;;
*) info "no GPU group for GPU='$GPU'" ;;
esac
+47
View File
@@ -0,0 +1,47 @@
# Deploy /etc + /usr/local/bin config files (see 02-system/files/).
# v4l2loopback virtual camera (for OBS virtual webcam)
deploy etc/modprobe.d/v4l2loopback.conf
deploy etc/modules-load.d/v4l2loopback.conf
# Logitech mice (logiops) — config + udev restart rule
deploy etc/logid.cfg
deploy etc/udev/rules.d/90-logid-start-restart.rules
# AirPlay receiver
deploy etc/shairport-sync.conf
# No autologin: plain tty1 password prompt, then ~/.zprofile exec's Hyprland.
# Drop any autologin override left by earlier provisioning.
DROPIN=/etc/systemd/system/getty@tty1.service.d/autologin.conf
if [ -f "$DROPIN" ]; then
rm -f "$DROPIN"
rmdir --ignore-fail-on-non-empty "$(dirname "$DROPIN")" 2>/dev/null || true
systemctl daemon-reload
info "removed stale autologin drop-in"
fi
# Desktop only: never sleep/suspend
if [ "$IS_DESKTOP" = 1 ]; then
deploy etc/sleep.conf.d/disable-sleep.conf
fi
# Unlock the keyring at login (what GDM normally does). Idempotent; 'optional'
# so a missing module never blocks login. pam_gnome_keyring.so ships with gnome-keyring.
PAM=/etc/pam.d/login
if ! grep -q pam_gnome_keyring.so "$PAM"; then
sed -i '/^auth[[:space:]]\+include[[:space:]]\+system-local-login/a auth optional pam_gnome_keyring.so' "$PAM"
sed -i '/^session[[:space:]]\+include[[:space:]]\+system-local-login/a session optional pam_gnome_keyring.so auto_start' "$PAM"
info "wired pam_gnome_keyring into $PAM"
fi
# Keep the login keyring's password in sync when you change your Unix password.
PAM_PW=/etc/pam.d/passwd
if ! grep -q pam_gnome_keyring.so "$PAM_PW"; then
sed -i '/^password[[:space:]]\+include[[:space:]]\+system-auth/a password optional pam_gnome_keyring.so' "$PAM_PW"
info "wired pam_gnome_keyring into $PAM_PW"
fi
# One-time: pam unlocks the "login" keyring (password = your login password).
# Fresh install creates it automatically; on an existing box, make the login keyring
# the default with that password in Seahorse, or wipe ~/.local/share/keyrings/* and re-login.
+19
View File
@@ -0,0 +1,19 @@
# Enable system services. enable_unit skips any unit that isn't installed yet
# (e.g. logid.service comes from the AUR logiops package, installed in the user layer).
enable_unit NetworkManager.service
enable_unit bluetooth.service
enable_unit avahi-daemon.service
enable_unit cups.socket # socket-activated: cups runs only on demand
enable_unit systemd-timesyncd.service
enable_unit fstrim.timer
enable_unit logid.service # logitech mice (AUR)
# Laptop: battery/power profiles. Desktop: not useful.
[ "$IS_DESKTOP" = 0 ] && enable_unit power-profiles-daemon.service
# libvirt / KVM (modular daemons + their sockets)
for drv in qemu interface network nodedev nwfilter secret storage; do
enable_unit "virt${drv}d.service"
enable_unit "virt${drv}d.socket" "virt${drv}d-ro.socket" "virt${drv}d-admin.socket"
done
+16
View File
@@ -0,0 +1,16 @@
# AMD GPU tuning — desktop only (high perf level + custom fan curve).
# Skipped on laptops or non-AMD GPUs.
if [ "$IS_DESKTOP" != 1 ] || [ "$GPU" != amd ]; then
info "skipping AMD GPU tuning (IS_DESKTOP=$IS_DESKTOP GPU=$GPU)"
return 0 2>/dev/null || exit 0
fi
deploy usr/local/bin/gpuprofile.sh 755
deploy usr/local/bin/amdgpu-fancontrol.sh 755
deploy etc/systemd/system/gpuprofile.service
deploy etc/systemd/system/amdgpu-fancontrol.service
deploy etc/systemd/system/amdgpu-fancontrol.timer
systemctl daemon-reload
enable_unit gpuprofile.service
enable_unit amdgpu-fancontrol.timer
+19
View File
@@ -0,0 +1,19 @@
# Add kernel cmdline tuning to the systemd-boot loader entries, idempotently.
# systemd-boot reads `options` at boot — no initramfs/entry regeneration needed.
# (intel_iommu is harmless on AMD CPUs; both target machines are Intel.)
toks="intel_iommu=on iommu=pt" # VFIO / PCI passthrough
[ "$GPU" = amd ] && toks="$toks amdgpu.mcbp=0 amdgpu.ppfeaturemask=0xfff7ffff"
shopt -s nullglob
entries=(/boot/loader/entries/arch*.conf)
[ "${#entries[@]}" -gt 0 ] || die "no loader entries in /boot/loader/entries (run base install first)"
for f in "${entries[@]}"; do
opts="$(sed -n 's/^options //p' "$f")"
for t in $toks; do
case " $opts " in *" $t "*) ;; *) opts="$opts $t" ;; esac
done
sed -i "s|^options .*|options $opts|" "$f"
info "$(basename "$f"): options $opts"
done
+33
View File
@@ -0,0 +1,33 @@
# Network shares + ramdisk. Mount points, fstab entries and the "reachable" gate
# services live here (no secrets). Only the credential FILES the CIFS/davfs mounts
# reference (/etc/nase.meow.credentials, /etc/davfs2/secrets) are secret — enter
# them via 04-secrets/run.sh. The mounts just fail until those files exist.
# mount points
for d in /mnt/nase.meow /mnt/files.70b1.de /mnt/ramdisk; do
[ -d "$d" ] || { mkdir -p "$d" && info "created $d"; }
done
# fstab entries owned by the provisioning user (numeric uid/gid, rebuild-safe).
u="${SUDO_USER:-$(id -un 1000 2>/dev/null || echo root)}"
uid="$(id -u "$u")"; gid="$(id -g "$u")"
add_fstab() { # add_fstab <mountpoint> <full fstab line>
grep -qE "[[:space:]]$1[[:space:]]" /etc/fstab && return 0
printf '%s\n' "$2" >> /etc/fstab && info "fstab += $1"
}
add_fstab /mnt/ramdisk \
"tmpfs /mnt/ramdisk tmpfs rw,uid=$uid,gid=$gid,nodev,nosuid,size=16G,comment=x-gvfs-show 0 0"
add_fstab /mnt/nase.meow \
"//nase.meow/data /mnt/nase.meow cifs rw,exec,uid=$uid,gid=$gid,credentials=/etc/nase.meow.credentials,_netdev,x-systemd.requires=nase.meow-ready.service,comment=x-gvfs-show 0 0"
add_fstab /mnt/files.70b1.de \
"https://files.70b1.de /mnt/files.70b1.de davfs rw,uid=$uid,gid=$gid,_netdev,x-systemd.requires=files.70b1.de-ready.service,comment=x-gvfs-show 0 0"
# "share reachable" gate services (wait until host is up before mounting)
deploy etc/systemd/system/nase.meow-ready.service
deploy etc/systemd/system/files.70b1.de-ready.service
systemctl daemon-reload
enable_unit nase.meow-ready.service
enable_unit files.70b1.de-ready.service
info "NOTE: enter share credentials via 04-secrets/run.sh (mounts fail until then)"
+19
View File
@@ -0,0 +1,19 @@
devices: (
{
name: "MX Anywhere 3S";
smartshift:
{
on: false;
threshold: 15;
torque: 50;
};
hiresscroll:
{
hires: true;
invert: false;
target: false;
};
dpi: 1000;
}
);
@@ -0,0 +1 @@
options v4l2loopback devices=1 video_nr=10 card_label="Virtual Cam" exclusive_caps=1
@@ -0,0 +1 @@
v4l2loopback
+304
View File
@@ -0,0 +1,304 @@
// Sample Configuration File for Shairport Sync
// Commented out settings are generally the defaults, except where noted.
// Some sections are operative only if Shairport Sync has been built with the right configuration flags.
// See the individual sections for details.
// General Settings
general =
{
name = "%h"; // This means "Hostname" -- see below. This is the name the service will advertise to iTunes.
// The default is "Hostname" -- i.e. the machine's hostname with the first letter capitalised (ASCII only.)
// You can use the following substitutions:
// %h for the hostname,
// %H for the Hostname (i.e. with first letter capitalised (ASCII only)),
// %v for the version number, e.g. 3.0 and
// %V for the full version string, e.g. 3.3-OpenSSL-Avahi-ALSA-soxr-metadata-sysconfdir:/etc
// Overall length can not exceed 50 characters. Example: "Shairport Sync %v on %H".
// password = "secret"; // (AirPlay 1 only) leave this commented out if you don't want to require a password
// interpolation = "auto"; // aka "stuffing". Default is "auto". Alternatives are "basic" or "soxr". Choose "soxr" only if you have a reasonably fast processor and Shairport Sync has been built with "soxr" support.
output_backend = "pa"; // Run "shairport-sync -h" to get a list of all output_backends, e.g. "alsa", "pipe", "stdout". The default is the first one.
// mdns_backend = "avahi"; // Run "shairport-sync -h" to get a list of all mdns_backends. The default is the first one.
// interface = "name"; // Use this advanced setting to specify the interface on which Shairport Sync should provide its service. Leave it commented out to get the default, which is to select the interface(s) automatically.
// port = <number>; // Listen for service requests on this port. 5000 for AirPlay 1, 7000 for AirPlay 2
// udp_port_base = 6001; // (AirPlay 1 only) start allocating UDP ports from this port number when needed
// udp_port_range = 10; // (AirPlay 1 only) look for free ports in this number of places, starting at the UDP port base. Allow at least 10, though only three are needed in a steady state.
// airplay_device_id_offset = 0; // (AirPlay 2 only) add this to the default airplay_device_id calculated from one of the device's MAC address
// airplay_device_id = 0x<six-digit_hexadecimal_number>L; // (AirPlay 2 only) use this as the airplay_device_id e.g. 0xDCA632D4E8F3L -- remember the "L" at the end as it's a 64-bit quantity!
// regtype = "<string>"; // Use this advanced setting to set the service type and transport to be advertised by Zeroconf/Bonjour. Default is "_raop._tcp" for AirPlay 1, "_airplay._tcp" for AirPlay 2.
// drift_tolerance_in_seconds = 0.002; // allow a timing error of this number of seconds of drift away from exact synchronisation before attempting to correct it
// resync_threshold_in_seconds = 0.050; // a synchronisation error greater than this number of seconds will cause resynchronisation; 0 disables it
// resync_recovery_time_in_seconds = 0.100; // allow this extra time to recover after a late resync. Increase the value, possibly to 0.5, in a virtual machine.
// playback_mode = "stereo"; // This can be "stereo", "mono", "reverse stereo", "both left" or "both right". Default is "stereo".
// alac_decoder = "hammerton"; // This can be "hammerton" or "apple". This advanced setting allows you to choose
// the original Shairport decoder by David Hammerton or the Apple Lossless Audio Codec (ALAC) decoder written by Apple.
// If you build Shairport Sync with the flag --with-apple-alac, the Apple ALAC decoder will be chosen by default.
// ignore_volume_control = "no"; // set this to "yes" if you want the volume to be at 100% no matter what the source's volume control is set to.
// volume_range_db = 60 ; // use this advanced setting to set the range, in dB, you want between the maximum volume and the minimum volume. Range is 30 to 150 dB. Leave it commented out to use mixer's native range.
// volume_max_db = 0.0 ; // use this advanced setting, which must have a decimal point in it, to set the maximum volume, in dB, you wish to use.
// The setting is for the hardware mixer, if chosen, or the software mixer otherwise. The value must be in the mixer's range (0.0 to -96.2 for the software mixer).
// Leave it commented out to use mixer's maximum volume.
// volume_control_profile = "standard" ; // use this advanced setting to specify how the airplay volume is transferred to the mixer volume.
// "standard" makes the volume change more quickly at lower volumes and slower at higher volumes.
// "flat" makes the volume change at the same rate at all volumes.
// "dasl_tapered" is similar to "standard" - it makes the volume change more quickly at lower volumes and slower at higher volumes.
// The intention behind dasl_tapered is that a given percentage change in volume should result in the same percentage change in
// perceived loudness. For instance, doubling the volume level should result in doubling the perceived loudness.
// With the range of AirPlay volume being from -30 to 0, doubling the volume from -22.5 to -15 results in an increase of 10 dB.
// Similarly, doubling the volume from -15 to 0 results in an increase of 10 dB.
// For compatibility with mixers having a restricted attenuation range (e.g. 30 dB), "dasl_tapered" will switch to a flat profile at low AirPlay volumes.
// volume_control_combined_hardware_priority = "no"; // when extending the volume range by combining the built-in software attenuator with the hardware mixer attenuator, set this to "yes" to reduce volume by using the hardware mixer first, then the built-in software attenuator.
// default_airplay_volume = -24.0; // this is the suggested volume after a reset or after the high_volume_threshold has been exceed and the high_volume_idle_timeout_in_minutes has passed
// The following settings are for dealing with potentially surprising high ("very loud") volume levels.
// When a new play session starts, it usually requests a suggested volume level from Shairport Sync. This is normally the volume level of the last session.
// This can cause unpleasant surprises if the last session was (a) very loud and (b) a long time ago.
// Thus, the user could be unpleasantly surprised by the volume level of the new session.
// To deal with this, when the last session volume is "very loud", the following two settings will lower the suggested volume after a period of idleness:
// high_threshold_airplay_volume = -16.0; // airplay volume greater or equal to this is "very loud"
// high_volume_idle_timeout_in_minutes = 0; // if the current volume is "very loud" and the device is not playing for more than this time, suggest the default volume for new connections instead of the current volume.
// Note 1: This timeout is set to 0 by default to disable this feature. Set it to some positive number, e.g. 180 to activate the feature.
// Note 2: Not all applications use the suggested volume: MacOS Music and Mac OS System Sounds use their own settings.
// run_this_when_volume_is_set = "/full/path/to/application/and/args"; // Run the specified application whenever the volume control is set or changed.
// The desired AirPlay volume is appended to the end of the command line leave a space if you want it treated as an extra argument.
// AirPlay volume goes from 0.0 to -30.0 and -144.0 means "mute".
// audio_backend_latency_offset_in_seconds = 0.0; // This is added to the latency requested by the player to delay or advance the output by a fixed amount.
// Use it, for example, to compensate for a fixed delay in the audio back end.
// E.g. if the output device, e.g. a soundbar, takes 100 ms to process audio, set this to -0.1 to deliver the audio
// to the output device 100 ms early, allowing it time to process the audio and output it perfectly in sync.
// audio_backend_buffer_desired_length_in_seconds = 0.2; // If set too small, buffer underflow occurs on low-powered machines.
// Too long and the response time to volume changes becomes annoying.
// Default is 0.2 seconds in the alsa backend, 0.35 seconds in the pa backend and 1.0 seconds otherwise.
// audio_backend_buffer_interpolation_threshold_in_seconds = 0.075; // Advanced feature. If the buffer size drops below this, stop using time-consuming interpolation like soxr to avoid dropouts due to underrun.
// audio_backend_silent_lead_in_time = "auto"; // This optional advanced setting, either "auto" or a positive number, sets the length of the period of silence that precedes the start of the audio.
// The default is "auto" -- the silent lead-in starts as soon as the player starts sending packets.
// Values greater than the latency are ignored. Values that are too low will affect initial synchronisation.
// dbus_service_bus = "system"; // The Shairport Sync dbus interface, if selected at compilation, will appear
// as "org.gnome.ShairportSync" on the whichever bus you specify here: "system" (default) or "session".
// mpris_service_bus = "system"; // The Shairport Sync mpris interface, if selected at compilation, will appear
// as "org.gnome.ShairportSync" on the whichever bus you specify here: "system" (default) or "session".
// resend_control_first_check_time = 0.10; // Use this optional advanced setting to set the wait time in seconds before deciding a packet is missing.
// resend_control_check_interval_time = 0.25; // Use this optional advanced setting to set the time in seconds between requests for a missing packet.
// resend_control_last_check_time = 0.10; // Use this optional advanced setting to set the latest time, in seconds, by which the last check should be done before the estimated time of a missing packet's transfer to the output buffer.
// missing_port_dacp_scan_interval_seconds = 2.0; // Use this optional advanced setting to set the time interval between scans for a DACP port number if no port number has been provided by the player for remote control commands
};
// Advanced parameters for controlling how Shairport Sync stays active and how it runs a session
sessioncontrol =
{
// "active" state starts when play begins and ends when the active_state_timeout has elapsed after play ends, unless another play session starts before the timeout has fully elapsed.
// run_this_before_entering_active_state = "/full/path/to/application and args"; // make sure the application has executable permission. If it's a script, include the shebang (#!/bin/...) on the first line
// run_this_after_exiting_active_state = "/full/path/to/application and args"; // make sure the application has executable permission. If it's a script, include the shebang (#!/bin/...) on the first line
// active_state_timeout = 10.0; // wait for this number of seconds after play ends before leaving the active state, unless another play session begins.
// run_this_before_play_begins = "/full/path/to/application and args"; // make sure the application has executable permission. If it's a script, include the shebang (#!/bin/...) on the first line
// run_this_after_play_ends = "/full/path/to/application and args"; // make sure the application has executable permission. If it's a script, include the shebang (#!/bin/...) on the first line
// run_this_if_an_unfixable_error_is_detected = "/full/path/to/application and args"; // if a problem occurs that can't be cleared by Shairport Sync itself, hook a program on here to deal with it.
// An error code-string is passed as the last argument.
// Many of these "unfixable" problems are caused by malfunctioning output devices, and sometimes it is necessary to restart the whole device to clear the problem.
// You could hook on a program to do this automatically, but beware -- the device may then power off and restart without warning!
// wait_for_completion = "no"; // set to "yes" to get Shairport Sync to wait until the "run_this..." applications have terminated before continuing
// allow_session_interruption = "no"; // set to "yes" to allow another device to interrupt Shairport Sync while it's playing from an existing audio source
// session_timeout = 120; // wait for this number of seconds after a source disappears before terminating the session and becoming available again.
};
// Back End Settings
// These are parameters for the "alsa" audio back end.
// For this section to be operative, Shairport Sync must be built with the following configuration flag:
// --with-alsa
alsa =
{
// output_device = "default"; // the name of the alsa output device. Use "shairport-sync -h" to discover the names of ALSA hardware devices. Use "alsamixer" or "aplay" to find out the names of devices, mixers, etc.
// mixer_control_name = "PCM"; // the name of the mixer to use to adjust output volume. No default. If not specified, no mixer is used and volume in adjusted in software.
// mixer_control_index = 0; // the index of the mixer to use to adjust output volume. Default is 0. The mixer is fully identified by the combination of the mixer_control_name and the mixer_control_index, e.g. "PCM",0 would be such a specification.
// mixer_device = "default"; // the mixer_device default is whatever the output_device is. Normally you wouldn't have to use this.
// output_rate = "auto"; // can be "auto", 44100, 88200, 176400 or 352800, but the device must have the capability.
// output_format = "auto"; // can be "auto", "U8", "S8", "S16", "S16_LE", "S16_BE", "S24", "S24_LE", "S24_BE", "S24_3LE", "S24_3BE", "S32", "S32_LE" or "S32_BE" but the device must have the capability. Except where stated using (*LE or *BE), endianness matches that of the processor.
// disable_synchronization = "no"; // Set to "yes" to disable synchronization. Default is "no" This is really meant for troubleshootingG.
// period_size = <number>; // Use this optional advanced setting to set the alsa period size near to this value
// buffer_size = <number>; // Use this optional advanced setting to set the alsa buffer size near to this value
// use_mmap_if_available = "yes"; // Use this optional advanced setting to control whether MMAP-based output is used to communicate with the DAC. Default is "yes"
// use_hardware_mute_if_available = "no"; // Use this optional advanced setting to control whether the hardware in the DAC is used for muting. Default is "no", for compatibility with other audio players.
// maximum_stall_time = 0.200; // Use this optional advanced setting to control how long to wait for data to be consumed by the output device before considering it an error. It should never approach 200 ms.
// use_precision_timing = "auto"; // Use this optional advanced setting to control how Shairport Sync gathers timing information. When set to "auto", if the output device is a real hardware device, precision timing will be used. Choose "no" for more compatible standard timing, choose "yes" to force the use of precision timing, which may cause problems.
// disable_standby_mode = "never"; // This setting prevents the DAC from entering the standby mode. Some DACs make small "popping" noises when they go in and out of standby mode. Settings can be: "always", "auto" or "never". Default is "never", but only for backwards compatibility. The "auto" setting prevents entry to standby mode while Shairport Sync is in the "active" mode. You can use "yes" instead of "always" and "no" instead of "never".
// disable_standby_mode_silence_threshold = 0.040; // Use this optional advanced setting to control how little audio should remain in the output buffer before the disable_standby code should start sending silence to the output device.
// disable_standby_mode_silence_scan_interval = 0.004; // Use this optional advanced setting to control how often the amount of audio remaining in the output buffer should be checked.
};
// Parameters for the "pw" PipeWire backend.
// For this section to be operative, Shairport Sync must be built with the following configuration flag:
// --with-pw
pw =
{
// application_name = "Shairport Sync"; // Set this to the name that should appear in the Sounds "Applications" or "Volume Levels".
// node_name = "Shairport Sync"; // This appears in some PipeWire CLI tool outputs.
// sink_target = "<sink target name>"; // Leave this commented out to get the sink target already chosen by the PipeWire system.
};
// Parameters for the "sndio" audio back end. All are optional.
// For this section to be operative, Shairport Sync must be built with the following configuration flag:
// --with-sndio
sndio =
{
// device = "snd/0"; // optional setting to set the name of the output device. Default is the sndio system default.
// rate = 44100; // optional setting which can be 44100, 88200, 176400 or 352800, but the device must have the capability. Default is 44100.
// format = "S16"; // optional setting which can be "U8", "S8", "S16", "S24", "S24_3LE", "S24_3BE" or "S32", but the device must have the capability. Except where stated using (*LE or *BE), endianness matches that of the processor.
// round = <number>; // advanced optional setting to set the period size near to this value
// bufsz = <number>; // advanced optional setting to set the buffer size near to this value
};
// Parameters for the "pa" PulseAudio backend.
// For this section to be operative, Shairport Sync must be built with the following configuration flag:
// --with-pa
pa =
{
// server = "host"; // Set this to override the default pulseaudio server that should be used.
// sink = "Sink Name"; // Set this to override the default pulseaudio sink that should be used. (Untested)
// application_name = "Shairport Sync"; //Set this to the name that should appear in the Sounds "Applications" tab when Shairport Sync is active.
};
// Parameters for the "jack" JACK Audio Connection Kit backend.
// For this section to be operative, Shairport Sync must be built with the following configuration flag:
// --with-jack
jack =
{
// client_name = "shairport-sync"; // Set this to the name of the client that should appear in "Connections" when Shairport Sync is active.
// autoconnect_pattern = ""; // Set this to a POSIX regular expression pattern that describes the ports you would like to connect to
// automatically. Examples:
// "system:playback_[12]"
// "some_app_[0-9]*:in-[LR]"
// "jack_mixer:in_2[78]"
// Beware: if you make a syntax error, libjack might crash. In that case, fix it and start over.
// For a good overview, look here: https://www.ibm.com/support/knowledgecenter/SS8NLW_11.0.1/com.ibm.swg.im.infosphere.dataexpl.engine.doc/c_posix-regex-examples.html
// soxr_resample_quality = "none"; // Enable resampling by setting this to "very high", "high", "medium", "low" or "quick"
// bufsz = <number>; // advanced optional setting to set the buffer size to this value
};
// Parameters for the "pipe" audio back end, a back end that directs raw CD-format audio output to a pipe. No interpolation is done.
// For this section to be operative, Shairport Sync must have been built with the following configuration flag:
// --with-pipe
pipe =
{
// name = "/tmp/shairport-sync-audio"; // this is the default
};
// There are no configuration file parameters for the "stdout" audio back end. No interpolation is done.
// To include support for the "stdout" backend, Shairport Sync must be built with the following configuration flag:
// --with-stdout
// There are no configuration file parameters for the "ao" audio back end. No interpolation is done.
// To include support for the "ao" backend, Shairport Sync must be built with the following configuration flag:
// --with-ao
// For this section to be operative, Shairport Sync must be built with the following configuration flag:
// --with-convolution
dsp =
{
//////////////////////////////////////////
// This convolution filter can be used to apply almost any correction to the audio signal, like frequency and phase correction.
// For example you could measure (with a good microphone and a sweep-sine) the frequency response of your speakers + room,
// and apply a correction to get a flat response curve.
//////////////////////////////////////////
//
// convolution = "no"; // Set this to "yes" to activate the convolution filter.
// convolution_ir_file = "impulse.wav"; // Impulse Response file to be convolved to the audio stream
// convolution_gain = -4.0; // Static gain applied to prevent clipping during the convolution process
// convolution_max_length = 44100; // Truncate the input file to this length in order to save CPU.
//////////////////////////////////////////
// This loudness filter is used to compensate for human ear non linearity.
// When the volume decreases, our ears loose more sentisitivity in the low range frequencies than in the mid range ones.
// This filter aims at compensating for this loss, applying a variable gain to low frequencies depending on the volume.
// More info can be found here: https://en.wikipedia.org/wiki/Equal-loudness_contour
// For this filter to work properly, you should disable (or set to a fix value) all other volume control and only let shairport-sync control your volume.
// The setting "loudness_reference_volume_db" should be set at the volume reported by shairport-sync when listening to music at a normal listening volume.
//////////////////////////////////////////
//
// loudness = "no"; // Set this to "yes" to activate the loudness filter
// loudness_reference_volume_db = -20.0; // Above this level the filter will have no effect anymore. Below this level it will gradually boost the low frequencies.
};
// How to deal with metadata, including artwork
// For this section to be operative, Shairport Sync must be built with at one (or more) of the following configuration flags:
// --with-metadata, --with-dbus-interface, --with-mpris-interface or --with-mqtt-client.
// In those cases, "enabled" and "include_cover_art" will both be "yes" by default
metadata =
{
// enabled = "yes"; // set this to yes to get Shairport Sync to solicit metadata from the source and to pass it on via a pipe
// include_cover_art = "yes"; // set to "yes" to get Shairport Sync to solicit cover art from the source and pass it via the pipe. You must also set "enabled" to "yes".
// cover_art_cache_directory = "/tmp/shairport-sync/.cache/coverart"; // artwork will be stored in this directory if the dbus or MPRIS interfaces are enabled or if the MQTT client is in use. Set it to "" to prevent caching, which may be useful on some systems
// pipe_name = "/tmp/shairport-sync-metadata";
// pipe_timeout = 5000; // wait for this number of milliseconds for a blocked pipe to unblock before giving up
// progress_interval = 0.0; // if non-zero, progress 'phbt' messages will be sent at the interval specified in seconds. A 'phb0' message will also be sent when the first audio frame of a play session is about to be played.
// Each message consists of the RTPtime of a a frame of audio and the exact system time when it is to be played. The system time, in nanoseconds, is based the CLOCK_MONOTONIC_RAW of the machine -- if available -- or CLOCK_MONOTONIC otherwise.
// Messages are sent when the frame is placed in the output device's buffer, thus, they will be _approximately_ 'audio_backend_buffer_desired_length_in_seconds' (default 0.2 seconds) ahead of time.
// socket_address = "226.0.0.1"; // if set to a host name or IP address, UDP packets containing metadata will be sent to this address. May be a multicast address. "socket-port" must be non-zero and "enabled" must be set to yes"
// socket_port = 5555; // if socket_address is set, the port to send UDP packets to
// socket_msglength = 65000; // the maximum packet size for any UDP metadata. This will be clipped to be between 500 or 65000. The default is 500.
};
// How to enable the MQTT-metadata/remote-service
// For this section to be operative, Shairport Sync must be built with the following configuration flag:
// --with-mqtt-client
// Note that, for compatability with many MQTT brokers and applications,
// every message that has no extra data is given a
// payload consisting of the string "--".
// You can change this or you can enable empty payloads -- see below.
mqtt =
{
// enabled = "no"; // set this to yes to enable the mqtt-metadata-service
// hostname = "iot.eclipse.org"; // Hostname of the MQTT Broker
// port = 1883; // Port on the MQTT Broker to connect to
// username = NULL; //set this to a string to your username in order to enable username authentication
// password = NULL; //set this to a string you your password in order to enable username & password authentication
// capath = NULL; //set this to the folder with the CA-Certificates to be accepted for the server certificate. If not set, TLS is not used
// cafile = NULL; //this may be used as an (exclusive) alternative to capath with a single file for all ca-certificates
// certfile = NULL; //set this to a string to a user certificate to enable MQTT Client certificates. keyfile must also be set!
// keyfile = NULL; //private key for MQTT Client authentication
// topic = NULL; //MQTT topic where this instance of shairport-sync should publish. If not set, the general.name value is used.
// publish_raw = "no"; //whether to publish all available metadata under the codes given in the 'metadata' docs.
// publish_parsed = "no"; //whether to publish a small (but useful) subset of metadata under human-understandable topics
// empty_payload_substitute = "--"; // MQTT messages with empty payloads often are invisible or have special significance to MQTT brokers and readers.
// To avoid empty payload problems, the string here is used instead of any empty payload. Set it to the empty string -- "" -- to leave the payload empty.
// Currently published topics:artist,album,title,genre,format,songalbum,volume,client_ip,
// Additionally, messages at the topics play_start,play_end,play_flush,play_resume are published
// publish_cover = "no"; //whether to publish the cover over mqtt in binary form. This may lead to a bit of load on the broker
// enable_remote = "no"; //whether to remote control via MQTT. RC is available under `topic`/remote.
// Available commands are "command", "beginff", "beginrew", "mutetoggle", "nextitem", "previtem", "pause", "playpause", "play", "stop", "playresume", "shuffle_songs", "volumedown", "volumeup"
};
// Diagnostic settings. These are for diagnostic and debugging only. Normally you should leave them commented out
diagnostics =
{
// disable_resend_requests = "no"; // set this to yes to stop Shairport Sync from requesting the retransmission of missing packets. Default is "no".
// log_output_to = "syslog"; // set this to "syslog" (default), "stderr" or "stdout" or a file or pipe path to specify were all logs, statistics and diagnostic messages are written to. If there's anything wrong with the file spec, output will be to "stderr".
// statistics = "no"; // set to "yes" to print statistics in the log
// log_verbosity = 0; // "0" means no debug verbosity, "3" is most verbose.
// log_show_file_and_line = "yes"; // set this to yes if you want the file and line number of the message source in the log file
// log_show_time_since_startup = "no"; // set this to yes if you want the time since startup in the debug message -- seconds down to nanoseconds
// log_show_time_since_last_message = "yes"; // set this to yes if you want the time since the last debug message in the debug message -- seconds down to nanoseconds
// drop_this_fraction_of_audio_packets = 0.0; // use this to simulate a noisy network where this fraction of UDP packets are lost in transmission. E.g. a value of 0.001 would mean an average of 0.1% of packets are lost, which is actually quite a high figure.
// retain_cover_art = "no"; // artwork is deleted when its corresponding track has been played. Set this to "yes" to retain all artwork permanently. Warning -- your directory might fill up.
};
@@ -0,0 +1,5 @@
[Sleep]
AllowSuspend=no
AllowHibernation=no
AllowHybridSleep=no
AllowSuspendThenHibernate=no
@@ -0,0 +1,7 @@
[Unit]
Description=AMDGPU fan control
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/amdgpu-fancontrol.sh
@@ -0,0 +1,9 @@
[Unit]
Description=Run AMDGPU fan control periodically
[Timer]
OnBootSec=20s
OnUnitActiveSec=20s
[Install]
WantedBy=timers.target
@@ -0,0 +1,11 @@
[Unit]
Description=Wait for nase.meow to be reachable
After=network-online.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'until host files.70b1.de; do sleep 1; done'
TimeoutSec=30
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,11 @@
[Unit]
Description=Increase GPU core and memory clocks
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/gpuprofile.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,11 @@
[Unit]
Description=Wait for nase.meow to be reachable
After=network-online.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'until host nase.meow; do sleep 1; done'
TimeoutSec=30
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,3 @@
# Logitech via Bluetooth (BlueZ UHID path 0005:046D:...)
ACTION=="add|change", SUBSYSTEM=="hidraw", KERNELS=="0005:046D:*", \
RUN+="/usr/bin/systemctl restart --no-block logid.service"
@@ -0,0 +1,42 @@
#!/bin/sh
# ---------------- CONFIG ----------------
# Temperature threshold in millidegrees Celsius
# 55000 = 55°C
TEMP_THRESHOLD=55000
# PWM values (0255)
PWM_IDLE=25 # fan speed below threshold
PWM_HOT=90 # fan speed above threshold
# ---------------------------------------
# Find the AMD card (vendor 0x1002), then its hwmon — no hardcoded cardN.
HWMON=""
for c in /sys/class/drm/card[0-9]*; do
[ "$(cat "$c/device/vendor" 2>/dev/null)" = "0x1002" ] || continue
HWMON="$(ls -d "$c"/device/hwmon/hwmon* 2>/dev/null | head -n1)"
break
done
[ -z "$HWMON" ] && exit 0
TEMP_FILE="$HWMON/temp1_input"
PWM_ENABLE="$HWMON/pwm1_enable"
PWM_FILE="$HWMON/pwm1"
# Enable manual fan control (always)
echo 1 > "$PWM_ENABLE"
# Read temperature
TEMP="$(cat "$TEMP_FILE")"
# Decide PWM
if [ "$TEMP" -ge "$TEMP_THRESHOLD" ]; then
PWM="$PWM_HOT"
else
PWM="$PWM_IDLE"
fi
# Always write PWM
echo "$PWM" > "$PWM_FILE"
exit 0
@@ -0,0 +1,10 @@
#!/bin/sh
# Force the AMD GPU to "high" performance level.
# Pins memory clock to 100% — raises idle draw (~20W) but fixes stuttering.
# Run as root (systemd oneshot). Finds the AMD card by vendor id; no hardcoded cardN.
for c in /sys/class/drm/card[0-9]*; do
[ "$(cat "$c/device/vendor" 2>/dev/null)" = "0x1002" ] || continue
echo high > "$c/device/power_dpm_force_performance_level"
exit 0
done
exit 0
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Tiny shared helpers. Source this; don't execute.
info() { echo ">> $*"; }
die() { echo "ERROR: $*" >&2; exit 1; }
# deploy <path-under-root> [mode] : copy 02-system/files/<path> to /<path>
# e.g. deploy etc/logid.cfg | deploy usr/local/bin/gpuprofile.sh 755
deploy() { install -Dm"${2:-644}" "files/$1" "/$1" && info "deployed /$1"; }
# enable a systemd unit only if it exists (some come from AUR, installed later)
enable_unit() { systemctl enable "$@" 2>/dev/null && info "enabled $*" || echo " skip (no unit): $*"; }
# install every package named in a file (ignores # comments and blank lines)
pac_file() { pacman -S --needed --noconfirm $(grep -vE '^\s*#|^\s*$' "$1"); }
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
# OPT-IN: create a NetworkManager bridge (br0) that enslaves a physical NIC, so
# libvirt/qemu VMs get real LAN IPs (DHCP from your router) instead of NAT.
#
# Host-specific (NIC name differs per machine) and briefly drops the wired link,
# so this is NOT part of run.sh. Run once per machine, locally (not over the
# very link you're bridging):
# sudo ./kvm-bridge.sh [iface] # iface defaults to the connected ethernet
#
# For a STATIC bridge IP instead of DHCP, after running this:
# nmcli connection modify br0 ipv4.method manual \
# ipv4.addresses 192.168.1.100/24 ipv4.gateway 192.168.1.1 ipv4.dns 8.8.8.8
# nmcli connection up br0
set -euo pipefail
[ "$(id -u)" -eq 0 ] || { echo "run as root"; exit 1; }
IFACE="${1:-$(nmcli -t -f DEVICE,TYPE,STATE device status \
| awk -F: '$2=="ethernet" && $3=="connected"{print $1; exit}')}"
[ -n "$IFACE" ] || { echo "no connected ethernet found — pass the interface name"; exit 1; }
echo "Bridging $IFACE into br0 (the wired connection will blip)."
# let qemu's bridge helper use br0
install -d /etc/qemu
grep -qxF 'allow br0' /etc/qemu/bridge.conf 2>/dev/null || echo 'allow br0' >> /etc/qemu/bridge.conf
# bridge + slave (DHCP on the bridge by default); idempotent
nmcli connection show br0 >/dev/null 2>&1 \
|| nmcli connection add type bridge con-name br0 ifname br0
nmcli connection show "bridge-slave-$IFACE" >/dev/null 2>&1 \
|| nmcli connection add type ethernet con-name "bridge-slave-$IFACE" ifname "$IFACE" master br0
nmcli connection up br0
echo "Done. Point VMs at bridge 'br0' (virt-manager: Bridge device → br0)."
+10
View File
@@ -0,0 +1,10 @@
# AMD GPU packages — installed only when a host profile sets GPU=amd.
# Generic mesa/vulkan-icd-loader stay in the base pacman.txt; these are AMD-only.
vulkan-radeon
lib32-vulkan-radeon
xf86-video-amdgpu
libva-utils
gst-plugin-va
rocm-hip-runtime
rocm-opencl-runtime
amdgpu_top
+7
View File
@@ -0,0 +1,7 @@
# Intel GPU packages — installed only when a host profile sets GPU=intel
# (e.g. the laptop). Not present on the AMD desktop harvest; net-new additions.
vulkan-intel
lib32-vulkan-intel
intel-media-driver
libva-utils
gst-plugin-va
+323
View File
@@ -0,0 +1,323 @@
# Native explicit packages. Refresh on the running system: pacman -Qqen > pacman.txt
7zip
accountsservice
adwaita-icon-theme
adw-gtk-theme
alsa-firmware
alsa-plugins
alsa-utils
ant
arduino-cli
argyllcms
asar
assimp
b43-fwcutter
base
base-devel
bash-completion
bind
blender
blueman
bluez
bluez-utils
bmon
broadcom-wl-dkms
btrfs-progs
cantarell-fonts
cava
cdrtools
chromium
clinfo
cmake
code
composer
cosmic-session
cryptsetup
cups
darktable
davfs2
dconf-editor
device-mapper
diffutils
dmidecode
dmraid
dnsmasq
docker
docker-buildx
docker-compose
dosfstools
e2fsprogs
easytag
edk2-ovmf
efibootmgr
efitools
element-desktop
esptool
ethtool
evince
evolution
evolution-ews
evtest
exfatprogs
f2fs-tools
feishin
ffmpegthumbnailer
file-roller
firefox
foliate
fractal
freecad
freerdp
gamescope
gendesk
ghidra
gimp
gnome-calculator
gnome-calendar
gnome-clocks
gnome-console
gnome-contacts
gnome-disk-utility
gnome-keyring
gnome-maps
gnome-nettool
gnome-terminal
gnome-text-editor
gnome-themes-extra
gnome-weather
go
godot
gst-libav
gst-plugin-pipewire
gst-plugins-bad
gst-plugins-ugly
gtk3-demos
guestfs-tools
gvfs
gvfs-afc
gvfs-gphoto2
gvfs-mtp
gvfs-nfs
gvfs-smb
haveged
hdparm
hexedit
htop
httpie
hwdetect
hyprland
hyprland-protocols
hyprlang
hyprpaper
hyprpicker
hyprshot
hyprsunset
hyprwayland-scanner
iftop
inetutils
inkscape
intel-ucode
inter-font
iotop
iperf
iptables
iwd
jdk17-openjdk
jdk8-openjdk
jfsutils
kdenlive
keepassxc
kicad
kid3
kid3-common
kismet
kitty
krita
less
lib32-mesa
lib32-vulkan-icd-loader
libcurl-gnutls
libdvdcss
libgsf
libopenraw
libreoffice-fresh
libvirt
libvncserver
libwnck3
linssid
linux
linux-firmware
linux-headers
logrotate
loupe
lsb-release
lsof
lsscsi
lvm2
man-db
man-pages
mdadm
mediainfo
mesa
mesa-utils
mitmproxy
mixxx
mkinitcpio
modemmanager
monolith
moreutils
mpv
mtools
musescore
nano
nautilus
ncdu
neovim
netctl
nethogs
networkmanager
network-manager-applet
networkmanager-openconnect
networkmanager-opecd pn
nfs-utils
nilfs-utils
nmap
nodejs
noto-fonts
noto-fonts-cjk
noto-fonts-emoji
noto-fonts-extra
npm
nss-mdns
ntfs-3g
ntp
nvtop
openbsd-netcat
openssh
otf-font-awesome
pacman-contrib
pavucontrol
pd
perl
perl-image-exiftool
pipewire-alsa
pipewire-jack
pipewire-pulse
pipewire-roc
pipewire-zeroconf
pkgfile
plocate
po4a
poco
poppler-glib
power-profiles-daemon
prusa-slicer
python
python-pyqt6
python-rtmidi
python-tinycss2
python-virtualenv
qemu-full
qemu-img
qpwgraph
radeontop
rclone
read-edid
reaper
rebuild-detector
reflector
remmina
rocm-smi-lib
rpi-imager
rsync
rtaudio
rtkit
rtl_433
rust
samba
sassc
sg3_utils
shairport-sync
smartmontools
s-nail
socat
sof-firmware
solaar
sonic-visualiser
sqlitebrowser
steam
sudo
supercollider
sushi
swaync
swtpm
sysbench
sysfsutils
sysstat
systemd-sysvcompat
tenacity
testdisk
texinfo
thunderbird
tmux
totem
ttf-bitstream-vera
ttf-dejavu
ttf-liberation
ttf-opensans
unrar
unzip
upower
uriparser
usb_modeswitch
usbutils
v4l2loopback-dkms
vdpauinfo
vim
virt-install
virt-manager
virt-viewer
vlc
vlc-plugins-all
vulkan-icd-loader
waybar
wayvnc
webapp-manager
wf-recorder
wget
which
wimlib
wine
wine-gecko
wine-mono
winetricks
wireguard-tools
wireplumber
wireshark-cli
wireshark-qt
wofi
wpa_supplicant
xcb-util-wm
xdg-desktop-portal
xdg-desktop-portal-gtk
xdg-desktop-portal-hyprland
xdg-user-dirs
xdg-user-dirs-gtk
xdg-utils
xf86-input-libinput
xf86-video-ati
xfsprogs
xl2tpd
xorg-server
xorg-xdpyinfo
xorg-xinit
xorg-xinput
xorg-xkill
xorg-xrandr
xterm
yabridge
yabridgectl
yt-dlp
zsh
zsh-autosuggestions
zsh-syntax-highlighting
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# Root-level provisioning. Run on the installed system as root:
# sudo ./run.sh
set -euo pipefail
cd "$(dirname "$0")"
source lib.sh
source ../system.conf # GPU, IS_DESKTOP, …
[ "$(id -u)" -eq 0 ] || die "run as root"
[ -n "${GPU:-}" ] && [ -n "${IS_DESKTOP:-}" ] || die "set GPU and IS_DESKTOP in system.conf"
info "provisioning (GPU=$GPU, desktop=$IS_DESKTOP)"
# run every numbered step in order; each is independently re-runnable
for step in [0-9][0-9]-*.sh; do
info "--- $step ---"
source "$step"
done
info "system provisioning done. Next: run 03-user/run.sh as your user."
+11
View File
@@ -0,0 +1,11 @@
# Ensure the yay AUR helper is present (build yay-bin from the AUR if not).
if command -v yay >/dev/null; then
info "yay already installed"
return 0 2>/dev/null || exit 0
fi
sudo pacman -S --needed --noconfirm git base-devel
tmp="$(mktemp -d)"
git clone https://aur.archlinux.org/yay-bin.git "$tmp/yay-bin"
( cd "$tmp/yay-bin" && makepkg -si --noconfirm )
rm -rf "$tmp"
+21
View File
@@ -0,0 +1,21 @@
# Install AUR packages one at a time, so a single build failure (common with the
# AUR — removed packages, broken builds) doesn't abort the rest. yay still pulls
# each package's AUR dependencies automatically. Failures are collected and
# reported at the end, and logged to ~/aur-failed.log for retrying.
LOG="$HOME/aur-failed.log"
: > "$LOG"
while read -r pkg; do
yay -S --needed --noconfirm "$pkg" || echo "$pkg" >> "$LOG"
done < <(grep -vE '^\s*#|^\s*$' "$REPO_ROOT/03-user/packages/aur.txt")
if [ -s "$LOG" ]; then
echo ""
echo "!! $(wc -l < "$LOG") AUR package(s) FAILED — retry later with:"
echo " yay -S \$(cat $LOG)"
echo " failed:"
sed 's/^/ - /' "$LOG"
else
rm -f "$LOG"
info "all AUR packages installed"
fi
+13
View File
@@ -0,0 +1,13 @@
# Apply dotfiles: copy the plain tree in 03-user/dotfiles/ into $HOME.
DOTS="$REPO_ROOT/03-user/dotfiles"
if [ -z "$(ls -A "$DOTS" 2>/dev/null)" ]; then
echo " 03-user/dotfiles empty — nothing to deploy"
return 0 2>/dev/null || exit 0
fi
cp -a "$DOTS/." "$HOME/"
# If exec bits were lost in transit (USB exFAT / optional custom ISO), restore them
# on the deployed scripts. They're all shebang scripts (no binaries) → detect by shebang.
grep -rlI '^#!' "$HOME/scripts" "$HOME/.config/waybar/scripts" 2>/dev/null \
| xargs -r chmod +x
+9
View File
@@ -0,0 +1,9 @@
# Deploy display colour profiles (ICC) to ~/.local/share/icc/.
# Monitor calibration; the compositor / colord matches them to a display.
found=0
for icc in "$REPO_ROOT/03-user/colorprofiles"/*.icc; do
[ -e "$icc" ] || continue # no matches -> skip (glob left literal)
install -Dm644 "$icc" "$HOME/.local/share/icc/$(basename "$icc")" && info "icc: $(basename "$icc")"
found=1
done
[ "$found" = 1 ] || echo " no colour profiles in 03-user/colorprofiles"
+22
View File
@@ -0,0 +1,22 @@
# User defaults: login shell, file manager, mime handlers, user services.
# Login shell = zsh. The Hyprland autostart lives in ~/.zprofile, which only zsh
# reads at login; with the default bash shell you'd just land on a prompt.
if [ "$(getent passwd "$USER" | cut -d: -f7)" != /usr/bin/zsh ]; then
sudo chsh -s /usr/bin/zsh "$USER" && info "login shell set to zsh"
fi
# Default file manager = GNOME Files (Nautilus). Set explicitly so no other app
# that claims inode/directory (e.g. easytag) wins. (arch_notes.md)
xdg-mime default org.gnome.Nautilus.desktop inode/directory
# User services that ship as ~/.config/systemd/user units (from dotfiles).
systemctl --user daemon-reload
systemctl --user enable shairport-sync.service 2>/dev/null \
&& info "enabled shairport-sync (user)" || echo " skip: shairport-sync user unit"
# Let PAM own gnome-keyring-daemon (see 02-system/20-config.sh); disable the user
# socket so it isn't also started here — avoids a double instance / double prompt.
systemctl --user disable --now gnome-keyring-daemon.socket 2>/dev/null \
&& info "disabled gnome-keyring-daemon.socket (PAM starts the daemon)" \
|| echo " skip: gnome-keyring-daemon.socket already off"
+19
View File
@@ -0,0 +1,19 @@
# Install VS Code extensions (edit the list below to add/remove).
# code is the native OSS build (pacman 'code'), installed by the system layer.
# It resolves extensions against the Open VSX registry (not the MS Marketplace).
# `code --install-extension` is idempotent: it skips anything already present.
if ! command -v code >/dev/null; then
echo " skip: code not installed — no VS Code extensions"
return 0 2>/dev/null || exit 0
fi
exts=(
anthropic.claude-code
esbenp.prettier-vscode
)
for ext in "${exts[@]}"; do
code --install-extension "$ext" >/dev/null 2>&1 \
&& info "extension: $ext" \
|| echo " FAILED extension: $ext"
done
+12
View File
@@ -0,0 +1,12 @@
# Seed localsend settings ONCE. Kept out of the dotfiles tree: localsend rewrites
# this file at runtime (it regenerates the SSL keys we stripped from the seed), so
# re-applying dotfiles would clobber them. Deploy only if no config exists yet.
SEED="$REPO_ROOT/03-user/seed/localsend-shared_preferences.json"
DST="$HOME/.local/share/org.localsend.localsend_app/shared_preferences.json"
if [ -f "$DST" ]; then
info "localsend config already present — leaving it untouched"
elif [ -f "$SEED" ]; then
install -Dm644 "$SEED" "$DST"
info "seeded localsend settings (SSL keys regenerate on first launch)"
fi
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,14 @@
{
"window.menuBarVisibility": "toggle",
"security.workspace.trust.untrustedFiles": "open",
"diffEditor.ignoreTrimWhitespace": false,
"extensions.ignoreRecommendations": true,
"chat.commandCenter.enabled": false,
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"workbench.editor.enablePreview": false,
"diffEditor.maxComputationTime": 0,
"diffEditor.hideUnchangedRegions.enabled": true,
"claudeCode.preferredLocation": "panel",
}
+3
View File
@@ -0,0 +1,3 @@
--enable-features=UseOzonePlatform
--ozone-platform=wayland
--enable-wayland-ime
@@ -0,0 +1,3 @@
--enable-features=UseOzonePlatform
--ozone-platform=wayland
--enable-wayland-ime
@@ -0,0 +1,7 @@
file:///mnt/nase.meow/Data/Projects/Static/das_buero/lightcontrol lightcontrol
file:///mnt/nase.meow/Data/Projects/Static/huttinger_web huttinger_web
file:///mnt/nase.meow/Data/Projects/Static/tobiashuttinger tobiashuttinger
file:///mnt/nase.meow/Data
file:///mnt/nase.meow/Download
file:///mnt/nase.meow/Media
file:///mnt/nase.meow/Data/Projects
+461
View File
@@ -0,0 +1,461 @@
# https://wiki.hypr.land/Configuring/
# You can split this configuration into multiple files
# Create your files separately and then link them to this file like this:
# source = ~/.config/hypr/myColors.conf
################
### MONITORS ###
################
# See https://wiki.hypr.land/Configuring/Monitors/
monitorv2 {
output = DP-1
mode = 3840x2160@60
position = auto-left
scale = 1.5
bitdepth = 10
icc = /home/tobias/scripts/set_gamma/LG_1_2020_D6500_sRGB.icm
}
monitorv2 {
output = DP-2
mode = 3840x2160@60
position = auto-right
scale = 1.5
bitdepth = 10
icc = /home/tobias/scripts/set_gamma/LG_1_2020_D6500_sRGB.icm
}
# Assign Workspace 1 to correct monitor and set cursor to that workspace on start
#workspace=name:1, monitor:DP-2
#exec-once = hyprctl dispatch workspace 1
debug {
disable_logs = true
}
# unscale XWayland
xwayland {
force_zero_scaling = true
}
###################
### MY PROGRAMS ###
###################
# See https://wiki.hypr.land/Configuring/Keywords/
# Set programs that you use
$terminal = kitty
$fileManager = nautilus
$menu = wofi --show drun
#################
### AUTOSTART ###
#################
# Autostart necessary processes (like notifications daemons, status bars, etc.)
# Or execute your favorite apps at launch like this:
exec-once = hyprpaper & waybar & swaync & hyprsunset
exec-once = blueman-applet & nm-applet & pasystray
exec-once = localsend --hidden
exec-once = [workspace 1 silent] firefox
exec-once = [workspace 2 silent] evolution
# Screen sharing conf
exec-once=dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP
#############################
### ENVIRONMENT VARIABLES ###
#############################
# See https://wiki.hypr.land/Configuring/Environment-variables/
# Cursor
env = XCURSOR_SIZE,24
env = HYPRCURSOR_SIZE,24
env = XCURSOR_THEME,default
# Theme options
env = ADWAITA_THEME,dark
env = COLOR_SCHEME,prefer-dark
env = GDK_BACKEND,wayland,x11,*
env = XDG_CURRENT_DESKTOP,Hyprland
env = XDG_SESSION_TYPE,wayland
env = XDG_SESSION_DESKTOP,Hyprland
env = QT_AUTO_SCREEN_SCALE_FACTOR,1
env = QT_QPA_PLATFORM,wayland;xcb
env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1
# Setting wayland for var toolkits
env = MOZ_ENABLE_WAYLAND,1
env = ELECTRON_OZONE_PLATFORM_HINT,wayland
env = CLUTTER_BACKEND,wayland
env = SDL_VIDEODRIVER,wayland
#env = QT_STYLE_OVERRIDE,Adwaita-Dark
# This makes qt apps get dark mode preference via xdg portal, however no dark icon theme is set at least in kid3
# disabled it for now because of a regression/bug in qt6 where dark theme isn't applied because prob. of this: https://bugreports.qt.io/browse/QTBUG-130884
# env = QT_QPA_PLATFORMTHEME,xdgdesktopportal
# as temp. fix, dont make qt apps ask xdg portal what theme/color scheme to use:
env = QT_QPA_PLATFORMTHEME,gtk3
###################
### PERMISSIONS ###
###################
# See https://wiki.hypr.land/Configuring/Permissions/
# Please note permission changes here require a Hyprland restart and are not applied on-the-fly
# for security reasons
# ecosystem {
# enforce_permissions = 1
# }
# permission = /usr/(bin|local/bin)/grim, screencopy, allow
# permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow
# permission = /usr/(bin|local/bin)/hyprpm, plugin, allow
#####################
### LOOK AND FEEL ###
#####################
# Refer to https://wiki.hypr.land/Configuring/Variables/
# https://wiki.hypr.land/Configuring/Variables/#general
general {
gaps_in = 5
gaps_out = 13
border_size = 2
# https://wiki.hypr.land/Configuring/Variables/#variable-types for info about colors
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
#col.active_border = rgba(29dbffee)
col.inactive_border = rgba(595959aa)
# Set to true enable resizing windows by clicking and dragging on borders and gaps
resize_on_border = false
# Please see https://wiki.hypr.land/Configuring/Tearing/ before you turn this on
allow_tearing = false
layout = dwindle
}
# https://wiki.hypr.land/Configuring/Variables/#decoration
decoration {
rounding = 10
rounding_power = 2
# Change transparency of focused and unfocused windows
active_opacity = 1.0
inactive_opacity = 1.0
#shadow {
# enabled = true
# range = 4
# render_power = 3
# color = rgba(1a1a1aee)
#}
shadow {
enabled = true
range = 100
render_power = 3
color = rgba(00000050)
scale = 0.99
offset = 0 9
}
# https://wiki.hypr.land/Configuring/Variables/#blur
blur {
enabled = true
size = 8
passes = 2
vibrancy = 0.1696
}
layerrule = blur on, match:namespace waybar
layerrule = ignore_alpha 0, blur on, match:namespace wofi
layerrule = ignore_alpha .3, blur on, match:namespace swaync-control-center
layerrule = ignore_alpha .3, blur on, match:namespace swaync-notification-window
}
# https://wiki.hypr.land/Configuring/Variables/#animations
animations {
enabled = yes, please :)
#enabled = no
# Default animations, see https://wiki.hypr.land/Configuring/Animations/ for more
bezier = easeOutQuint,0.23,1,0.32,1
bezier = easeInOutCubic,0.65,0.05,0.36,1
bezier = linear,0,0,1,1
bezier = almostLinear,0.5,0.5,0.75,1.0
bezier = quick,0.15,0,0.1,1
bezier = smoothQuick,0.08,0.93,0,1
animation = global, 1, 10, default
animation = border, 1, 5.39, easeOutQuint
animation = windows, 1, 4.79, easeOutQuint
animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
animation = windowsOut, 1, 1.49, linear, popin 87%
animation = fadeIn, 1, 1.73, almostLinear
animation = fadeOut, 1, 1.46, almostLinear
animation = fade, 1, 3.03, quick
animation = layers, 1, 3.81, easeOutQuint
animation = layersIn, 1, 4, easeOutQuint, fade
animation = layersOut, 1, 1.5, linear, fade
animation = fadeLayersIn, 1, 1.79, almostLinear
animation = fadeLayersOut, 1, 1.39, almostLinear
animation = workspaces, 1, 3, smoothQuick, slide
animation = workspacesIn, 1, 3, smoothQuick, slide
animation = workspacesOut, 1, 3, smoothQuick, slide
}
# Ref https://wiki.hypr.land/Configuring/Workspace-Rules/
# "Smart gaps" / "No gaps when only"
# uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# windowrule = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrule = rounding 0, floating:0, onworkspace:w[tv1]
# windowrule = bordersize 0, floating:0, onworkspace:f[1]
# windowrule = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hypr.land/Configuring/Dwindle-Layout/ for more
dwindle {
preserve_split = true # You probably want this
}
# See https://wiki.hypr.land/Configuring/Master-Layout/ for more
master {
new_status = master
}
# https://wiki.hypr.land/Configuring/Variables/#misc
misc {
force_default_wallpaper = 0 # Set to 0 or 1 to disable the anime mascot wallpapers
disable_hyprland_logo = true # If true disables the random hyprland logo / anime girl background. :(
anr_missed_pings = 3
}
ecosystem {
no_update_news = true
no_donation_nag = true
}
#cursor {
# no_hardware_cursors = true
# min_refresh_rate = 60
#}
#############
### INPUT ###
#############
# https://wiki.hypr.land/Configuring/Variables/#input
input {
kb_layout = de
kb_variant =
kb_model =
kb_options =
kb_rules =
follow_mouse = 1
sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
scroll_factor = 0.04
emulate_discrete_scroll = 1
touchpad {
natural_scroll = true
}
}
# For configuring gestures, see:
# https://wiki.hypr.land/Configuring/Gestures/
# Example per-device config
# See https://wiki.hypr.land/Configuring/Keywords/#per-device-input-configs for more
#device {
# name = mx-anywhere-3s-mouse
# scroll_factor = 0.08
#}
###################
### KEYBINDINGS ###
###################
# See https://wiki.hypr.land/Configuring/Keywords/
$mainMod = SUPER # Sets "Windows" key as main modifier
# Example binds, see https://wiki.hypr.land/Configuring/Binds/ for more
bind = $mainMod, T, exec, $terminal
bind = $mainMod, Q, killactive,
bind = $mainMod, M, exit,
bind = $mainMod, F, exec, $fileManager
bind = $mainMod, V, togglefloating,
bind = $mainMod, Y, exec, $menu
#bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod, J, layoutmsg, togglesplit # dwindle
bind = $mainMod, N, exec,~/scripts/joplin.sh
bind = $mainMod, B, exec, firefox
bind = $mainMod, E, exec,~/scripts/display_sleep.sh
# Move focus with mainMod + arrow keys
bind = $mainMod, left, movefocus, l
bind = $mainMod, right, movefocus, r
bind = $mainMod, up, movefocus, u
bind = $mainMod, down, movefocus, d
# Switch workspaces with mainMod + [0-9]
bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, workspace, 5
bind = $mainMod, 6, workspace, 6
bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10
# Move active window to a workspace with mainMod + SHIFT + [0-9]
bind = $mainMod SHIFT, 1, movetoworkspace, 1
bind = $mainMod SHIFT, 2, movetoworkspace, 2
bind = $mainMod SHIFT, 3, movetoworkspace, 3
bind = $mainMod SHIFT, 4, movetoworkspace, 4
bind = $mainMod SHIFT, 5, movetoworkspace, 5
bind = $mainMod SHIFT, 6, movetoworkspace, 6
bind = $mainMod SHIFT, 7, movetoworkspace, 7
bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10
# Resize windows with arrow keys
binde = $mainMod SHIFT, left, resizeactive, -40 0
binde = $mainMod SHIFT, right, resizeactive, 40 0
binde = $mainMod SHIFT, up, resizeactive, 0 -40
binde = $mainMod SHIFT, down, resizeactive, 0 40
# Example special workspace (scratchpad)
bind = $mainMod, S, togglespecialworkspace, magic
bind = $mainMod SHIFT, S, movetoworkspace, special:magic
# Scroll through existing workspaces with mainMod + scroll
#bind = $mainMod, mouse_down, workspace, e+1
#bind = $mainMod, mouse_up, workspace, e-1
# Move/resize windows with mainMod + LMB/RMB and dragging
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%-
bindel = , code:238, exec, brightnessctl -d smc::kbd_backlight s +20
bindel = , code:237, exec, brightnessctl -d smc::kbd_backlight s 20-
# Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next
bindl = , XF86AudioPause, exec, playerctl play-pause
bindl = , XF86AudioPlay, exec, playerctl play-pause
bindl = , XF86AudioPrev, exec, playerctl previous
# Screenshots with hyprshot
# Screenshot a window
bind = $mainMod, PRINT, exec, hyprshot -m window
# Screenshot a monitor
bind = , PRINT, exec, hyprshot -m region
# Screenshot a region
bind = $shiftMod, PRINT, exec, hyprshot -m output
# Hyprpicker
bind = $mainMod,P,exec,hyprpicker -a
##############################
### WINDOWS AND WORKSPACES ###
##############################
# See https://wiki.hypr.land/Configuring/Window-Rules/ for more
# See https://wiki.hypr.land/Configuring/Workspace-Rules/ for workspace rules
# workspacerules
workspace = name:1, monitor:DP-1, default:false
workspace = name:2, monitor:DP-1, default:false
workspace = name:3, monitor:DP-1, default:false
workspace = name:4, monitor:DP-1, default:false
workspace = name:5, monitor:DP-1, default:false
workspace = name:6, monitor:DP-2, default:false
workspace = name:7, monitor:DP-2, default:false
workspace = name:8, monitor:DP-2, default:false
workspace = name:9, monitor:DP-2, default:false
workspace = name:0, monitor:DP-2, default:false
# windowrules
windowrule = float on, size 1100 700, match:class ^(org.gnome.Nautilus)$
windowrule = float on, pin on, match:class ^(org.gnome.NautilusPreviewer)$
windowrule = float on, match:class ^(org.gnome.Loupe)$
windowrule = float on, match:class ^(org.rncbc.qpwgraph)$
windowrule = float on, scroll_mouse 0.2, match:class ^(org.keepassxc.KeePassXC)$
windowrule = float on, size 1400 900, scroll_mouse 0.05, match:class ^(@joplin/app-desktop)$
windowrule = float on, size 1200 750, scroll_mouse 0.2, match:class ^(ferdium)$
windowrule = float on, size 1200 750, match:class ^(Element)$
windowrule = float on, size 1200 750, match:class ^(org.gnome.Fractal)$
#windowrule = suppressevent[activatefocus activate],initialClass:^(photoshop.exe)$
windowrule = no_initial_focus on, match:initial_class ^(photoshop.exe)$
#windowrule = noblur,initialClass:^(photoshop.exe)$
#windowrule = noshadow,initialClass:^(photoshop.exe)$
#windowrule = noanim,initialClass:^(photoshop.exe)$
#windowrule = nodim,initialClass:^(photoshop.exe)$
#windowrule = nomaxsize,initialClass:^(photoshop.exe)$
# Per app scroll factor
windowrule = scroll_mouse 0.3, match:class ^(code)$
windowrule = scroll_mouse 0.2, match:class ^(org.gnome.Evolution)$
windowrule = scroll_mouse 0.4, match:class ^(libreoffice-.*)$
windowrule = scroll_mouse 0.2, match:class ^(virt-viewer)$
windowrule = scroll_mouse 0.2, match:class ^(RapidRAW)$
# Ignore maximize requests from apps. You'll probably like this.
windowrule = suppress_event maximize, match:class .*
# Fix some dragging issues with XWayland
windowrule = no_focus on, match:class ^$, match:title ^$, match:xwayland 1, match:float 1, match:fullscreen 0, match:pin 0
# Shadow only for floating windows
windowrule = no_shadow on, match:float 0
@@ -0,0 +1,12 @@
preload = /home/tobias/wall2.jpg
ipc = false
splash = false
wallpaper {
monitor = DP-1
path = /home/tobias/wall2.jpg
}
wallpaper {
monitor = DP-2
path = /home/tobias/wall2.jpg
}
@@ -0,0 +1,12 @@
max-gamma = 150
profile {
time = 8:00
identity = true
}
profile {
time = 22:00
temperature = 3500
gamma = 1.0
}
@@ -0,0 +1,62 @@
{
"$schema": "https://joplinapp.org/schema/settings.json",
"altInstanceId": "",
"editor.codeView": true,
"sync.target": 6,
"sync.6.path": "https://files.70b1.de/joplin",
"sync.6.username": "tobias",
"richTextBannerDismissed": true,
"locale": "de_DE",
"ocr.enabled": false,
"theme": 2,
"themeAutoDetect": false,
"layoutButtonSequence": 1,
"notes.sortOrder.field": "user_updated_time",
"notes.sortOrder.reverse": true,
"notes.perFieldReverse": {
"user_updated_time": true,
"user_created_time": true,
"title": false,
"order": false,
"todo_due": true,
"todo_completed": true
},
"notes.listRendererId": "compact",
"markdown.plugin.softbreaks": false,
"markdown.plugin.typographer": false,
"showTrayIcon": true,
"style.editor.fontSize": 15,
"style.editor.fontFamily": "SF Mono",
"style.editor.monospaceFontFamily": "SF Mono",
"style.editor.contentMaxWidth": 0,
"ui.layout": {
"key": "root",
"children": [
{
"key": "sideBar",
"width": 224,
"visible": true
},
{
"key": "noteList",
"width": 297,
"visible": true
},
{
"key": "editor",
"visible": true
}
],
"visible": true
},
"noteVisiblePanes": [
"editor"
],
"editor.inlineRendering": true,
"editor.imageRendering": true,
"api.token": "51dcd22d8da20ca9f2d709e9660c03893fbabc387b19d904c10bd1d5d2f77211bc9477baffbe500ac1eaa77aaaf1005280fce282bd72de36ef7a43626bacad4e",
"spellChecker.languages": [
"de"
],
"windowContentZoomFactor": 100
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,33 @@
[General]
ConfigVersion=2
UpdateCheckMessageShown=true
[Browser]
CustomProxyLocation=
Enabled=true
[GUI]
ApplicationTheme=dark
CheckForUpdates=false
CompactMode=false
HidePreviewPanel=true
MinimizeOnClose=true
ShowTrayIcon=true
TrayIconAppearance=monochrome-light
[KeeShare]
Active="<?xml version=\"1.0\"?><KeeShare><Active/></KeeShare>\n"
Own="<?xml version=\"1.0\"?><KeeShare><PrivateKey>MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCqbx6OoGAa2vC/qTRfKeu4TG0fVZTiiVZe3QsGgUYrHoexwLgqOr0bysWr2fMi5v2FVEeEs7zGRAXYtZJXscVRjK62BdIg8rJfg+bCD3Mzwf+FtNniT4eQOczR1csNNJ4ZvtVRO5znJ9ZGrOZIi+lEIsvEqFpDUcIE3YieYCx8/rsc2hdo8aksjs58yFv5xdfnSmcN3sL4mGGHOS+DHFCpWDqYORgRwBVJIo53zo4/ZDj3Ng8Kbi2KcaMS+yRqbSiLsOy0FCh9xTis0ZLIzsonT80rUBxMchs2rKFKXvoF0RGvCns3y6EsfLijdTQhQLAhgtvKTlBkPdoPfCdf3VidAgMBAAECggEACrw1EIbJhueDgo8F3XimgFVQCkk5t4svBYqmxyIdaVni8i9RaleI0ddT3B8+UVR7Y4qLdrBbk6F1PNEzBpML+rcByjVTpv+ifKGyR0bx2rC9h458quSXhV4eqJju0UYfLz/178fxeh3oQUtite8aIlCOxTRVeygLMINDt7YXF0hZ74f7LmjANYGIGTkzAdMfQdF4jZBrBZlsFdCFUeo7HfxQscSr89XwIDcvOSxawoexatiRzUtuMJjITM6lAtCVwO2Ldke6MBkkvZF6+RX0qp1a3P95K78ZEBof69LQ9/4LFDhVM2Xc7u4SZklk032m3wajHM4Bx56fHhO8o+brgQKBgQDNefwDmWxMdww/lgg/RBdSz6a/iIzdseAVSYUQj/2yFldfjOMQEpCHBd5tZz6h2hfFAlmvRnDmAJIEPAeXj5/bgbu08sGSCPAnhGtwJ+6dw0toNLoS3dAheK9wafpwm1WZDuVNCmXZHxXLayAVhg+Z4oA9JLKToOqbZJWyak8vhwKBgQDUV1Z3oaI5GKB5Za1+QjNp/sm1eNtJHsEfox+V3k9sc8hhHdsiQoqYy7414TViitoZgSQGGX6NPgfAOrzdIuOXXRonpFmBIkTkFyUcBQj+tj+W7QPLN4vZDC3PRHCkh1GbNsFfD++u8uvOMKfHe0lAIGeyR0Z95wVugA55cluXuwKBgB9HCk2h9RJOrNahB/BZdRNt+Hv/VTIJ+YpD/rVetcd+Dx7EW2v+53EmO417wdTxVdzvVqePmW/pdlCesqkne7X2MZSBv2VzZtsdFR2ldnUdXUUngYuNqDjwHgSGnVC21HjQA6eOhaJfUPn9/IxKM+XAzLSB+YzvWcb9sKvP8u3RAoGBALcNJ6Rv+bpA6a5dogfTKCF7HQZNTrUlRxVv+X2oLU3wLlDSfSN2u6ZnFe263Nu7mbMc6iI7/iXi0Km9uSzls8+72h1MiEBTe5IqBbq2+H8kO4NvhbK9itissB0bAgREB2zH8kFyKozmK7QPq8PDG22lwd8lpLZK3xrYWCIIHL+bAoGBAKVogLExSXSFHuIDqZGRKYQmMX3ta2eEHNSzVOn26+o3okkj1a9gZnOYC2gfvhSNrCLVtmC+2N/yOOhRqSZVfTaCNCWE//+l60aQD/N/RskDMB8WcnrrE3kQGmv1LSg0iiO5mQJeSoUO33/hr+A8FikOHnn7oj2yPYcOvkpYWhbQ</PrivateKey><PublicKey><Signer>tobias</Signer><Key>MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCqbx6OoGAa2vC/qTRfKeu4TG0fVZTiiVZe3QsGgUYrHoexwLgqOr0bysWr2fMi5v2FVEeEs7zGRAXYtZJXscVRjK62BdIg8rJfg+bCD3Mzwf+FtNniT4eQOczR1csNNJ4ZvtVRO5znJ9ZGrOZIi+lEIsvEqFpDUcIE3YieYCx8/rsc2hdo8aksjs58yFv5xdfnSmcN3sL4mGGHOS+DHFCpWDqYORgRwBVJIo53zo4/ZDj3Ng8Kbi2KcaMS+yRqbSiLsOy0FCh9xTis0ZLIzsonT80rUBxMchs2rKFKXvoF0RGvCns3y6EsfLijdTQhQLAhgtvKTlBkPdoPfCdf3VidAgMBAAECggEACrw1EIbJhueDgo8F3XimgFVQCkk5t4svBYqmxyIdaVni8i9RaleI0ddT3B8+UVR7Y4qLdrBbk6F1PNEzBpML+rcByjVTpv+ifKGyR0bx2rC9h458quSXhV4eqJju0UYfLz/178fxeh3oQUtite8aIlCOxTRVeygLMINDt7YXF0hZ74f7LmjANYGIGTkzAdMfQdF4jZBrBZlsFdCFUeo7HfxQscSr89XwIDcvOSxawoexatiRzUtuMJjITM6lAtCVwO2Ldke6MBkkvZF6+RX0qp1a3P95K78ZEBof69LQ9/4LFDhVM2Xc7u4SZklk032m3wajHM4Bx56fHhO8o+brgQKBgQDNefwDmWxMdww/lgg/RBdSz6a/iIzdseAVSYUQj/2yFldfjOMQEpCHBd5tZz6h2hfFAlmvRnDmAJIEPAeXj5/bgbu08sGSCPAnhGtwJ+6dw0toNLoS3dAheK9wafpwm1WZDuVNCmXZHxXLayAVhg+Z4oA9JLKToOqbZJWyak8vhwKBgQDUV1Z3oaI5GKB5Za1+QjNp/sm1eNtJHsEfox+V3k9sc8hhHdsiQoqYy7414TViitoZgSQGGX6NPgfAOrzdIuOXXRonpFmBIkTkFyUcBQj+tj+W7QPLN4vZDC3PRHCkh1GbNsFfD++u8uvOMKfHe0lAIGeyR0Z95wVugA55cluXuwKBgB9HCk2h9RJOrNahB/BZdRNt+Hv/VTIJ+YpD/rVetcd+Dx7EW2v+53EmO417wdTxVdzvVqePmW/pdlCesqkne7X2MZSBv2VzZtsdFR2ldnUdXUUngYuNqDjwHgSGnVC21HjQA6eOhaJfUPn9/IxKM+XAzLSB+YzvWcb9sKvP8u3RAoGBALcNJ6Rv+bpA6a5dogfTKCF7HQZNTrUlRxVv+X2oLU3wLlDSfSN2u6ZnFe263Nu7mbMc6iI7/iXi0Km9uSzls8+72h1MiEBTe5IqBbq2+H8kO4NvhbK9itissB0bAgREB2zH8kFyKozmK7QPq8PDG22lwd8lpLZK3xrYWCIIHL+bAoGBAKVogLExSXSFHuIDqZGRKYQmMX3ta2eEHNSzVOn26+o3okkj1a9gZnOYC2gfvhSNrCLVtmC+2N/yOOhRqSZVfTaCNCWE//+l60aQD/N/RskDMB8WcnrrE3kQGmv1LSg0iiO5mQJeSoUO33/hr+A8FikOHnn7oj2yPYcOvkpYWhbQ</Key></PublicKey></KeeShare>\n"
QuietSuccess=true
[PasswordGenerator]
AdditionalChars=
ExcludedChars=
Length=20
LowerCase=true
SpecialChars=false
UpperCase=true
[Security]
ClearClipboard=false
LockDatabaseIdle=false
@@ -0,0 +1,2 @@
background_opacity .7
window_margin_width 5
+39
View File
@@ -0,0 +1,39 @@
[Default Applications]
image/jpeg=org.gnome.Loupe.desktop
image/png=org.gnome.Loupe.desktop
x-scheme-handler/tonsite=org.telegram.desktop._bed96f4b363d7710ea902a60dee70952.desktop
hoppscotch=hoppscotch-handler.desktop
x-scheme-handler/http=firefox.desktop
application/xhtml+xml=firefox.desktop
text/html=firefox.desktop
x-scheme-handler/https=firefox.desktop
application/x-desktop=code.desktop
inode/directory=org.gnome.Nautilus.desktop
text/plain=code.desktop
audio/flac=mpv.desktop
image/heif=org.gnome.Loupe.desktop
image/webp=org.gnome.Loupe.desktop
text/csv=libreoffice-calc.desktop
audio/x-opus+ogg=mpv.desktop
text/markdown=code.desktop
[Added Associations]
image/jpeg=org.gnome.Loupe.desktop;
image/png=org.gnome.Loupe.desktop;
x-scheme-handler/tonsite=org.telegram.desktop._bed96f4b363d7710ea902a60dee70952.desktop;
x-scheme-handler/http=firefox.desktop;
application/xhtml+xml=firefox.desktop;
text/html=firefox.desktop;
x-scheme-handler/https=firefox.desktop;
application/x-desktop=code.desktop;
text/plain=code.desktop;
audio/flac=mpv.desktop;
image/heif=org.gnome.Loupe.desktop;
application/octet-stream=code.desktop;
image/webp=org.gnome.Loupe.desktop;
text/csv=libreoffice-calc.desktop;
application/sketch=lunacy.desktop;
audio/x-opus+ogg=mpv.desktop;
application/lunacy=lunacy.desktop;
application/gzip=org.gnome.FileRoller.desktop;
text/markdown=code.desktop;
+1
View File
@@ -0,0 +1 @@
hwdec=auto
@@ -0,0 +1,6 @@
context.modules = [
{
name = libpipewire-module-raop-discover
args = { }
}
]
@@ -0,0 +1,17 @@
context.modules = [
{ name = libpipewire-module-roc-sink
args = {
fec.code = rs8m
#fec.code = disable
remote.ip = 192.168.1.235
remote.source.port = 10001
remote.repair.port = 10002
remote.control.port = 10003
sink.name = "Studio Raspi"
sink.props = {
node.name = "studio-raspi-roc-sink"
node.description = "Studio Raspi"
}
}
}
]
+349
View File
@@ -0,0 +1,349 @@
* {
all: unset;
font-size: 14px;
font-family: "SF Pro Display";
transition: 200ms;
}
trough highlight {
background: #cdd6f4;
}
scale trough {
margin: 0rem 1rem;
background-color: #313244;
min-height: 8px;
min-width: 70px;
}
slider {
background-color: #89b4fa;
}
.floating-notifications.background .notification-row .notification-background {
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.8), inset 0 0 0 1px #313244;
border-radius: 10px;
margin: 18px;
background-color: rgba(21, 18, 27, .6);
color: #cdd6f4;
padding: 0;
}
.floating-notifications.background .notification-row .notification-background .notification {
padding: 7px;
border-radius: 10px;
}
.floating-notifications.background .notification-row .notification-background .notification.critical {
box-shadow: inset 0 0 7px 0 #f38ba8;
}
.floating-notifications.background .notification-row .notification-background .notification .notification-content {
margin: 7px;
}
.floating-notifications.background .notification-row .notification-background .notification .notification-content .summary {
color: #cdd6f4;
font-weight: bold;
margin-left: 5px;
}
.floating-notifications.background .notification-row .notification-background .notification .notification-content .time {
color: #a6adc8;
}
.floating-notifications.background .notification-row .notification-background .notification .notification-content .body {
color: #cdd6f4;
margin-left: 5px;
}
.floating-notifications.background .notification-row .notification-background .notification > *:last-child > * {
min-height: 3.4em;
}
.floating-notifications.background .notification-row .notification-background .notification > *:last-child > * .notification-action {
border-radius: 10px;
color: #cdd6f4;
background-color: #313244;
box-shadow: inset 0 0 0 1px #45475a;
margin: 7px;
}
.floating-notifications.background .notification-row .notification-background .notification > *:last-child > * .notification-action:hover {
box-shadow: inset 0 0 0 1px #45475a;
background-color: #313244;
color: #cdd6f4;
}
.floating-notifications.background .notification-row .notification-background .notification > *:last-child > * .notification-action:active {
box-shadow: inset 0 0 0 1px #45475a;
background-color: #74c7ec;
color: #cdd6f4;
}
.floating-notifications.background .notification-row .notification-background .close-button {
margin: 7px;
padding: 2px;
border-radius: 6px;
color: #1e1e2e;
background-color: #f38ba8;
}
.floating-notifications.background .notification-row .notification-background .close-button:hover {
background-color: #eba0ac;
color: #1e1e2e;
}
.floating-notifications.background .notification-row .notification-background .close-button:active {
background-color: #f38ba8;
color: #1e1e2e;
}
.control-center {
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.8), inset 0 0 0 1px #313244;
border-radius: 10px;
margin: 18px;
background-color: rgba(21, 18, 27, .6);
color: #cdd6f4;
padding: 14px;
}
.control-center .widget-title > label {
color: #cdd6f4;
font-size: 1.3em;
font-weight: bold;
}
.control-center .widget-title button {
border-radius: 10px;
color: #cdd6f4;
background-color: #313244;
box-shadow: inset 0 0 0 1px #45475a;
padding: 8px;
}
.control-center .widget-title button:hover {
box-shadow: inset 0 0 0 1px #45475a;
background-color: #585b70;
color: #cdd6f4;
}
.control-center .widget-title button:active {
box-shadow: inset 0 0 0 1px #45475a;
background-color: #74c7ec;
color: #1e1e2e;
}
.control-center .notification-row .notification-background {
border-radius: 10px;
color: #cdd6f4;
background-color: #313244;
box-shadow: inset 0 0 0 1px #45475a;
margin-top: 14px;
}
.control-center .notification-row .notification-background .notification {
padding: 7px;
border-radius: 10px;
}
.control-center .notification-row .notification-background .notification.critical {
box-shadow: inset 0 0 7px 0 #f38ba8;
}
.control-center .notification-row .notification-background .notification .notification-content {
margin: 7px;
}
.control-center .notification-row .notification-background .notification .notification-content .summary {
color: #cdd6f4;
font-weight: bold;
margin-left: 5px;
}
.control-center .notification-row .notification-background .notification .notification-content .time {
color: #a6adc8;
}
.control-center .notification-row .notification-background .notification .notification-content .body {
color: #cdd6f4;
margin-left: 5px;
}
.control-center .notification-row .notification-background .notification > *:last-child > * {
min-height: 3.4em;
}
.control-center .notification-row .notification-background .notification > *:last-child > * .notification-action {
border-radius: 10px;
color: #cdd6f4;
background-color: #11111b;
box-shadow: inset 0 0 0 1px #45475a;
margin: 7px;
}
.control-center .notification-row .notification-background .notification > *:last-child > * .notification-action:hover {
box-shadow: inset 0 0 0 1px #45475a;
background-color: #313244;
color: #cdd6f4;
}
.control-center .notification-row .notification-background .notification > *:last-child > * .notification-action:active {
box-shadow: inset 0 0 0 1px #45475a;
background-color: #74c7ec;
color: #cdd6f4;
}
.control-center .notification-row .notification-background .close-button {
margin: 7px;
padding: 2px;
border-radius: 6.3px;
color: #1e1e2e;
background-color: #eba0ac;
}
.close-button {
border-radius: 6.3px;
}
.control-center .notification-row .notification-background .close-button:hover {
background-color: #f38ba8;
color: #1e1e2e;
}
.control-center .notification-row .notification-background .close-button:active {
background-color: #f38ba8;
color: #1e1e2e;
}
.control-center .notification-row .notification-background:hover {
box-shadow: inset 0 0 0 1px #45475a;
background-color: #3f4054;
color: #cdd6f4;
}
.control-center .notification-row .notification-background:active {
box-shadow: inset 0 0 0 1px #45475a;
background-color: #74c7ec;
color: #cdd6f4;
}
.notification.critical progress {
background-color: #f38ba8;
}
.notification.low progress,
.notification.normal progress {
background-color: #89b4fa;
}
.control-center-dnd {
margin-top: 5px;
border-radius: 10px;
background: #313244;
border: 1px solid #45475a;
box-shadow: none;
}
.control-center-dnd:checked {
background: #313244;
}
.control-center-dnd slider {
background: #45475a;
border-radius: 8px;
}
.widget-dnd {
margin: 0px;
font-size: 1.1rem;
}
.widget-dnd > switch {
font-size: initial;
border-radius: 8px;
background: #313244;
border: 1px solid #45475a;
box-shadow: none;
}
.widget-dnd > switch:checked {
background: #313244;
}
.widget-dnd > switch slider {
background: #45475a;
border-radius: 8px;
border: 1px solid #6c7086;
}
.widget-mpris .widget-mpris-player {
background: #313244;
padding: 7px;
}
.widget-mpris .widget-mpris-title {
font-size: 1.2rem;
}
.widget-mpris .widget-mpris-subtitle {
font-size: 0.8rem;
}
.widget-menubar > box > .menu-button-bar > button > label {
font-size: 3rem;
padding: 0.5rem 2rem;
}
.widget-menubar > box > .menu-button-bar > :last-child {
color: #f38ba8;
}
.power-buttons button:hover,
.powermode-buttons button:hover,
.screenshot-buttons button:hover {
background: #313244;
}
.control-center .widget-label > label {
color: #cdd6f4;
font-size: 2rem;
}
.widget-buttons-grid {
padding-top: 1rem;
}
.widget-buttons-grid > flowbox > flowboxchild > button label {
font-size: 2.5rem;
}
.widget-volume {
padding-top: 1rem;
}
.widget-volume label {
font-size: 1.5rem;
color: #74c7ec;
}
.widget-volume trough highlight {
background: #74c7ec;
}
.widget-backlight trough highlight {
background: #f9e2af;
}
.widget-backlight label {
font-size: 1.5rem;
color: #f9e2af;
}
.widget-backlight .KB {
padding-bottom: 1rem;
}
.image {
padding-right: 0.5rem;
}
@@ -0,0 +1,15 @@
[Unit]
Description=Shairport Sync - AirPlay Audio Receiver
After=sound.target
#Requires=avahi-daemon.service
#After=avahi-daemon.service
Wants=network-online.target
After=network.target network-online.target
[Service]
ExecStart=/usr/bin/shairport-sync --log-to-syslog
#User=shairport-sync
#Group=shairport-sync
[Install]
WantedBy=default.target
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,217 @@
{
"layer": "top",
"position": "top",
"mod": "dock",
"exclusive": true,
"passthrough": false,
"gtk-layer-shell": true,
"height": 28,
"modules-left": [
"clock",
"custom/weather",
"hyprland/workspaces",
"custom/apps",
"custom/files"
],
"modules-center": [
"hyprland/window"
],
"modules-right": [
"tray",
"custom/network",
"temperature",
"cpu",
"memory",
"battery",
"custom/studio-sound",
"bluetooth",
"wireplumber",
"custom/hyprsunset",
"custom/notificationbar",
"privacy"
],
"privacy": {
"icon-spacing": 4,
"icon-size": 13,
"transition-duration": 250,
"modules": [
{
"type": "screenshare",
"tooltip": true,
"tooltip-icon-size": 24
},
{
"type": "audio-in",
"tooltip": true,
"tooltip-icon-size": 24
}
],
"ignore-monitor": true
},
"hyprland/workspaces": {
"format": "{icon}",
"on-scroll-up": "hyprctl dispatch workspace e+1",
"on-scroll-down": "hyprctl dispatch workspace e-1",
"format-icons": {
"1": "1",
"2": "2",
"3": "3",
"4": "4",
"5": "5"
},
"persistent_workspaces": {
"*": 1
}
},
"hyprland/window": {
"format": "{}",
"separate-outputs": true
},
"custom/apps": {
"format": "Apps",
"tooltip": false,
"on-click": "wofi --show drun"
},
"custom/files": {
"format": "Files",
"tooltip": false,
"on-click": "nautilus"
},
"custom/weather": {
"tooltip": true,
"format": "{}",
"interval": 3600,
"exec": "~/.config/waybar/scripts/waybar-wttr.py",
"return-type": "json"
},
"temperature": {
"thermal-zone": 2,
"hwmon-path": "/sys/class/hwmon/hwmon5/temp1_input",
"critical-threshold": 80,
"format-critical": " {temperatureC}°C",
"format": " {temperatureC}°C",
"interval": 2,
"tooltip": true
},
"cpu": {
"format": " {usage}%",
"tooltip": true,
"interval": 2,
"states": {
"warning": 70,
"critical": 90
}
},
"memory": {
"format": " {}%",
"format-alt": " {used:0.1f}G/{total:0.1f}G",
"tooltip": true,
"tooltip-format": "Used: {used:0.2f}GB ({percentage}%)\nAvailable: {avail:0.2f}GB\nTotal: {total:0.2f}GB",
"interval": 2,
"states": {
"warning": 70,
"critical": 90
}
},
"tray": {
"icon-size": 16,
"spacing": 25,
"icons": {
"blueman": "/usr/share/icons/WhiteSur-dark/devices@2x/32/network-bluetooth.svg",
"nm-applet": "/usr/share/icons/WhiteSur-dark/devices@2x/24/network-wired.svg",
"pasystray": "/usr/share/icons/WhiteSur-dark/devices@2x/16/audio-speakers.svg"
}
},
"custom/notificationbar": {
"format": "",
"on-click": "swaync-client -t"
},
"clock": {
"timezone": "Europe/Berlin",
"format": "{:%H:%M %a, %b %e}",
"tooltip-format": "<big>{:%Y %B}</big>\n<tt>{calendar}</tt>"
},
"backlight": {
"device": "intel_backlight",
"format": "{icon} {percent}%",
"format-icons": [
"󰃞",
"󰃟",
"󰃠"
],
"on-scroll-up": "brightnessctl -q set 1%+",
"on-scroll-down": "brightnessctl -q set 1%-"
},
"battery": {
"states": {
"good": 95,
"warning": 20,
"critical": 10
},
"format": "{icon} {capacity}%",
"format-charging": " {capacity}%",
"format-plugged": " {capacity}%",
"format-alt": "{time} {icon}",
"format-icons": [
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
""
]
},
"wireplumber": {
"format": " {volume}%",
"format-muted": "",
"on-click": "qpwgraph",
"max-volume": 100,
"scroll-step": 0.2
},
"custom/network": {
"exec": "~/.config/waybar/scripts/network.sh",
"return-type": "json",
"interval": 2,
"format": "{}"
//"on-click": "nmcli device wifi list",
//"on-click-right": "nm-connection-editor"
},
"custom/hyprsunset": {
"format": "{}",
"exec": "~/.config/waybar/scripts/hyprsunset.sh",
"on-click": "~/.config/waybar/scripts/hyprsunset.sh toggle",
"signal": 8,
"tooltip": true,
"return-type": "json"
},
"custom/studio-sound": {
"format": "{}",
"exec": "~/.config/waybar/scripts/studio-sound.py",
"on-click": "~/.config/waybar/scripts/studio-sound.py toggle",
"interval": 30,
"return-type": "json",
"tooltip": true
},
"bluetooth": {
"format": " {status}",
"format-disabled": "",
"format-connected": " {num_connections}",
"tooltip-format": "{device_alias}",
"tooltip-format-connected": " {device_enumerate}",
"tooltip-format-enumerate-connected": "{device_alias}"
}
}
+63
View File
@@ -0,0 +1,63 @@
#!/bin/bash
# Waybar Hyprsunset Module Script
# Place this in ~/.config/waybar/scripts/hyprsunset.sh
# Make executable: chmod +x ~/.config/waybar/scripts/hyprsunset.sh
TEMP=3500 # Default temperature when enabled
STATE_FILE="/tmp/hyprsunset_state"
# Initialize state file if it doesn't exist
if [ ! -f "$STATE_FILE" ]; then
echo "disabled" > "$STATE_FILE"
fi
get_status() {
# Check if hyprsunset is currently active
if [ -f "$STATE_FILE" ]; then
state=$(cat "$STATE_FILE" 2>/dev/null)
if [ "$state" = "enabled" ]; then
echo "enabled"
else
echo "disabled"
fi
else
echo "disabled"
fi
}
toggle_hyprsunset() {
current_status=$(get_status)
if [ "$current_status" = "enabled" ]; then
# Disable hyprsunset
hyprctl hyprsunset identity
echo "disabled" > "$STATE_FILE"
else
# Enable hyprsunset
hyprctl hyprsunset temperature "$TEMP"
echo "enabled" > "$STATE_FILE"
fi
# Signal Waybar to update the module
pkill -SIGRTMIN+8 waybar
}
output_json() {
status=$(get_status)
if [ "$status" = "enabled" ]; then
printf '{"text":"","tooltip":"Sunset: ON (%sK)","class":"enabled"}\n' "$TEMP"
else
printf '{"text":"","tooltip":"Sunset: OFF","class":"disabled"}\n'
fi
}
case "$1" in
"toggle")
toggle_hyprsunset
;;
*)
output_json
;;
esac
+112
View File
@@ -0,0 +1,112 @@
#!/bin/bash
INTERFACE="br0"
TEMP_FILE="/tmp/waybar_network_$INTERFACE"
MAX_AGE=10
# Function to format bytes/s to human readable with max 2 digits
format_rate() {
local rate=$1
local unit="K"
local value
# Convert to KB/s first
value=$(( (rate * 10) / 1024 ))
# If KB/s would be >= 1000 (100.0K), convert to MB/s
if [ $value -ge 1000 ]; then
unit="M"
value=$(( (rate * 10) / 1048576 )) # 1024*1024
# If MB/s would be >= 1000 (100.0M), convert to GB/s
if [ $value -ge 1000 ]; then
unit="G"
value=$(( (rate * 10) / 1073741824 )) # 1024*1024*1024
fi
fi
# Split into whole and decimal parts
local whole=$((value / 10))
local decimal=$((value % 10))
# Format with appropriate spacing
if [ $whole -lt 10 ]; then
printf "%d.%d%s" "$whole" "$decimal" "$unit"
else
printf "%2d%s" "$whole" "$unit"
fi
}
# Check if interface exists
if [ ! -d "/sys/class/net/$INTERFACE" ]; then
echo '{"text":"󰈀 No Interface","tooltip":"Interface '$INTERFACE' not found"}'
exit 1
fi
# Get current values
RX_BYTES=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes)
TX_BYTES=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
CURRENT_TIME=$(date +%s)
# Check if temp file exists and is recent
TEMP_FILE_VALID=0
if [ -f "$TEMP_FILE" ]; then
read PREV_RX PREV_TX PREV_TIME < "$TEMP_FILE"
TIME_DIFF=$((CURRENT_TIME - PREV_TIME))
# Accept temp file if it's recent (0 seconds is OK, negative or too old is not)
if [ $TIME_DIFF -ge 0 ] && [ $TIME_DIFF -le $MAX_AGE ]; then
TEMP_FILE_VALID=1
fi
fi
# If no valid temp file, initialize
if [ $TEMP_FILE_VALID -eq 0 ]; then
echo "$RX_BYTES $TX_BYTES $CURRENT_TIME" > "$TEMP_FILE"
echo '{"text":"'${INTERFACE}' ↑0.0K ↓0.0K","tooltip":"Upload: 0.0 KB/s\\nDownload: 0.0 KB/s"}'
exit 0
fi
# If TIME_DIFF is 0, return the last calculated result without updating temp file
if [ $TIME_DIFF -eq 0 ]; then
# Try to read cached result from a secondary file
CACHE_FILE="/tmp/waybar_network_cache_$INTERFACE"
if [ -f "$CACHE_FILE" ]; then
cat "$CACHE_FILE"
exit 0
else
# No cache, show 0.0K
echo '{"text":"'${INTERFACE}' ↑0.0K ↓0.0K","tooltip":"Upload: 0.0 KB/s\\nDownload: 0.0 KB/s"}'
exit 0
fi
fi
# Calculate rates (bytes per second)
RX_RATE=$(( (RX_BYTES - PREV_RX) / TIME_DIFF ))
TX_RATE=$(( (TX_BYTES - PREV_TX) / TIME_DIFF ))
# Handle negative values (counter reset) or unrealistic high values
if [ $RX_RATE -lt 0 ] || [ $RX_RATE -gt 1073741824 ]; then RX_RATE=0; fi
if [ $TX_RATE -lt 0 ] || [ $TX_RATE -gt 1073741824 ]; then TX_RATE=0; fi
# Format rates with auto-scaling
TX_FORMATTED=$(format_rate $TX_RATE)
RX_FORMATTED=$(format_rate $RX_RATE)
# Calculate tooltip values (always in KB/s for consistency)
RX_KB_TENTHS=$(( (RX_RATE * 10) / 1024 ))
TX_KB_TENTHS=$(( (TX_RATE * 10) / 1024 ))
RX_WHOLE=$((RX_KB_TENTHS / 10))
RX_DECIMAL=$((RX_KB_TENTHS % 10))
TX_WHOLE=$((TX_KB_TENTHS / 10))
TX_DECIMAL=$((TX_KB_TENTHS % 10))
# Format output with auto-scaled units
RESULT=$(printf '{"text":"'${INTERFACE}' ↑%4s ↓%4s","tooltip":"Upload: %d.%d KB/s\\nDownload: %d.%d KB/s"}' \
"$TX_FORMATTED" "$RX_FORMATTED" \
"$TX_WHOLE" "$TX_DECIMAL" "$RX_WHOLE" "$RX_DECIMAL")
echo "$RESULT"
# Store current values for next iteration AND cache the result
echo "$RX_BYTES $TX_BYTES $CURRENT_TIME" > "$TEMP_FILE"
echo "$RESULT" > "/tmp/waybar_network_cache_$INTERFACE"
+78
View File
@@ -0,0 +1,78 @@
#!/bin/bash
INTERFACE="br0"
TEMP_FILE="/tmp/waybar_network_$INTERFACE"
MAX_AGE=10
# Check if interface exists
if [ ! -d "/sys/class/net/$INTERFACE" ]; then
echo '{"text":"󰈀 No Interface","tooltip":"Interface '$INTERFACE' not found"}'
exit 1
fi
# Get current values
RX_BYTES=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes)
TX_BYTES=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
CURRENT_TIME=$(date +%s)
# Check if temp file exists and is recent
TEMP_FILE_VALID=0
if [ -f "$TEMP_FILE" ]; then
read PREV_RX PREV_TX PREV_TIME < "$TEMP_FILE"
TIME_DIFF=$((CURRENT_TIME - PREV_TIME))
# Accept temp file if it's recent (0 seconds is OK, negative or too old is not)
if [ $TIME_DIFF -ge 0 ] && [ $TIME_DIFF -le $MAX_AGE ]; then
TEMP_FILE_VALID=1
fi
fi
# If no valid temp file, initialize
if [ $TEMP_FILE_VALID -eq 0 ]; then
echo "$RX_BYTES $TX_BYTES $CURRENT_TIME" > "$TEMP_FILE"
echo '{"text":"'${INTERFACE}' ↑ 0.0K ↓ 0.0K","tooltip":"Upload: 0.0 KB/s\\nDownload: 0.0 KB/s"}'
exit 0
fi
# If TIME_DIFF is 0, return the last calculated result without updating temp file
if [ $TIME_DIFF -eq 0 ]; then
# Try to read cached result from a secondary file
CACHE_FILE="/tmp/waybar_network_cache_$INTERFACE"
if [ -f "$CACHE_FILE" ]; then
cat "$CACHE_FILE"
exit 0
else
# No cache, show 0.0K
echo '{"text":"'${INTERFACE}' ↑ 0.0K ↓ 0.0K","tooltip":"Upload: 0.0 KB/s\\nDownload: 0.0 KB/s"}'
exit 0
fi
fi
# Calculate rates (bytes per second)
RX_RATE=$(( (RX_BYTES - PREV_RX) / TIME_DIFF ))
TX_RATE=$(( (TX_BYTES - PREV_TX) / TIME_DIFF ))
# Handle negative values (counter reset) or unrealistic high values
if [ $RX_RATE -lt 0 ] || [ $RX_RATE -gt 1073741824 ]; then RX_RATE=0; fi
if [ $TX_RATE -lt 0 ] || [ $TX_RATE -gt 1073741824 ]; then TX_RATE=0; fi
# Convert to KB/s with one decimal place
RX_KB_TENTHS=$(( (RX_RATE * 10) / 1024 ))
TX_KB_TENTHS=$(( (TX_RATE * 10) / 1024 ))
# Split into whole and decimal parts
RX_WHOLE=$((RX_KB_TENTHS / 10))
RX_DECIMAL=$((RX_KB_TENTHS % 10))
TX_WHOLE=$((TX_KB_TENTHS / 10))
TX_DECIMAL=$((TX_KB_TENTHS % 10))
# Format output with fixed width
RESULT=$(printf '{"text":"'${INTERFACE}' ↑%2d.%dK ↓%2d.%dK","tooltip":"Upload: %d.%d KB/s\\nDownload: %d.%d KB/s"}' \
"$TX_WHOLE" "$TX_DECIMAL" "$RX_WHOLE" "$RX_DECIMAL" \
"$TX_WHOLE" "$TX_DECIMAL" "$RX_WHOLE" "$RX_DECIMAL")
echo "$RESULT"
# Store current values for next iteration AND cache the result
echo "$RX_BYTES $TX_BYTES $CURRENT_TIME" > "$TEMP_FILE"
echo "$RESULT" > "/tmp/waybar_network_cache_$INTERFACE"
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/env python3
"""
Waybar module for controlling Studio Sound power outlet
Toggles power on click and shows current status
"""
import json
import requests
import sys
import os
STATUS_URL = 'http://192.168.1.75/cm?cmnd=status'
TOGGLE_URL = 'http://192.168.1.75/ay?o=1'
CACHE_FILE = '/tmp/studio_sound_status.json'
TIMEOUT = 2 # seconds
def get_status():
"""Fetch the current power status from the device"""
try:
response = requests.get(STATUS_URL, timeout=TIMEOUT)
response.raise_for_status()
data = response.json()
return data.get('Status', {}).get('Power', 0) == 1
except:
# Return cached status if available
if os.path.exists(CACHE_FILE):
try:
with open(CACHE_FILE, 'r') as f:
cached = json.load(f)
return cached.get('power', False)
except:
pass
return False
def toggle_power():
"""Toggle the power state"""
try:
requests.get(TOGGLE_URL, timeout=TIMEOUT)
# Give device time to process
import time
time.sleep(0.5)
return get_status()
except:
return False
def save_cache(power_state):
"""Save current state to cache file"""
try:
with open(CACHE_FILE, 'w') as f:
json.dump({'power': power_state}, f)
except:
pass
def main():
# Check if this is a click event
if len(sys.argv) > 1 and sys.argv[1] == 'toggle':
power_state = toggle_power()
else:
power_state = get_status()
# Save to cache
save_cache(power_state)
# Output JSON for waybar
output = {
"text": "Studio " if power_state else "Studio ",
"tooltip": f"Studio Sound: {'ON' if power_state else 'OFF'}",
"class": "studio-sound-on" if power_state else "studio-sound-off",
"alt": "on" if power_state else "off"
}
print(json.dumps(output))
sys.stdout.flush()
if __name__ == "__main__":
main()
+213
View File
@@ -0,0 +1,213 @@
* {
border: none;
border-radius: 0;
/*font-family: "SF Pro Display", "FontAwesome";*/
font-family: "SF Mono", "FontAwesome";
font-weight: 600;
font-size: 13px;
min-height: 0;
}
window#waybar {
background: rgba(21, 18, 27, 0.36);
}
#privacy-item, #privacy-item > * {
color: #ffae00;
}
tooltip {
background: #1e1e2e;
border-radius: 10px;
border-width: 2px;
border-style: solid;
border-color: #11111b;
}
.modules-left {
margin-left: 10px;
}
.modules-right {
margin-right: 10px;
}
#workspaces {
margin-left: 10px;
padding-right: 0px;
padding-left: 5px;
}
#workspaces button {
padding: 2px 10px;
}
#workspaces button.active {
background-color: rgba(0,0,0,0.3);
}
#workspaces button:hover {
box-shadow: none;
text-shadow: none;
background: none;
background-color: rgba(255,255,255,0.1);
}
#custom-power_profile,
#custom-weather,
#custom-moon,
#custom-wallpaper,
#custom-studio-sound,
#custom-apps,
#custom-files,
#custom-hyprsunset,
#window,
#clock,
#battery,
#pulseaudio,
#custom-network,
#bluetooth,
#temperature,
#cpu,
#memory,
#wireplumber,
#workspaces,
#tray,
#custom-notificationbar,
#backlight,
#privacy {
opacity: 0.95;
padding: 0px 10px;
margin: 0px;
margin-top: 0px;
/*border: 2px solid red;*/
}
#custom-files {
border-radius: 0px 10px 10px 0px;
}
#wireplumber {
min-width: 50px;
}
#custom-network {
min-width: 110px;
border-radius: 10px 0px 0px 10px;
}
#custom-studio-sound {
border-radius: 10px 0px 0px 10px;
min-width: 62px;
}
#memory {
min-width: 45px;
color: #eba0ac;
border-radius: 0px 10px 10px 0px;
}
#cpu {
min-width: 50px;
color: #c3eba0;
}
#temperature {
min-width: 50px;
color: #89b4fa;
}
#backlight {
border-radius: 10px 0px 0px 10px;
}
#tray {
border-radius: 10px;
margin-right: 10px;
}
#tray > .active,
#tray > .passive {
margin-right: 100px;
padding-left: 100px;
}
#custom-power_profile {
color: #a6e3a1;
border-left: 0px;
border-right: 0px;
}
#window {
border-radius: 10px;
margin-left: 60px;
margin-right: 60px;
}
#clock {
border-radius: 10px 0px 0px 10px;
border-right: 0px;
}
#network {
border-radius: 10px 0px 0px 10px;
border-left: 0px;
border-right: 0px;
}
#bluetooth {
min-width: 17px;
}
#battery {
margin-right: 0px;
padding: 0 10px;
border-left: 0px;
}
#battery.warning {
color: #FFA500;
}
#battery.critical {
color: #F00;
}
/* Menu styling */
menu {
border-radius: 8px;
background: rgba(43, 48, 59, 0.95);
color: #ffffff;
/*border: 1px solid rgba(100, 114, 125, 0.3);*/
border-style: none;
padding: 4px 0;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
window decoration{
border-style: none;
box-shadow: none;
}
menuitem {
border-radius: 4px;
padding: 8px 16px;
margin: 2px 4px;
transition: background-color 0.2s ease;
}
menuitem:hover {
background-color: rgba(100, 114, 125, 0.3);
}
menuitem:selected {
background-color: #64727D;
}
/* Separator styling */
separator {
background-color: rgba(100, 114, 125, 0.3);
margin: 4px 8px;
}
@@ -0,0 +1,167 @@
* {
border: none;
border-radius: 0;
font-family: "SF Display";
font-weight: bold;
font-size: 12px;
min-height: 0;
}
window#waybar {
background: rgba(21, 18, 27, 0);
color: #cdd6f4;
}
tooltip {
background: #1e1e2e;
border-radius: 10px;
border-width: 2px;
border-style: solid;
border-color: #11111b;
}
#workspaces button {
padding: 2px 5px;
color: #636777;
margin-right: 5px;
}
#workspaces button.active {
background-color: #000;
}
#workspaces button.focused {
color: #a6adc8;
background: #eba0ac;
border-radius: 10px;
}
#workspaces button.urgent {
color: #11111b;
background: #a6e3a1;
border-radius: 10px;
}
#workspaces button:hover {
background: #11111b;
color: #11111b;
border-radius: 5px;
}
#custom-power_profile,
#custom-weather,
#custom-moon,
#custom-wallpaper,
#window,
#clock,
#battery,
#pulseaudio,
#network,
#bluetooth,
#temperature,
#cpu,
#memory,
#workspaces,
#tray,
#backlight {
background: #1e1e2e;
opacity: 0.8;
padding: 0px 10px;
/* margin: 3px 0px; */
margin: 0px;
margin-top: 10px;
border: 1px solid #181825;
}
#memory {
color: #eba0ac;
}
#temperature {
border-radius: 10px 0px 0px 10px;
}
#custom-temperature.critical {
color: #f00;
}
#backlight {
border-radius: 10px 0px 0px 10px;
}
#tray {
border-radius: 10px;
margin-right: 10px;
}
#workspaces {
background: #1e1e2e;
border-radius: 10px;
margin-left: 10px;
padding-right: 0px;
padding-left: 5px;
}
#custom-power_profile {
color: #a6e3a1;
border-left: 0px;
border-right: 0px;
}
#window {
border-radius: 10px;
margin-left: 60px;
margin-right: 60px;
}
#clock {
color: #fab387;
border-radius: 10px 0px 0px 10px;
margin-left: 10px;
border-right: 0px;
}
#network {
color: #f9e2af;
border-radius: 10px 0px 0px 10px;
border-left: 0px;
border-right: 0px;
}
#bluetooth {
color: #89b4fa;
border-radius: 0px 10px 10px 0px;
margin-right: 10px
}
#pulseaudio {
color: #89b4fa;
border-left: 0px;
border-right: 0px;
}
#pulseaudio.microphone {
color: #cba6f7;
border-left: 0px;
border-right: 0px;
border-radius: 0px 10px 10px 0px;
margin-right: 10px;
}
#battery {
color: #a6e3a1;
border-radius: 0 10px 10px 0;
margin-right: 10px;
border-left: 0px;
}
#battery.warning {
color: #FFA500;
}
#battery.critical {
color: #F00;
}
#custom-moon {
border-radius: 0px 10px 10px 0px;
border-right: 0px;
margin-left: 0px;
}
+2
View File
@@ -0,0 +1,2 @@
mode=drun
insensitive=true
+54
View File
@@ -0,0 +1,54 @@
window {
margin: 0px;
border: 2px solid #bd93f9;
background-color: rgba(40,42,54,.5);
border-radius: 13px;
font-family: "SF Pro Display";
}
#input {
margin: 5px;
border: none;
color: #f8f8f2;
background-color: #44475a;
}
#inner-box {
margin: 5px;
border: none;
background-color: rgba(40,42,54,.5);
}
#outer-box {
margin: 5px;
border: none;
background-color: rgba(40,42,54,.5);
}
#scroll {
margin: 0px;
border: none;
}
#text {
margin: 5px;
border: none;
color: #f8f8f2;
}
#entry.activatable #text {
color: #282a36;
}
#entry > * {
color: #f8f8f2;
}
#entry:selected {
background-color: #44475a;
border-radius: 6px;
}
#entry:selected #text {
font-weight: bold;
}
@@ -0,0 +1,9 @@
[Desktop Entry]
Name=Joplin
Comment=Joplin - a note taking and to-do application with synchronization capabilities for Windows, macOS, Linux, Android and iOS.
Exec=env XDG_CURRENT_DESKTOP=GNOME /opt/Joplin/joplin %U --enable-features=UseOzonePlatform --ozone-platform=wayland --enable-wayland-ime
Icon=/usr/share/joplin-desktop/resources/build/icons/128x128.png
Terminal=false
Type=Application
Categories=Application;Office;
StartupWMClass=Joplin
@@ -0,0 +1,8 @@
[Desktop Entry]
Type=Application
Name=Open Stage Control
Comment=Libre and modular OSC / MIDI controller
Exec=open-stage-control
Icon=/opt/open-stage-control/resources/app/assets/logo.png
Categories=Audio;AudioVideo;
Terminal=false
+2
View File
@@ -0,0 +1,2 @@
# openframeworks
export PG_OF_PATH=/home/tobias/ofx/of_v0.12.0_linux64gcc6_release
+3
View File
@@ -0,0 +1,3 @@
if [[ -z $WAYLAND_DISPLAY && $XDG_VTNR == 1 && $(tty) == /dev/tty1 ]]; then
exec ~/scripts/start_hyprland.sh
fi
+46
View File
@@ -0,0 +1,46 @@
# git display, add ${vcs_info_msg_0_} to PROMPT
#autoload -Uz vcs_info
#zstyle ':vcs_info:*' enable git svn
#precmd() {
# vcs_info
#}
export CLICOLOR=1
export LSCOLORS=ExGxBxDxCxEgEdxbxgxcxd
export TERM=xterm-256color
# prompt format and color
PROMPT='%B%F{136}%n@%m%f%b %F{039}%.%f '
#PROMPT='%B%F{002}%m%f%b:%F{039}%.%f %F{039}%f '
# autocompletion case insensitivity
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}'
autoload -Uz compinit && compinit -i
# plugins
source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
# print all 256 color numbers to use in {}:
# for code in {000..255}; do print -P -- "$code: %F{$code}Color%f"; done
# write a history file
HISTFILE=~/.zsh_history
HISTSIZE=10000
SAVEHIST=10000
setopt SHARE_HISTORY
setopt HIST_IGNORE_SPACE
alias ls='ls --color=auto'
alias grep='grep --color=auto'
#alias data="cd /volumes/data"
#alias proj="cd /volumes/data/Data/Projects"
# enable jumping by words with ctrl+arrow keys
#bindkey ";5C" forward-word
#bindkey ";5D" backward-word
bindkey "^[[1;5C" forward-word
bindkey "^[[1;5D" backward-word
+30
View File
@@ -0,0 +1,30 @@
#!/bin/zsh
# This script puts the monitors to sleep via dpms.
# Sth in hyprland crashes and creates high gpu usage, if hyprpaper is running
# when a monitor is being turned off and on again.
# Therefore, we kill hyprpaper when turning the monitor off and start it again when turning it on.
export STATUS_FILE="$XDG_RUNTIME_DIR/display.status"
enable_display() {
printf "true" >"$STATUS_FILE"
hyprctl dispatch dpms on
sleep 1
exec hyprpaper
}
disable_display() {
killall hyprpaper
printf "false" >"$STATUS_FILE"
hyprctl dispatch dpms off
}
if ! [ -f "$STATUS_FILE" ]; then
disable_display
else
if [ $(cat "$STATUS_FILE") = "true" ]; then
disable_display
elif [ $(cat "$STATUS_FILE") = "false" ]; then
enable_display
fi
fi
+8
View File
@@ -0,0 +1,8 @@
#!/bin/zsh
JOPLIN_DEST=$(busctl --user list | grep "joplin" | awk '{print $1}' | sort -V | sed -n -e '2p')
if [ -n "$JOPLIN_DEST" ]; then
busctl --user call "$JOPLIN_DEST" /StatusNotifierItem org.kde.StatusNotifierItem Activate ii 0 0
else
exec gtk-launch joplin.desktop
fi
+5
View File
@@ -0,0 +1,5 @@
#!/bin/zsh
#source ~/scripts/set_gamma/set_gamma_table.sh
exec start-hyprland
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# OPT-IN: PipeWire/WirePlumber pro-audio routing for the RME Fireface 802.
#
# Creates a stereo null sink ("rme-nullsink") and statically patches it to the
# RME's AES outs (AUX12/13), sets the card to the "pro-audio" profile, and keeps
# the null sink linked to whatever output is active — so Pulse/Wine apps always
# see a stable stereo device. (guide: bennett.dev/auto-link-pipewire-ports-wireplumber)
#
# Hardware-specific: the RME serial is baked into rme-proaudio/auto-connect-ports.lua
# ("Fireface 802 (24240739)") and rme-proaudio/alsa.conf (device.name) — edit those
# for a different unit. Run on the machine with the interface, as your normal user:
# ./rme-proaudio.sh
set -euo pipefail
[ "$(id -u)" -ne 0 ] || { echo "run as your user, not root (writes ~/.config)"; exit 1; }
cd "$(dirname "$0")"
src=rme-proaudio
PW="$HOME/.config/pipewire/pipewire.conf.d"
WP="$HOME/.config/wireplumber"
install -Dm644 "$src/nullsink.conf" "$PW/nullsink.conf"
install -Dm644 "$src/auto-connect-ports.lua" "$WP/scripts/auto-connect-ports.lua"
install -Dm644 "$src/alsa.conf" "$WP/wireplumber.conf.d/alsa.conf"
# The component file registers the lua by ABSOLUTE path (~ isn't expanded here),
# so generate it with $HOME rather than shipping a hardcoded path.
install -Dm644 /dev/stdin "$WP/wireplumber.conf.d/99-auto-connect-ports.conf" <<EOF
wireplumber.components = [
{
name = $WP/scripts/auto-connect-ports.lua, type = script/lua
provides = custom.auto-connect-ports
}
]
wireplumber.profiles = {
main = {
custom.auto-connect-ports = required
}
}
EOF
echo "RME pro-audio config installed. Restart audio to apply:"
echo " systemctl --user restart wireplumber pipewire pipewire-pulse"
+16
View File
@@ -0,0 +1,16 @@
monitor.alsa.rules = [
{
# Sets pro audio profile for RME Fireface
matches = [
{
device.name = "alsa_card.usb-RME_Fireface_802__24240739__3A179EAE2137208-00"
}
]
actions = {
update-props = {
device.profile = "pro-audio"
}
}
}
]
@@ -0,0 +1,196 @@
-- As explained on: https://bennett.dev/auto-link-pipewire-ports-wireplumber/
--
-- This script keeps my stereo-null-sink connected to whatever output I'm currently using.
-- I do this so Pulseaudio (and Wine) always sees a stereo output plus I can swap the output
-- without needing to reconnect everything.
-- Link two ports together
function link_port(output_port, input_port)
if not input_port or not output_port then
return nil
end
local link_args = {
["link.input.node"] = input_port.properties["node.id"],
["link.input.port"] = input_port.properties["object.id"],
["link.output.node"] = output_port.properties["node.id"],
["link.output.port"] = output_port.properties["object.id"],
-- The node never got created if it didn't have this field set to something
["object.id"] = nil,
-- I was running into issues when I didn't have this set
["object.linger"] = true,
["node.description"] = "Link created by auto_connect_ports"
}
local link = Link("link-factory", link_args)
link:activate(1)
return link
end
-- Automatically link ports together by their specific audio channels.
--
-- ┌──────────────────┐ ┌───────────────────┐
-- │ │ │ │
-- │ FL ├────────►│ AUX0 │
-- │ OUTPUT │ │ │
-- │ FR ├────────►│ AUX1 INPUT │
-- │ │ │ │
-- └──────────────────┘ │ AUX2 │
-- │ │
-- └───────────────────┘
--
-- -- Call this method inside a script in global scope
--
-- auto_connect_ports {
--
-- -- A constraint for all the required ports of the output device
-- output = Constraint { "node.name"}
--
-- -- A constraint for all the required ports of the input device
-- input = Constraint { .. }
--
-- -- A mapping of output audio channels to input audio channels
--
-- connections = {
-- ["FL"] = "AUX0"
-- ["FR"] = "AUX1"
-- }
--
-- }
--
function auto_connect_ports(args)
local output_om = ObjectManager {
Interest {
type = "port",
args["output"],
Constraint { "port.direction", "equals", "out" }
}
}
local links = {}
local input_om = ObjectManager {
Interest {
type = "port",
args["input"],
Constraint { "port.direction", "equals", "in" }
}
}
local all_links = ObjectManager {
Interest {
type = "link",
}
}
local unless = nil
if args["unless"] then
unless = ObjectManager {
Interest {
type = "port",
args["unless"],
Constraint { "port.direction", "equals", "in" }
}
}
end
function _connect()
local delete_links = unless and unless:get_n_objects() > 0
if delete_links then
for _i, link in pairs(links) do
link:request_destroy()
end
links = {}
return
end
for output_name, input_names in pairs(args.connect) do
local input_names = input_names[1] == nil and { input_names } or input_names
if delete_links then
else
-- Iterate through all the output ports with the correct channel name
for output in output_om:iterate { Constraint { "audio.channel", "equals", output_name } } do
for _i, input_name in pairs(input_names) do
-- Iterate through all the input ports with the correct channel name
for input in input_om:iterate { Constraint { "audio.channel", "equals", input_name } } do
-- Link all the nodes
local link = link_port(output, input)
if link then
table.insert(links, link)
end
end
end
end
end
end
end
output_om:connect("object-added", _connect)
input_om:connect("object-added", _connect)
all_links:connect("object-added", _connect)
output_om:activate()
input_om:activate()
all_links:activate()
if unless then
unless:connect("object-added", _connect)
unless:connect("object-removed", _connect)
unless:activate()
end
end
-- Auto connect the stereo null sink to the first two channels of the RME Fireface
auto_connect_ports {
output = Constraint { "object.path", "matches", "rme-nullsink:*" },
input = Constraint { "port.alias", "matches", "Fireface 802 (24240739):*" },
connect = {
["FL"] = "AUX12",
["FR"] = "AUX13"
}
}
-- Auto connect the stereo null sink to the jack_sink for when the jack server gets started
auto_connect_ports {
output = Constraint { "object.path", "matches", "rme-nullsink:*" },
input = Constraint { "object.path", "matches", "jack_sink:*" },
connect = {
["FL"] = "FL",
["FR"] = "FR"
}
}
auto_connect_ports {
output = Constraint { "object.path", "matches", "rme-nullsink:*" },
input = Constraint { "object.path", "matches", "alsa:*" },
connect = {
["FL"] = "FL",
["FR"] = "FR"
},
-- Don't connect to speakers if there are bluetooth headphones plugged in
-- unless = Constraint { "object.path", "matches", "bluez_output.*" }
}
-- Auto connect the stereo null sink to bluetooth headphones
-- auto_connect_ports {
-- output = Constraint { "object.path", "matches", "rme-nullsink:*" },
-- input = Constraint { "object.path", "matches", "bluez_output.*" },
-- connect = {
-- -- Connect to the correct channel or "MONO" if the output is in "headset" mode
-- ["FL"] = { "FL", "MONO" },
-- ["FR"] = { "FR", "MONO" }
-- }
--}
@@ -0,0 +1,14 @@
context.objects = [
{ factory = adapter
args = {
factory.name = support.null-audio-sink
node.name = "rme-nullsink"
node.description = "RME Nullsink"
media.class = Audio/Sink
object.linger = true
audio.position = [ FL FR ]
monitor.channel-volumes = true
monitor.passthrough = true
}
}
]
+47
View File
@@ -0,0 +1,47 @@
# Explicit AUR packages. Refresh on the running system: pacman -Qqem > aur.txt
apple-fonts
arduino-ide-bin
binaryninja-free
coppwr
cura-bin
distroav-bin
dmg2img
dxvk-bin
ferdium
ffmpeg7.1
fontbase
freeshow-bin
fswebcam
glfw-git
inkstitch
joplin-bin
librepods-git
llama.cpp
localsend-bin
logiops
lunacy-bin
ndi-sdk
obs-studio-liberty
onlyoffice-bin
openmeters-git
opensoundmeter-jack
open-stage-control-bin
pasystray-wayland
pdfsam-bin
posting
processing
puddletag
python310
rapidraw
roomeqwizard
rustdesk-bin
scope-tui
sdrangel-bin
spotify
streamrip
ttf-ms-win11
uxplay
vcvrack
vkd3d-proton-bin
whitesur-icon-theme
wl-screenrec
Executable
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# User-level provisioning. Run as your normal user (NOT root), after the system
# layer has finished and you've rebooted into the installed system:
# ./run.sh
set -euo pipefail
cd "$(dirname "$0")"
source ../02-system/lib.sh
REPO_ROOT="$(cd .. && pwd)"
[ "$(id -u)" -ne 0 ] || die "run as your normal user, not root"
for step in [0-9][0-9]-*.sh; do
info "--- $step ---"
source "$step"
done
info "user provisioning done."
[ -s "$HOME/aur-failed.log" ] && echo "NOTE: some AUR packages failed — see ~/aur-failed.log"
@@ -0,0 +1,12 @@
{
"flutter.ls_version": 2,
"flutter.ls_color": "system",
"flutter.ls_window_offset_x": 0.0,
"flutter.ls_window_offset_y": 0.0,
"flutter.ls_window_height": 500.0,
"flutter.ls_window_width": 401.0,
"flutter.ls_theme": "dark",
"flutter.ls_minimize_to_tray": true,
"flutter.ls_quick_save": true,
"flutter.ls_advanced_settings": true
}
+18
View File
@@ -0,0 +1,18 @@
# Secrets (NOT in git)
Everything in this directory except `README.md` and `run.sh` is gitignored.
Secrets are **typed in interactively** by `run.sh` — nothing is committed, kept
on external media, or baked into the ISO.
## What counts as a secret here
- share credentials — `/etc/nase.meow.credentials` (CIFS) and `/etc/davfs2/secrets`
(davfs); the fstab entries that reference them are non-secret and live in
`02-system/60-shares.sh`
- localsend keys — strip `flutter.ls_security_context` from its prefs before archiving; it regenerates
- GNOME Online Accounts (`~/.config/goa-1.0/accounts.conf`)
- later: licensed/cracked app installers & licenses (see `03-user/90-licensed-apps.sh`)
## Usage
```
sudo ./run.sh # prompts for each credential, writes the /etc files
```
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Enter share credentials interactively and write them to their target files.
# Nothing secret is stored in the repo or on external media — you type it in here.
# Mount points + fstab entries are handled by 02-system/60-shares.sh, not this script.
# sudo ./run.sh
set -euo pipefail
[ "$(id -u)" -eq 0 ] || { echo "run as root (writes /etc/*)"; exit 1; }
ask() { local v; read -rp " $1: " v; printf '%s' "$v"; } # visible
asks() { local v; read -rsp " $1: " v; echo >&2; printf '%s' "$v"; } # hidden
# --- CIFS //nase.meow/data -> /etc/nase.meow.credentials ---
echo "nase.meow (CIFS) credentials:"
nm_user="$(ask username)"
nm_pass="$(asks password)"
nm_dom="$(ask 'domain (blank = none)')"
{
printf 'username=%s\npassword=%s\n' "$nm_user" "$nm_pass"
[ -n "$nm_dom" ] && printf 'domain=%s\n' "$nm_dom"
} | install -Dm600 /dev/stdin /etc/nase.meow.credentials
echo " wrote /etc/nase.meow.credentials (600)"
# --- davfs https://files.70b1.de -> /etc/davfs2/secrets ---
# Format: <resource> <username> <password>, one per line. We replace only this
# resource's line, leaving any other davfs secrets intact.
echo "files.70b1.de (davfs) credentials:"
dv_user="$(ask username)"
dv_pass="$(asks password)"
res="https://files.70b1.de"
tmp="$(mktemp)"
grep -vE "^${res//./\\.}[[:space:]]" /etc/davfs2/secrets 2>/dev/null > "$tmp" || true
printf '%s %s %s\n' "$res" "$dv_user" "$dv_pass" >> "$tmp"
install -Dm600 "$tmp" /etc/davfs2/secrets && rm -f "$tmp"
echo " wrote /etc/davfs2/secrets (600)"
echo "credentials written. Mount with 'mount -a' or reboot (mounts wait on the -ready services)."
+84
View File
@@ -0,0 +1,84 @@
# arch-system-th
Reproducible Arch Linux + Hyprland install
## Layers
| Dir | Layer | Runs where |
|---------------|-------------------|-----------------------|
| `01-install/` | base install | live ISO (root) |
| `02-system/` | root provisioning | installed system |
| `03-user/` | user provisioning | installed system |
| `04-secrets/` | share credentials | interactive prompts |
Opt-in, run-once scripts that aren't part of the auto-provision loop live in an
`optional/` dir under their layer:
- `02-system/optional/kvm-bridge.sh` — libvirt LAN bridge (root)
- `03-user/optional/rme-proaudio.sh` — RME Fireface pro-audio routing (user)
## Rebuild a machine
Boot the official Arch ISO, get online, then clone this repo and run it:
```sh
# 1. boot the official Arch ISO, connect (iwctl for wifi; wired is automatic),
# then fetch this repo:
git clone <repo-url> arch-system-th && cd arch-system-th
# 2. set target + options, then install the base:
vim system.conf # DISK, hostname, GPU, desktop/laptop…
./01-install/run.sh # partitions + base install
# 3. reboot, log in, then provision:
sudo ~/arch-system-th/02-system/run.sh
~/arch-system-th/03-user/run.sh
# 4. (optional) enter share credentials interactively
sudo ~/arch-system-th/04-secrets/run.sh
```
### Post Install
- install openframeworks
- `tar -xf of_v0.12.0_linux64gcc6_release.tar.gz`
- sudo run both scripts from unpacked archive: scripts/linux/archlinux/
- ensure that all pacman packages installed there are avail. offline
- install custom glfw-git from AUR, change in PKGBUILD:
- line 44, set `DGLFW_BUILD_WAYLAND=OFF`, otherwise of doesnt show window
- `mkdir ~/ofx && cp -r of_v0.12.0_linux64gcc6_release ~/ofx/`
- cd into the new dir under ~/ofx/, run
- `scripts/linux/compileOF.sh -j8`
- `scripts/linux/compilePG.sh -j8`
- say yes to install the projectGenerator, then add `export PG_OF_PATH=/home/tobias/ofx/of_v0.12.0_linux64gcc6_release` to ~/.profile manually
- optional: `scripts/linux/buildAllExamples.sh -j8`
- rm example debug files `find ./examples -wholename "*bin/*_debug" -type f -print0 | xargs -0 /bin/rm -f`
- the of dir must reside in the user folder because of permissions in /opt. copying to opt would work, but every time a new addon gets used by a project (the standard ones in /addons) new obj files are created in the ofx folder, which fails because users shall not have write perms in opt, so every make would have to be run as root at least once.. not a good solution.
- install davinci resolve manually
- install bitwig studio manually
- agisoft metashape manually
- configure wine manually
- configure yabridge manually
- copy vcvrack modules
- copy arduino libraries
- copy processing libraries
- install firefox extensions manually
- ublock origin
- floccus
- dark reader
- edit hyprland config to adjust for monitor setup, including color profiles under ~/.local/share/icc
## Package lists
`02-system/packages/pacman.txt` (native, system layer) and `03-user/packages/aur.txt`
(AUR, user layer) are the source of truth — edit them directly, or refresh from a
running machine:
```sh
pacman -Qqen > 02-system/packages/pacman.txt # native explicit
pacman -Qqem > 03-user/packages/aur.txt # explicit AUR
```
GPU drivers live in `graphics-amd.txt` / `graphics-intel.txt`, installed per the
`GPU=` set in `system.conf` (kept out of `pacman.txt` so a machine only gets its
own GPU's packages).
+10
View File
@@ -0,0 +1,10 @@
Arch + Hyprland custom installer (live environment)
===================================================
The provisioning repo is at: /root/arch-system-th
1. Get online: iwctl (wifi) — wired works automatically
2. Set target+opts: vim /root/arch-system-th/01-install/install.conf
3. Install base: /root/arch-system-th/01-install/run.sh
4. Reboot, then run the system + user provisioning (see repo README).
+7
View File
@@ -0,0 +1,7 @@
# Packages appended to releng's package list for the live ISO.
# (Most installer tools are already in releng; listed here to be explicit/safe.)
git
arch-install-scripts
gptfdisk
dosfstools
e2fsprogs
Executable
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# REFERENCE / OPTIONAL — the normal flow uses the official Arch ISO + `git clone`
# (see README). Kept in case a self-contained custom ISO is ever wanted.
#
# Build the thin custom Arch ISO by extending the official `releng` profile with:
# - a few explicit installer packages (extra-packages.x86_64)
# - this repo baked into /root/arch-system-th
# - a login MOTD with install instructions (airootfs/etc/motd)
#
# Run on a machine with the `archiso` package installed (needs root for mkarchiso):
# sudo ./run.sh [output_dir]
set -euo pipefail
cd "$(dirname "$0")"
REPO_ROOT="$(cd .. && pwd)"
OUTDIR="${1:-$REPO_ROOT/out}"
RELENG=/usr/share/archiso/configs/releng
command -v mkarchiso >/dev/null || { echo "install archiso first: pacman -S archiso"; exit 1; }
[ -d "$RELENG" ] || { echo "releng profile missing at $RELENG"; exit 1; }
WORK="$(mktemp -d)"; PROFILE="$WORK/profile"
trap 'rm -rf "$WORK"' EXIT
cp -r "$RELENG" "$PROFILE"
# extra installer packages
cat extra-packages.x86_64 >> "$PROFILE/packages.x86_64"
# our airootfs overlay (motd, etc.)
cp -aT airootfs "$PROFILE/airootfs"
# bake the repo into the live root (without git history / build output)
dest="$PROFILE/airootfs/root/arch-system-th"
mkdir -p "$dest"
cp -a "$REPO_ROOT/." "$dest/"
rm -rf "$dest/.git" "$dest/out"
# mkarchiso copies airootfs with --no-preserve=mode, so exec bits are dropped and
# must be declared in profiledef's file_permissions array (the same way releng's
# own scripts get +x). We only need the bootstrap executable here; run.sh then
# restores +x across the rest of the repo at runtime, which propagates to the
# installed system. file_permissions+=(...) appends to the array defined in releng.
printf '\nfile_permissions+=(["/root/arch-system-th/01-install/run.sh"]="0:0:755")\n' \
>> "$PROFILE/profiledef.sh"
mkdir -p "$OUTDIR"
mkarchiso -v -w "$WORK/work" -o "$OUTDIR" "$PROFILE"
echo "ISO written to $OUTDIR"
+634
View File
@@ -0,0 +1,634 @@
[deprecated] general info:
install blender after freecad, because at first install, blender was first installed and when installing freecad, there was a conflict between hdf5 and hdf5-openmpi. (this is probably not mandatory anymore).
AppImage/Manual:
process: copy program files, then icons and .desktop files for manually installed apps. copy appimages to /opt/softwarename
> These files usually reside in /usr/share/applications/ or /usr/local/share/applications/ for applications installed system-wide, or ~/.local/share/applications/ for user-specific applications. User entries take precedence over system entries.
Bespoke
Meshlab
Agisoft Metashape + Crack (runs like portable app, put whole folder in /opt)
gnome astra monitor shell extension
- https://www.debugpoint.com/manual-installation-gnome-extension/
- then, run `glib-compile-schemas ./schemas` inside the extension dir
gnome own smarthome plugin
- copy `smarthomebar@tobiashuttinger.de` to `/home/tobias/.local/share/gnome-shell/extensions/r`
openframeworks
- `tar -xf of_v0.12.0_linux64gcc6_release.tar.gz`
- sudo run both scripts from unpacked archive: scripts/linux/archlinux/
- ensure that all pacman packages installed there are avail. offline
- install custom glfw-git from AUR, change in PKGBUILD:
- line 44, set `DGLFW_BUILD_WAYLAND=OFF`, otherwise of doesnt show window
- `mkdir ~/ofx && cp -r of_v0.12.0_linux64gcc6_release ~/ofx/`
- cd into the new dir under ~/ofx/, run
- `scripts/linux/compileOF.sh -j8`
- `scripts/linux/compilePG.sh -j8`
- say yes to install the projectGenerator, then add `export PG_OF_PATH=/home/tobias/ofx/of_v0.12.0_linux64gcc6_release` to ~/.profile manually
- optional: `scripts/linux/buildAllExamples.sh -j8`
- rm example debug files `find ./examples -wholename "*bin/*_debug" -type f -print0 | xargs -0 /bin/rm -f`
- the of dir must reside in the user folder because of permissions in /opt. copying to opt would work, but every time a new addon gets used by a project (the standard ones in /addons) new obj files are created in the ofx folder, which fails because users shall not have write perms in opt, so every make would have to be run as root at least once.. not a good solution.
create webapps with webapp-manager manually
install firefox extensions manually
AUR:
gnome-shell-extension-blur-my-shell
gnome-shell-extension-tilingshell
gnome-shell-extension-dash-to-dock
gnome-shell-extension-appindicator
whitesur-icon-theme
inter-font
apple-fonts
ttf-ms-win11-auto
davfs2
roomeqwizard
davinci-resolve-studio
bitwig-studio
spotify
cura-bin
processing-bin
lunacy-bin
joplin-desktop (3.0.14)
fontbase
obs-studio-liberty (includes browser)
ndi-sdk ffmpeg7.1 distroav
localsend-bin
webapp-manager
vcvrack
open-stage-control python-rtmidi (pacman)
freeshow-bin
python310
sdrangel-bin
rtl_433
scope-tui
uxplay
fswebcam
arduino-ide-bin (package from extra hangs)
ferdium
binaryninja-free
feishin-bin
puddletag
onlyoffice-bin
posting
rapidraw
logiops (for logitech mice)
opensoundmeter-jack
openmeters
Repos:
zsh zsh-syntax-highlighting zsh-autosuggestions
vim
neovim
firefox
vlc vlc-plugins-all
sonic-visualiser
gimp
inkscape python-tinycss2 (curr. needed for eps import)
krita
mixxx
freecad
blender
element-desktop
code
libreoffice-fresh
tenacity
thunderbird
remmina libvncserver freerdp
reaper
keepassxc
kicad
prusa-slicer
dconf-editor
kismet
darktable
gnome-calendar gnome-contacts evolution evolution-ews
gnome-maps
qemu-full qemu-img libvirt virt-install virt-manager virt-viewer edk2-ovmf swtpm guestfs-tools libosinfo
wine-staging wine-mono wine-gecko
supercollider
puredata
musescore
pipewire-zeroconf (autodiscover airplay targets)
pipewire-roc
qpwgraph
sqlitebrowser
netcat (choose openbsd version for v6 support)
linssid
yabridge
arduino-cli
ghidra
rpi-imager
foliate
cups
kid3-common
kdenlive
godot
socat
cdrkit
solaar (logitech mice)
v4l2loopback-dkms (video loopback needed for obs virt webcam)
nvtop
```
sudo pacman -Sy tmux inetutils moreutils findutils wget curl httpie htop iotop sysstat iftop nethogs bmon nmap wireshark-cli wireshark-qt iperf rclone rsync p7zip hexedit go rust nodejs ffmpeg libusb mediainfo cmake perl-image-exiftool ninja yt-dlp ncdu mpv openssl libimobiledevice mitmproxy monolith chromium shairport-sync docker docker-compose docker-buildx wireguard-tools gnutls
```
Hardware-dependant graphics libs:
AMD:
mesa lib32-mesa vulkan-radeon lib32-vulkan-radeon
(libva-mesa-driver (for video enc/dec accel)) -> not needed anymore, was merged with main mesa package
libva-utils (check if vaapi is enabled on system)
gst-plugin-va (gstreamer vaapi libs)
rocm-hip-runtime (amds rocm hip libraries)
rocm-opencl-runtime (opencl support)
If using hyprland as main desktop:
disable gnome display manager
```
systemctl set-default multi-user.target
```
Then, add to ~/.zprofile:
```
if [[ -z $WAYLAND_DISPLAY && $XDG_VTNR == 1 && $(tty) == /dev/tty1 ]]; then
exec ~/scripts/start_hyprland.sh
fi
```
and copy the scripts start_hyprland.sh, display_sleep.sh and set_gamma folder to ~/scripts/
To enable autologin:
```
sudo mkdir -p /etc/systemd/system/getty@tty1.service.d
```
Create `/etc/systemd/system/getty@tty1.service.d/autologin.conf` with:
```
[Service]
ExecStart=
ExecStart=-/usr/bin/agetty --autologin tobias --noclear %I $TERM
```
Then:
```
sudo systemctl daemon-reload
sudo systemctl restart getty@tty1
```
Settings:
If system is a desktop:
add dir/file:
```
/etc/systemd/sleep.conf.d/disable-sleep.conf
```
With content:
```
[Sleep]
AllowSuspend=no
AllowHibernation=no
AllowHybridSleep=no
AllowSuspendThenHibernate=no
```
activate iommu in kernel:
append to `/etc/kernel/cmdline`:
```
intel_iommu=on iommu=pt
```
then regenerate boot entries and initrds: `sudo reinstall-kernels`
import gnome settings
experimental features in gnome 47 (also included in dconf settings, just for completeness):
```
gsettings set org.gnome.mutter experimental-features "['scale-monitor-framebuffer']"
gsettings set org.gnome.mutter experimental-features '["scale-monitor-framebuffer", "xwayland-native-scaling"]'
```
copy nautilus bookmarks bar file: `~/.config/gtk-3.0/bookmarks`
copy xdg mime associations file: `~/.config/mimeapps.list`
install monitor color profiles
install blender addons
Enable services: bluetooth service
Copy ~/.profile
(for env vars that are not shell related)
Copy ~/.zshrc and make zsh the default shell with
`chsh -s /usr/bin/zsh`
Configure shairport-sync
- copy shairport config file `/etc/shairport-sync.conf`
- copy systemd user service file: `/home/tobias/.config/systemd/user/shairport-sync.service`
- enable service `systemctl --user enable shairport-sync.service`
Configure joplin
- copy joplin.desktop from /usr/share/applications to ~/.local/share/applications
- change Exec line in joplin.desktop:
`Exec=env XDG_CURRENT_DESKTOP=GNOME /usr/bin/joplin-desktop --enable-features=UseOzonePlatform --ozone-platform=wayland --enable-wayland-ime`
- The env XDG... is needed for non-gnome envs like hyprland because when set to sth else, joplin takes more startup time when probing what portal is used...
- Add line: `StartupWMClass=@joplin/app-desktop`
- copy settings json and userchrome.css
- then, copy joplin start helper script joplin.sh to ~/scripts/
Configure vscode
- install extensions
- copy settings file
- copy keybindings file
- copy .desktop file from `/usr/share/applications/code.desktop` to `~/.local/share/applications`
- replace the line `StartupWMClass=Code` with `StartupWMClass=code-url-handler`
Create ./config/electron-flags.conf and ./config/code-flags.conf with contents:
```
--enable-features=UseOzonePlatform
--ozone-platform=wayland
--enable-wayland-ime
```
configure obs-ndi:
ndi-sdk from AUR installs v6 into /usr/lib. obs-ndi however expects v5. solution: symlink it:
`sudo ln -s /usr/lib/libndi.so.6 /usr/local/lib/libndi.so.5`
Because a ndi sdk version requires specific versions of ffmpeg (v6.1.1 >= ffmpeg 7, but NOT 8, that doesnt work), pin the ffmpeg package in pacman to stay at the current version and only update ffmpeg if its safe that ndi sdk works with it.
`strings /usr/lib/libndi.so.5.6.1 | grep 'libav'`. The version numbers of libavcodec and libavutil are important; those are provided by ffmpeg.
configure v4l2loopback kernel module
/etc/modprobe.d/v4l2loopback.conf:
```
options v4l2loopback devices=1 video_nr=10 card_label="Virtual Cam" exclusive_caps=1
```
then:
```
echo v4l2loopback | sudo tee /etc/modules-load.d/v4l2loopback.conf
```
configure fontbase:
apply fontbase crack
create symlink to fonts folder - change source path accordingly:
`ln -s /mnt/nase.meow/Data/Gfxres/fonts ~/FontBase/fonts`
- apply bitwig crack
- for all bitwig versions before 5.3.9, theres a bug in bitwig with newer vulkan libs that prevent bitwig from starting. to fix:
copy `/opt/vulkan-icd-loader-1.4.309.0`
copy `~/.local/share/applications/com.bitwig.BitwigStudio.desktop`
(`env LD_LIBRARY_PATH=/opt/vulkan-icd-loader-1.4.309.0` was prepended to the Eexc command there)
apply resolve crack
create webapps manually for now with webapp-manager
Set default file browser to nautilus:
```
xdg-mime default org.gnome.Nautilus.desktop inode/directory
```
Otherwise any app that has the mimetype inode/directory specified in its .desktop file will probably become default (easytag in this case)
- mount net shares and ramdisk on boot/login
- mkdir /mnt/nase.meow
- mkdir /mnt/files.70b1.de
- mkdir /mnt/ramdisk
- put credentials file /etc/nase.meow.credentials and /etc/davfs2/secrets
```
chmod 600 /etc/davfs2/secrets
chown root:root /etc/davfs2/secrets
chmod 600 /etc/nase.meow.credentials
chown root:root /etc/nase.meow.credentials
```
- create systemd services that wait until shares are reachable
- /etc/systemd/system/files.70b1.de-ready.service
- /etc/systemd/system/nase.meow-ready.service
- enable those services with systemctl enable
- make entries in fstab
copy /etc/gdm/custom.conf for autologin settings, disable autologin because otherweise gnome keyring asks for password twice
copy gnome online accounts config to `~/.config/goa-1.0/accounts.conf`. might not work because other things are stored elsewhere...
configure firefox
- sane user.prefs, also change
apz.gtk.pangesture.page_delta_mode_multiplier to 0.2
apz.gtk.pangesture.pixel_delta_mode_multiplier to 10
for slow trackpad scrolling
- to enable ffmpeg vaapi video decode hw accel, set:
media.ffmpeg.vaapi.enabled to true
- configure kvm
enable libvirt daemons
```
for drv in qemu interface network nodedev nwfilter secret storage; do
sudo systemctl enable virt${drv}d.service;
sudo systemctl enable virt${drv}d{,-ro,-admin}.socket;
done
```
- configure kvm networking
[qemu bridge networking](:/25eb0085f9f04d1cbf343502255c432b)
Configure wine
- run `winecfg`
- installed samba package for ntlm_auth binary
- installed
```
winetricks d3dx9
winetricks d3dx11_43
winetricks vcrun2022
winetricks corefonts
```
- installed dxvk-bin from AUR (directx 9/10/11 vulkan layers)
- activated for current wine env with `setup_dxvk install`
- installed vkd3d-proton-bin from AUR (directx 12 vulkan layer)
- activated for current wine env with `setup_vkd3d_proton install`
- necessary for some VST setups:
`winetricks vcrun6sp6 `
configure localsend
- localsend stores its generated priv/pub ssl keys in the config file, in the json key `flutter.ls_security_context`. strip this key completely when archiving the file for setup. they get generated if this key is missing.
location: `.local/share/org.localsend.localsend_app/shared_preferences.json`
autostarting gui apps is best done via gnome autostart functionality, because systemd user units dont wait until display is ready
- remove anything thats already in `~/.config/autostart/`
- copy localsend.desktop
vcvrack:
- untar and copy rack appdata folder to ./local/share
arduino config and libraries:
- extract arduino15.tar.gz and copy to ~/.arduino15
- extract arduino.tar.gz and copy to ~/Arduino
processing config and libraries:
- copy ~/.config/processing/preferences.txt
- extract libraries.tar.gz and copy to ~/sketchbook/libraries
open stage control:
- its installed in /opt/open-stage-control but no desktop file or symlink is created
- create symlink:
```
sudo ln -s /opt/open-stage-control/open-stage-control /usr/local/bin
```
- create desktop file with icon
Configure VLC
- copy `~/.config/vlc/vlcrc`
Configure mpv:
- copy `~/.config/mpv/mpv.conf`
Pipewire Roc sinks:
1. Install pipewire roc module
```
pacman -S pipewire-roc
```
2. Ensure that you have pipewire configuration directory:
```
mkdir -p ~/.config/pipewire/pipewire.conf.d
```
3. Create `~/.config/pipewire/pipewire.conf.d/roc-sink.conf` and add the following:
```
context.modules = [
{ name = libpipewire-module-roc-sink
args = {
fec.code = rs8m
remote.ip = <IP>
remote.source.port = 10001
remote.repair.port = 10002
sink.name = "Studio Raspi"
sink.props = {
node.name = "studio-raspi-roc-sink"
node.description = "Studio Raspi"
}
}
}
]
```
Here, `<IP>` is the IP address of the Roc receiver.
After that, the sink should be available.
https://docs.pipewire.org/page_module_roc_source.html
Pipewire airplay zeroconf:
Create file `~/.config/pipewire/pipewire.conf.d/raop-discover.conf` with content:
```
context.modules = [
{
name = libpipewire-module-raop-discover
args = { }
}
]
```
Pipewire RME Fireface conf with virtual sink: Follow this [Pipewire Wireplumber Config for Pro Audio](:/a3c201df819d4fb4a99a5e6cb00bd89d)
configure ferdium
remove from gnome (xdg) autostart
```
rm ~/.config/autostart/ferdium.desktop
```
configure cups
```
sudo systemctl enable cups.socket
sudo systemctl start cups.socket
```
Only cups.socket is enabled and started, this way, cups only runs when an application wants to use it.
Logitech mice: configure logiops
Create a udev rule with a file under: `/etc/udev/rules.d/90-logid-start-restart.rules`:
```
# Logitech via USB receiver
ACTION=="add|change", SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", \
RUN+="/usr/bin/systemctl restart --no-block logid.service"
# Logitech via Bluetooth (BlueZ UHID path 0005:046D:...)
ACTION=="add|change", SUBSYSTEM=="hidraw", KERNELS=="0005:046D:*", \
RUN+="/usr/bin/systemctl restart --no-block logid.service"
```
See this issue why: https://github.com/PixlOne/logiops/issues/279#issuecomment-1192737809
then, create config file: /etc/logid.cfg
Hint: When connected through Bolt receiver, MX Anywhere 3S shows up as "MX Anywhere 3"
```
devices: (
{
name: "MX Anywhere 3";
smartshift:
{
on: false;
threshold: 15;
torque: 50;
};
hiresscroll:
{
hires: false;
invert: false;
target: false;
};
dpi: 1000;
}
);
```
enable system service
```
sudo systemctl enable logiops
sudo systemctl start logiops
```
currently under gnome wayland, smooth scrolling doesnt work (wheel speed way too high, cant be adjusted via libinput)
configure keepassxc
copy ~/.config/keepassxc/keepassxc.ini
For amggpu performance control, create the file `/usr/local/bin/gpuprofile.sh`:
```
#!/bin/zsh
echo "high" | tee /sys/class/drm/card1/device/power_dpm_force_performance_level
```
Setting perf level to high fixes memclock to 100% which increases idle power draw to around 20W, but fixes stuttering.
Then, add a systemd service `/etc/systemd/system/gpuprofile.service`:
```
[Unit]
Description=Increase GPU core and memory clocks
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/gpuprofile.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
```
For amdgpu rx 6600 fan control, create the file `/usr/local/bin/amdgpu-fancontrol.sh`:
```
#!/bin/sh
# ---------------- CONFIG ----------------
# Temperature threshold in millidegrees Celsius
# 55000 = 55°C
TEMP_THRESHOLD=55000
# PWM values (0255)
PWM_IDLE=25 # fan speed below threshold
PWM_HOT=90 # fan speed above threshold
# Path root
HWMON_ROOT="/sys/class/drm/card1/device/hwmon"
# ---------------------------------------
# Find hwmon
HWMON="$(ls -d $HWMON_ROOT/hwmon* 2>/dev/null | head -n1)"
[ -z "$HWMON" ] && exit 0
TEMP_FILE="$HWMON/temp1_input"
PWM_ENABLE="$HWMON/pwm1_enable"
PWM_FILE="$HWMON/pwm1"
# Enable manual fan control (always)
echo 1 > "$PWM_ENABLE"
# Read temperature
TEMP="$(cat "$TEMP_FILE")"
# Decide PWM
if [ "$TEMP" -ge "$TEMP_THRESHOLD" ]; then
PWM="$PWM_HOT"
else
PWM="$PWM_IDLE"
fi
# Always write PWM
echo "$PWM" > "$PWM_FILE"
exit 0
```
Change the path root (card1) according to where the gpu is registered on the system.
Then, make it executable: `sudo chmod +x /usr/local/bin/amdgpu-fancontrol.sh`
Then, create a systemd service under `/etc/systemd/system/amdgpu-fancontrol.service`:
```
[Unit]
Description=AMDGPU fan control
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/amdgpu-fancontrol.sh
```
Then, create a systemd timer under `/etc/systemd/system/amdgpu-fancontrol.timer`:
```
[Unit]
Description=Run AMDGPU fan control periodically
[Timer]
OnBootSec=20s
OnUnitActiveSec=20s
[Install]
WantedBy=timers.target
```
Then, activate timer:
```
sudo systemctl daemon-reload
sudo systemctl enable --now amdgpu-fancontrol.timer
```
+39
View File
@@ -0,0 +1,39 @@
```bash
pacman -S hyprland hyprpaper hyprshot hyprpicker kitty wofi hyprsunset swaync xdg-desktop-portal-hyprland
pacman -S waybar otf-font-awesome
#statusbar applets
pacman -S blueman network-manager-applet
yay -S pasystray-wayland
```
hyprland conf: ~/.config/hypr/hyprland.conf
hyprpaper conf: ~/.config/hypr/hyprpaper.conf
hyprsunset conf: ~/.config/hypr/hyprsunset.conf
waybar conf: ~/.config/waybar/config.jsonc
waybar style: ~/.config/waybar/style.css
everythin in ~/.config/waybar/scripts
wofi config: ~/.config/wofi/config
wofi style: ~/.config/wofi/style.css
kitty config: ~/.config/kitty/kitty.conf
swaync style: ~/.config/swaync/style.css
## screensharing
```
sudo pacman -S xdg-desktop-portal-hyprland
```
## Joplin slow start
script in ~/scripts/joplin.sh
## Firefox blurry after monitor wake
In about:config, set `widget.wayland.fractional-scale.enabled = true`
+14
View File
@@ -0,0 +1,14 @@
# Global build config — the single source of truth for a rebuild.
# EDIT before running 01-install/run.sh; 02-system/run.sh reads it again later.
# --- install target (used by 01-install) ---
DISK=/dev/vda # TARGET DISK — WILL BE COMPLETELY ERASED (e.g. /dev/nvme0n1)
HOSTNAME=arch-th
USERNAME=tobias
TIMEZONE=Europe/Berlin
LOCALE=en_US.UTF-8
KEYMAP=de
# --- hardware / role (used by 02-system) ---
GPU=amd # amd | intel — installs 02-system/packages/graphics-<gpu>.txt
IS_DESKTOP=1 # 1 = desktop (no sleep, GPU fan/power tuning); 0 = laptop