Merge remote-tracking branch 'nixos-config/main'

This commit is contained in:
RealStickman 2023-05-21 14:12:24 +02:00
commit 58f60465ff
29 changed files with 1795 additions and 0 deletions

View File

@ -0,0 +1,15 @@
gtk-theme-name="Sweet-Dark"
#gtk-icon-theme-name="Sweet-Rainbow"
gtk-font-name="Fira Sans 12"
gtk-cursor-theme-name="capitaine-cursors-light"
gtk-cursor-theme-size=0
gtk-toolbar-style=GTK_TOOLBAR_ICONS
gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR
gtk-button-images=1
gtk-menu-images=1
gtk-enable-event-sounds=0
gtk-enable-input-feedback-sounds=0
gtk-xft-antialias=1
gtk-xft-hinting=1
gtk-xft-hintstyle="hintslight"
gtk-xft-rgba="rgb"

View File

@ -0,0 +1,16 @@
[Settings]
gtk-theme-name=Sweet-Dark
#gtk-icon-theme-name=Sweet-Rainbow
gtk-font-name=Fira Sans 12
gtk-cursor-theme-name=capitaine-cursors-light
gtk-cursor-theme-size=0
gtk-toolbar-style=GTK_TOOLBAR_ICONS
gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR
gtk-button-images=1
gtk-menu-images=1
gtk-enable-event-sounds=0
gtk-enable-input-feedback-sounds=0
gtk-xft-antialias=1
gtk-xft-hinting=1
gtk-xft-hintstyle=hintslight
gtk-xft-rgba=rgb

View File

@ -0,0 +1,16 @@
[Settings]
gtk-theme-name=Sweet-Dark
#gtk-icon-theme-name=Sweet-Rainbow
gtk-font-name=Fira Sans 12
gtk-cursor-theme-name=capitaine-cursors-light
gtk-cursor-theme-size=0
gtk-toolbar-style=GTK_TOOLBAR_ICONS
gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR
gtk-button-images=1
gtk-menu-images=1
gtk-enable-event-sounds=0
gtk-enable-input-feedback-sounds=0
gtk-xft-antialias=1
gtk-xft-hinting=1
gtk-xft-hintstyle=hintslight
gtk-xft-rgba=rgb

View File

@ -0,0 +1,19 @@
# Don't edit this file. Set the NixOS options security.sudo.configFile
# or security.sudo.extraRules instead.
# Set editor to nvim
Defaults editor=/run/current-system/sw/bin/nvim
# Keep SSH_AUTH_SOCK so that pam_ssh_agent_auth.so can do its magic.
Defaults env_keep+=SSH_AUTH_SOCK
# "root" is allowed to do anything.
root ALL=(ALL:ALL) SETENV: ALL
# extraRules
%wheel ALL=(ALL:ALL) SETENV: ALL
# Keep terminfo database for root and %wheel.
Defaults:root,%wheel env_keep+=TERMINFO_DIRS
Defaults:root,%wheel env_keep+=TERMINFO

View File

@ -0,0 +1,203 @@
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running `nixos-help`).
{ config, pkgs, ... }:
let
user = "exu";
hostname = "nixos";
in
{
imports = [
./hardware-configuration.nix
./system-packages.nix
./home-manager.nix
];
# Use the systemd-boot EFI boot loader.
boot.loader = {
systemd-boot = {
enable = true;
configurationLimit = 10;
};
efi = {
canTouchEfiVariables = true;
};
};
# Enable completions by nix
programs.fish.enable = true;
# set neovim as default
programs.neovim.enable = true;
programs.neovim.defaultEditor = true;
environment = {
shells = [ pkgs.fish ];
variables = {
EDITOR = "nvim";
VISUAL = "nvim";
SUDO_EDITOR = "nvim";
};
# remove nano from default packages
defaultPackages = [ pkgs.perl pkgs.rsync pkgs.strace ];
etc = {
# gtk theme configuration
# src: https://unix.stackexchange.com/questions/632879/how-to-set-a-system-wide-gtk-theme-in-nixos
"gtk-2.0/gtkrc".source = ./config/gtk-2.0/gtkrc;
"gtk-3.0/settings.ini".source = ./config/gtk-3.0/settings.ini;
"gtk-4.0/settings.ini".source = ./config/gtk-4.0/settings.ini;
};
};
networking.hostName = "${hostname}"; # Define your hostname.
# Pick only one of the below networking options.
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
networking.networkmanager.enable = true; # Easiest to use and most distros use this by default.
# disable global firewall for the time being
networking.firewall.enable = false;
# Set your time zone.
time.timeZone = "Europe/Zurich";
# Configure network proxy if necessary
# networking.proxy.default = "http://user:password@proxy:port/";
# networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
# Select internationalisation properties.
i18n.defaultLocale = "de_CH.UTF-8";
console = {
keyMap = "de_CH-latin1";
};
# Enable the X11 windowing system.
services.xserver = {
enable = true;
displayManager.defaultSession = "hyprland";
#displayManager.lightdm = {
# enable = true;
# greeters.gtk.enable = true;
#};
displayManager.gdm = {
enable = true;
wayland = true;
};
};
# enable gvfs service
services.gvfs.enable = true;
# Hyprland
security.polkit.enable = true;
programs.hyprland = {
enable = true;
};
# sudoers file
security.sudo.configFile = (builtins.readFile ./config/sudoers);
# Configure keymap in X11
services.xserver.layout = "ch";
# keyring
services.gnome.gnome-keyring.enable = true;
security.pam.services.${user}.enableGnomeKeyring = true;
programs.seahorse.enable = true;
# Enable CUPS to print documents.
services.printing.enable = true;
# Enable Pipewire
security.rtkit.enable = true;
services.pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;
# If you want to use JACK applications, uncomment this
#jack.enable = true;
};
# Enable touchpad support (enabled default in most desktopManager).
services.xserver.libinput.enable = true;
# root config
users.users.root = {
shell = pkgs.fish;
};
# User config
users.users.${user} = {
isNormalUser = true;
extraGroups = [ "wheel" "video" "audio" "networkmanager" "lp" "scanner" ];
initialPassword = "pass";
shell = pkgs.fish;
};
# Allow unfree packages
nixpkgs.config.allowUnfree = true;
# Some programs need SUID wrappers, can be configured further or are
# started in user sessions.
# programs.mtr.enable = true;
# programs.gnupg.agent = {
# enable = true;
# enableSSHSupport = true;
# };
# List services that you want to enable:
# Enable the OpenSSH daemon.
services.openssh.enable = true;
# Enable thumbnailer service
services.tumbler.enable = true;
# Open ports in the firewall.
# networking.firewall.allowedTCPPorts = [ ... ];
# networking.firewall.allowedUDPPorts = [ ... ];
# Or disable the firewall altogether.
# networking.firewall.enable = false;
# Copy the NixOS configuration file and link it from the resulting system
# (/run/current-system/configuration.nix). This is useful in case you
# accidentally delete configuration.nix.
# system.copySystemConfiguration = true;
# BTRFS options
fileSystems = {
"/".options = [ "compress=zstd" ];
"/home".options = [ "compress=zstd" ];
"/nix".options = [ "compress=zstd" "noatime" ];
"/swap".options = [ "noatime" ];
};
# Swapfile
swapDevices = [ { device = "/swap/swapfile"; } ];
# Enable automatic package upgrades
#system.autoUpgrade = {
# enable = true;
# channel = "https://nixos.org/channels/nixos-unstable";
#};
# Enable automatic garbage collection
nix = {
settings.auto-optimise-store = true;
gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 7d";
};
};
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. It's perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "22.11"; # Did you read the comment?
}

View File

@ -0,0 +1,141 @@
{ config, pkgs, ... }:
let
user = "exu";
hostname = "nixos";
in
{
imports = [
<home-manager/nixos>
];
# root home
home-manager.users.root = { pkgs, ... }: {
home.username = "root";
home.homeDirectory = "/root";
home.stateVersion = "22.11";
home.packages = with pkgs; [
kitty # terminfo support
];
imports = [
./home-manager/hyprland.nix
./home-manager/fish.nix
];
};
# keep everything using home manager within this block
home-manager.users.${user} = { pkgs, ... }: {
home.username = "${user}";
home.homeDirectory = "/home/${user}";
home.stateVersion = "22.11";
home.packages = with pkgs; [
firefox # browser
kitty # terminal
pciutils # lspci command
git # git
emacs # emacs editor
emacsPackages.doom # doom emacs configuration
acpilight # controlling laptop monitor backlight
networkmanagerapplet # network configuration
wofi # app launcher (wayland replacement for rofi)
fish # fish shell
libnotify # notifications
mako # notification daemon
xdg-desktop-portal-hyprland # desktop portal (hyprland fork)
#neovim # text editor
yt-dlp # video downloader
#sweet # gtk theme
waybar # status bar
playerctl # mpris
xfce.thunar # file manager
xfce.thunar-archive-plugin # manage archives in thunar
#xfce.xfce4-settings # xfce settings manager
xfce.xfconf # xfce config storage
];
imports = [
./home-manager/hyprland.nix
./home-manager/fish.nix
];
systemd.user = {
# user services
services = {
# ssh-agent user service
ssh-agent = {
Unit = {
Description = "SSH key agent";
};
Service = {
Type = "simple";
Environment = "SSH_AUTH_SOCK=%t/ssh-agent.socket";
ExecStart = "/run/current-system/sw/bin/ssh-agent -D -a $SSH_AUTH_SOCK";
};
Install = {
WantedBy = [ "default.target" ];
};
};
};
# user environment variables
sessionVariables = {
SSH_AUTH_SOCK = "/run/user/1000/ssh-agent.socket";
};
};
# git configuration
programs.git = {
enable = true;
extraConfig = {
init = {
defaultBranch = "main";
};
user = {
name = "RealStickman";
email = "mrc@frm01.net";
};
gitlab = {
user = "RealStickman";
};
github = {
user = "RealStickman";
};
};
};
programs.waybar = {
enable = true;
settings = {
mainBar = (builtins.fromJSON (builtins.readFile ./home-manager/config/waybar/config.json));
};
style = (builtins.readFile ./home-manager/config/waybar/style.css);
};
home.file = {
# Scripts
".scripts/waybar/player-mpris-tail.py" = {
source = ./home-manager/scripts/waybar/player-mpris-tail.py;
executable = true;
};
# Thunar configuration
".config/Thunar" = {
source = ./home-manager/config/Thunar;
#recursive = true;
};
# templates
".config/Vorlagen" = {
source = ./home-manager/config/Vorlagen;
#recursive = true;
};
# xfce4 settings
".config/xfce4".source = ./home-manager/config/xfce4;
# xdg user dirs
".config/user-dirs.dirs".source = ./home-manager/config/user-dirs.dirs;
# xdg user locales
".config/user-dirs.locale".source = ./home-manager/config/user-dirs.locale;
};
services.mako.enable = true;
};
}

View File

@ -0,0 +1,132 @@
; thunar GtkAccelMap rc-file -*- scheme -*-
; this file is an automated accelerator map dump
;
; (gtk_accel_path "<Actions>/ThunarBookmarks/fab0a703c3165b9ea6d4a2e40b570272" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/sort-by-type" "")
; (gtk_accel_path "<Actions>/ThunarBookmarks/134cf305a61c72f784680835c93c28fd" "")
; (gtk_accel_path "<Actions>/ThunarStatusBar/toggle-last-modified" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/cut" "<Primary>x")
; (gtk_accel_path "<Actions>/ThunarStandardView/sort-by-size" "")
; (gtk_accel_path "<Actions>/ThunarWindow/file-menu" "")
(gtk_accel_path "<Actions>/ThunarWindow/close-tab" "<Primary>q")
; (gtk_accel_path "<Actions>/ThunarStatusBar/toggle-size" "")
(gtk_accel_path "<Actions>/ThunarWindow/new-window" "")
; (gtk_accel_path "<Actions>/ThunarWindow/clear-directory-specific-settings" "")
(gtk_accel_path "<Actions>/ThunarWindow/close-window" "")
; (gtk_accel_path "<Actions>/ThunarBookmarks/ac3bbb1429c4180d34b90e935eaeaa7b" "")
(gtk_accel_path "<Actions>/ThunarWindow/open-parent" "")
; (gtk_accel_path "<Actions>/ThunarWindow/view-side-pane-menu" "")
; (gtk_accel_path "<Actions>/ThunarStatusBar/toggle-size-in-bytes" "")
; (gtk_accel_path "<Actions>/ThunarWindow/switch-previous-tab" "<Primary>Page_Up")
; (gtk_accel_path "<Actions>/ThunarBookmarks/3cb76eced52269e016bf542f6d20d431" "")
(gtk_accel_path "<Actions>/ThunarActionManager/open" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/sort-ascending" "")
; (gtk_accel_path "<Actions>/ThunarWindow/toggle-split-view" "F3")
; (gtk_accel_path "<Actions>/ThunarActionManager/copy-2" "<Primary>Insert")
; (gtk_accel_path "<Actions>/ThunarActionManager/trash-delete" "Delete")
; (gtk_accel_path "<Actions>/ThunarWindow/open-recent" "")
; (gtk_accel_path "<Actions>/ThunarWindow/view-configure-toolbar" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/forward" "<Alt>Right")
; (gtk_accel_path "<Actions>/ThunarBookmarks/9f9804d3a8acb92d2796c0e9ee791891" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/restore" "")
(gtk_accel_path "<Actions>/ThunarWindow/open-location-alt" "")
; (gtk_accel_path "<Actions>/ThunarBookmarks/0d63283611773acfd219c84ae028d009" "")
(gtk_accel_path "<Actions>/ThunarStandardView/select-by-pattern" "")
; (gtk_accel_path "<Actions>/ThunarWindow/zoom-out-alt" "<Primary>minus")
; (gtk_accel_path "<Actions>/ThunarWindow/open-file-menu" "F10")
(gtk_accel_path "<Actions>/ThunarWindow/contents" "")
; (gtk_accel_path "<Actions>/ThunarWindow/show-highlight" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/sort-descending" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/sort-by-name" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/select-all-files" "<Primary>a")
; (gtk_accel_path "<Actions>/ThunarActionManager/execute" "")
(gtk_accel_path "<Actions>/ThunarStandardView/properties" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/cut-2" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/sort-by-dtime" "")
; (gtk_accel_path "<Actions>/ThunarWindow/switch-next-tab" "<Primary>Page_Down")
; (gtk_accel_path "<Actions>/ThunarActionManager/paste-2" "<Shift>Insert")
; (gtk_accel_path "<Actions>/ThunarWindow/open-templates" "")
; (gtk_accel_path "<Actions>/ThunarStatusBar/toggle-filetype" "")
(gtk_accel_path "<Actions>/ThunarWindow/close-all-windows" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/create-document" "")
; (gtk_accel_path "<Actions>/ThunarWindow/detach-tab" "")
; (gtk_accel_path "<Actions>/ThunarBookmarks/310a68ed4e8d7e3153dbac6fd6f8509e" "")
; (gtk_accel_path "<Actions>/ThunarWindow/cancel-search" "Escape")
; (gtk_accel_path "<Actions>/ThunarWindow/zoom-in-alt2" "<Primary>equal")
(gtk_accel_path "<Actions>/ThunarShortcutsPane/sendto-shortcuts" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/undo" "<Primary>z")
; (gtk_accel_path "<Actions>/ThunarWindow/reload-alt" "F5")
(gtk_accel_path "<Actions>/ThunarActions/uca-action-1666515885637912-1" "<Primary>Return")
; (gtk_accel_path "<Actions>/ThunarStandardView/toggle-sort-order" "")
; (gtk_accel_path "<Actions>/ThunarWindow/view-location-selector-entry" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/paste" "<Primary>v")
; (gtk_accel_path "<Actions>/ThunarWindow/zoom-in-alt1" "<Primary>plus")
(gtk_accel_path "<Actions>/ThunarWindow/view-menubar" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/back" "<Alt>Left")
; (gtk_accel_path "<Actions>/ThunarWindow/open-desktop" "")
(gtk_accel_path "<Actions>/ThunarWindow/view-as-detailed-list" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/restore-show" "")
; (gtk_accel_path "<Actions>/ThunarStatusBar/toggle-display-name" "")
; (gtk_accel_path "<Actions>/ThunarWindow/zoom-out" "<Primary>KP_Subtract")
; (gtk_accel_path "<Actions>/ThunarBookmarks/d560a9adc56f1eaa2739d7e989051c36" "")
; (gtk_accel_path "<Actions>/ThunarWindow/sendto-menu" "")
; (gtk_accel_path "<Actions>/ThunarWindow/go-menu" "")
; (gtk_accel_path "<Actions>/ThunarWindow/remove-from-recent" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/open-with-other" "")
(gtk_accel_path "<Actions>/ThunarStandardView/invert-selection" "<Primary>i")
(gtk_accel_path "<Actions>/ThunarWindow/view-side-pane-shortcuts" "")
; (gtk_accel_path "<Actions>/ThunarWindow/view-location-selector-menu" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/sort-by-mtime" "")
; (gtk_accel_path "<Actions>/ThunarWindow/edit-menu" "")
; (gtk_accel_path "<Actions>/ThunarWindow/reload" "<Primary>r")
; (gtk_accel_path "<Actions>/ThunarActionManager/copy" "<Primary>c")
; (gtk_accel_path "<Actions>/ThunarActionManager/move-to-trash" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/unselect-all-files" "Escape")
; (gtk_accel_path "<Actions>/ThunarActionManager/delete-3" "<Shift>KP_Delete")
(gtk_accel_path "<Actions>/ThunarWindow/toggle-side-pane" "")
; (gtk_accel_path "<Actions>/ThunarBookmarks/bd09eece7395e751859c8153dca05324" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/arrange-items-menu" "")
; (gtk_accel_path "<Actions>/ThunarBookmarks/ef49cad9a2b186bac59b8de045e0f5d4" "")
; (gtk_accel_path "<Actions>/ThunarWindow/open-computer" "")
; (gtk_accel_path "<Actions>/ThunarWindow/bookmarks-menu" "")
; (gtk_accel_path "<Actions>/ThunarWindow/toggle-image-preview" "")
(gtk_accel_path "<Actions>/ThunarWindow/view-as-icons" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/delete-2" "<Shift>Delete")
; (gtk_accel_path "<Actions>/ThunarWindow/zoom-in" "<Primary>KP_Add")
; (gtk_accel_path "<Actions>/ThunarStandardView/configure-columns" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/rename" "F2")
; (gtk_accel_path "<Actions>/ThunarWindow/open-location" "<Primary>l")
(gtk_accel_path "<Actions>/ThunarWindow/view-as-compact-list" "")
; (gtk_accel_path "<Actions>/ThunarWindow/view-menu" "")
; (gtk_accel_path "<Actions>/ThunarWindow/search" "<Primary>f")
; (gtk_accel_path "<Actions>/ThunarWindow/new-tab" "<Primary>t")
; (gtk_accel_path "<Actions>/ThunarWindow/zoom-reset" "<Primary>KP_0")
; (gtk_accel_path "<Actions>/ThunarWindow/contents/help-menu" "")
(gtk_accel_path "<Actions>/ThunarActionManager/open-in-new-tab" "")
; (gtk_accel_path "<Actions>/ThunarWindow/view-location-selector-buttons" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/redo" "<Primary><Shift>z")
; (gtk_accel_path "<Actions>/ThunarWindow/open-trash" "")
; (gtk_accel_path "<Actions>/ThunarBookmarks/7d2c0d8f2cb46dda0c77c334948613d9" "")
(gtk_accel_path "<Actions>/ThunarActionManager/open-in-new-window" "")
; (gtk_accel_path "<Actions>/ThunarWindow/view-statusbar" "")
; (gtk_accel_path "<Actions>/ThunarBookmarks/356c14bf86880b16a82a896aac1ea75d" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/open-location" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/duplicate" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/trash-delete-2" "KP_Delete")
; (gtk_accel_path "<Actions>/ThunarBookmarks/efbd1f6870be1a5a9ee9ba157935b388" "")
(gtk_accel_path "<Actions>/ThunarActions/uca-action-1666516933235505-2" "<Primary>f")
; (gtk_accel_path "<Actions>/ThunarStandardView/create-folder" "<Primary><Shift>n")
(gtk_accel_path "<Actions>/ThunarWindow/open-home" "")
(gtk_accel_path "<Actions>/ThunarWindow/show-hidden" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/set-default-app" "")
; (gtk_accel_path "<Actions>/ThunarWindow/empty-trash" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/back-alt" "BackSpace")
; (gtk_accel_path "<Actions>/ThunarWindow/preferences" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/delete" "")
(gtk_accel_path "<Actions>/ThunarWindow/view-side-pane-tree" "")
; (gtk_accel_path "<Actions>/ThunarWindow/open-file-system" "")
; (gtk_accel_path "<Actions>/ThunarWindow/open-network" "")
; (gtk_accel_path "<Actions>/ThunarActionManager/sendto-desktop" "")
; (gtk_accel_path "<Actions>/ThunarStandardView/make-link" "")
; (gtk_accel_path "<Actions>/ThunarWindow/zoom-reset-alt" "<Primary>0")
; (gtk_accel_path "<Actions>/ThunarWindow/about" "")

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<actions>
<action>
<icon>folder</icon>
<name>Als root öffnen</name>
<submenu></submenu>
<unique-id>1673031093097554-1</unique-id>
<command>gksu thunar %f</command>
<description>Verzeichnis als root-Nutzer öffnen</description>
<range>*</range>
<patterns>*</patterns>
<directories/>
</action>
<action>
<icon>utilities-terminal</icon>
<name>Terminal öffnen</name>
<submenu></submenu>
<unique-id>1666515885637912-1</unique-id>
<command>for f in %F; do if [ -d &quot;$f&quot; ]; then kitty &quot;$f&quot;; elif [ -z &quot;$default&quot; ]; then default=1; kitty; fi done</command>
<description>Terminal im gewählten Ordner öffnen</description>
<range></range>
<patterns>*</patterns>
<startup-notify/>
<directories/>
<audio-files/>
<image-files/>
<other-files/>
<text-files/>
<video-files/>
</action>
<action>
<icon>preferences-system-search</icon>
<name>Suchen</name>
<submenu></submenu>
<unique-id>1666516933235505-2</unique-id>
<command>catfish --path=%f</command>
<description>Dateien und Ordner suchen</description>
<range></range>
<patterns>*</patterns>
<startup-notify/>
<directories/>
</action>
<action>
<icon>link</icon>
<name>Symlink erstellen</name>
<submenu></submenu>
<unique-id>1676990164646243-1</unique-id>
<command>ln -Ts %f %n&quot; (symlink)&quot;</command>
<description>Symbolischen Link erstellen</description>
<range>*</range>
<patterns>*</patterns>
<directories/>
<audio-files/>
<image-files/>
<other-files/>
<text-files/>
<video-files/>
</action>
</actions>

View File

@ -0,0 +1 @@
<mxfile host="Electron" modified="2022-09-16T06:39:11.723Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.3.0 Chrome/104.0.5112.114 Electron/20.1.3 Safari/537.36" etag="3qCqwMKNhbMENT5RahAg" version="20.3.0" type="device"><diagram id="sNatUqG7UvmBRNr3f2vi" name="Seite-1">dZFND8IgDIZ/DfcBRvE8vy6edvBMRh0kbF0YZtNf7xaYk0xPlOd9S2lLeF4PZydbfUUFlrBMDYQfCGN0Q8V4TOQZiBA0gMoZFU0LKMwLIswifRgFXWL0iNabNoUlNg2UPmHSOexT2x1tWrWVFaxAUUq7pjejvI6UbveLcAFT6VhasF0QajmbYyedlgr7L8SPhOcO0YeoHnKw0/DmuYS80x/18zEHjf+RMAbL2+Ml2RA/vgE=</diagram></mxfile>

View File

@ -0,0 +1,3 @@
<link href="/home/marc/GitProjects/markdown-css/markdown.css" rel="stylesheet"></link>
# Document Title

View File

@ -0,0 +1,35 @@
#vi mode for fish
#fish_vi_key_bindings
fish_default_key_bindings
# change greeting
set fish_greeting "Good Morning! Nice day for fishing ain't it! Hu ha!"
# Info:
# https://fishshell.com/docs/current/index.html#variables-for-changing-highlighting-colors
set fish_color_normal blue
set fish_color_command blue
set fish_color_quote bryellow
set fish_color_redirection
set fish_color_end brred
set fish_color_error red
set fish_color_param brblue
set fish_color_comment white
set fish_color_selection brcyan
set fish_color_search_match magenta
set fish_color_operator blue
set fish_color_escape green
set fish_color_autosuggestion brwhite
set fish_color_host_remote brwhite
set fish_color_cancel brred
# used in prompt
set fish_color_user --bold red
set fish_color_separator --bold yellow
set fish_color_host cyan
set fish_color_cwd yellow
# environment variables
# SSH Agent
set SSH_AUTH_SOCK "$XDG_RUNTIME_DIR/ssh-agent.socket"
export SSH_AUTH_SOCK

View File

@ -0,0 +1,32 @@
set -l last_pipestatus $pipestatus
set -lx __fish_last_status $status # Export for __fish_print_pipestatus.
set -l normal (set_color normal)
# Color the prompt differently when we're root
set -l color_cwd $fish_color_cwd
set -l suffix '>'
#if functions -q fish_is_root_user; and fish_is_root_user
# if set -q fish_color_cwd_root
# set color_cwd $fish_color_cwd_root
# end
# set suffix '#'
#end
# If we're running via SSH, change the host color.
set -l color_host $fish_color_host
#if set -q SSH_TTY
# set color_host $fish_color_host_remote
#end
# Write pipestatus
# If the status was carried over (e.g. after `set`), don't bold it.
set -l bold_flag --bold
set -q __fish_prompt_status_generation; or set -g __fish_prompt_status_generation $status_generation
if test $__fish_prompt_status_generation = $status_generation
set bold_flag
end
set __fish_prompt_status_generation $status_generation
set -l prompt_status (__fish_print_pipestatus "[" "]" "|" (set_color $fish_color_status) (set_color $bold_flag $fish_color_status) $last_pipestatus)
echo -n -s (set_color $fish_color_user) "$USER" $normal (set_color $fish_color_separator) @ $normal (set_color $color_host) (prompt_hostname) $normal ' ' (set_color $color_cwd) (prompt_pwd) $normal (fish_vcs_prompt) $normal " "$prompt_status $suffix " "
#echo -n -s (set_color --bold red) "$USER" $normal (set_color --bold yellow) @ $normal (set_color cyan) (prompt_hostname) $normal ' ' (set_color yellow) (prompt_pwd) $normal (fish_vcs_prompt) $normal " "$prompt_status $suffix " "

View File

@ -0,0 +1,201 @@
#
# Please note not all available settings / options are set here.
# For a full list, see the wiki
#
# See https://wiki.hyprland.org/Configuring/Monitors/
monitor=,preferred,auto,auto
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
# Execute your favorite apps at launch
# exec-once = waybar & hyprpaper & firefox
# Source a file (multi-file configs)
# source = ~/.config/hypr/myColors.conf
# Some default env vars.
env = XCURSOR_SIZE,24
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
input {
#kb_layout = de_CH-latin1
kb_layout = ch
kb_variant =
kb_model =
kb_options =
kb_rules =
follow_mouse = 1
touchpad {
natural_scroll = false
}
sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
}
general {
# See https://wiki.hyprland.org/Configuring/Variables/ for more
gaps_in = 0
gaps_out = 0
border_size = 2
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
col.inactive_border = rgba(595959aa)
layout = dwindle
}
decoration {
# See https://wiki.hyprland.org/Configuring/Variables/ for more
#rounding = 10
blur = yes
blur_size = 3
blur_passes = 1
blur_new_optimizations = on
drop_shadow = yes
shadow_range = 4
shadow_render_power = 3
col.shadow = rgba(1a1a1aee)
}
animations {
enabled = yes
# Some default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
bezier = myBezier, 0.05, 0.9, 0.1, 1.05
animation = windows, 1, 7, myBezier
animation = windowsOut, 1, 7, default, popin 80%
animation = border, 1, 10, default
animation = borderangle, 1, 8, default
animation = fade, 1, 7, default
animation = workspaces, 1, 6, default
}
dwindle {
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
pseudotile = yes # master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
preserve_split = yes # you probably want this
}
master {
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
new_is_master = true
}
gestures {
# See https://wiki.hyprland.org/Configuring/Variables/ for more
workspace_swipe = off
}
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
#device:epic-mouse-v1 {
# sensitivity = -0.5
#}
# Example windowrule v1
# windowrule = float, ^(kitty)$
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
$mod = SUPER
# Startup stuff
exec-once = mako
exec-once = waybar
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind = CTRL_ALT, RETURN, exec, kitty # terminal
bind = CTRL_ALT, A, exec, wofi --show drun # app launcher
bind = CTRL_ALT, f, exec, firefox # browser
bind = CTRL_ALT, e, exec, emacs # editor
bind = CTRL_ALT, t, exec, thunar # file manager
bind = $mod, Q, killactive, # close window
# logout
bind = ALT_$mod, L, exit,
# bind power management submap
bind = $mod, x, submap, | (S)hutdown, (R)eboot, (E)xit |
# power management submap
submap = | (S)hutdown, (R)eboot, (E)xit |
# logout
bind = , e, exit,
# lock
# TODO
# poweroff
bind = , s, exec, systemctl poweroff
# reboot
bind = , r, exec, systemctl reboot
# use reset to go back to the global submap
bind=,escape,submap,reset
# will reset the submap, meaning end the current one and return to the global one
submap=reset
#bind = $mod, Q, exec, kitty
#bind = $mod, C, killactive,
#bind = $mod, M, exit,
#bind = $mod, E, exec, dolphin
#bind = $mod, V, togglefloating,
#bind = $mod, R, exec, wofi --show drun
#bind = $mod, P, pseudo, # dwindle
#bind = $mod, J, togglesplit, # dwindle
# Move focus with $mod + arrow keys
bind = $mod, left, movefocus, l
bind = $mod, right, movefocus, r
bind = $mod, up, movefocus, u
bind = $mod, down, movefocus, d
# Move focus with $mod + hjkl
bind = $mod, H, movefocus, l
bind = $mod, L, movefocus, r
bind = $mod, K, movefocus, u
bind = $mod, J, movefocus, d
# Switch workspaces with mainMod + [0-9]
bind = $mod, 1, workspace, 1
bind = $mod, 2, workspace, 2
bind = $mod, 3, workspace, 3
bind = $mod, 4, workspace, 4
bind = $mod, 5, workspace, 5
bind = $mod, 6, workspace, 6
bind = $mod, 7, workspace, 7
bind = $mod, 8, workspace, 8
bind = $mod, 9, workspace, 9
bind = $mod, 0, workspace, 10
# Move active window to a workspace with mainMod + SHIFT + [0-9]
bind = $mod SHIFT, 1, movetoworkspace, 1
bind = $mod SHIFT, 2, movetoworkspace, 2
bind = $mod SHIFT, 3, movetoworkspace, 3
bind = $mod SHIFT, 4, movetoworkspace, 4
bind = $mod SHIFT, 5, movetoworkspace, 5
bind = $mod SHIFT, 6, movetoworkspace, 6
bind = $mod SHIFT, 7, movetoworkspace, 7
bind = $mod SHIFT, 8, movetoworkspace, 8
bind = $mod SHIFT, 9, movetoworkspace, 9
bind = $mod SHIFT, 0, movetoworkspace, 10
# Scroll through existing workspaces with $mod + scroll
bind = $mod, mouse_down, workspace, e+1
bind = $mod, mouse_up, workspace, e-1
# Move/resize windows with mainMod + LMB/RMB and dragging
bindm = $mod, mouse:272, movewindow
bindm = $mod, mouse:273, resizewindow

View File

@ -0,0 +1,15 @@
# This file is written by xdg-user-dirs-update
# If you want to change or add directories, just edit the line you're
# interested in. All local changes will be retained on the next run.
# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an
# absolute path. No other format is supported.
#
XDG_DESKTOP_DIR="$HOME/Schreibtisch"
XDG_DOWNLOAD_DIR="$HOME/Downloads"
XDG_TEMPLATES_DIR="$HOME/.config/Vorlagen"
XDG_PUBLICSHARE_DIR="$HOME/Öffentlich"
XDG_DOCUMENTS_DIR="$HOME/Dokumente"
XDG_MUSIC_DIR="$HOME/Musik"
XDG_PICTURES_DIR="$HOME/Bilder"
XDG_VIDEOS_DIR="$HOME/Videos"

View File

@ -0,0 +1 @@
de_CH

View File

@ -0,0 +1,70 @@
{
"layer": "top",
"position": "bottom",
"height": 25,
"spacing": 10,
"modules-left": ["wlr/workspaces", "hyprland/window", "hyprland/submap"],
"modules-center": ["clock"],
"modules-right": ["mpris", "idle_inhibitor", "battery", "tray"],
"wlr/workspaces": {
"format": "{name}: {icon}",
"format-icons": {
"urgent": "",
"active": "",
"default": ""
},
"sort-by-number": true
},
"hyprland/window": {
"format": "{}",
"separate-outputs": true
},
"hyprland/submap": {
"format": "{}",
"tooltip": false
},
"mpris": {
"format": "{status_icon} {dynamic}",
"format-paused": "{status_icon} <i>{dynamic}</i>",
"status-icons": {
"playing": "▶",
"paused": "⏸"
}
},
"battery": {
"bat": "BAT0",
"states": {
"warning": 30,
"critical": 15
},
"format": "{capacity}% {icon}",
"format-charging": "{capacity}% ",
"format-plugged": "{capacity}% ",
"format-alt": "{time} {icon}",
"format-icons": ["", "", "", "", ""]
},
"clock": {
"timezone": "Europe/Zurich",
"tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>",
"format-alt": "{:%Y-%m-%d}"
},
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
"activated": "",
"deactivated": ""
}
},
"tray": {
"icon-size": 21,
"spacing": 10
},
"custom/mpris": {
"exec": "~/.scripts/polybar/player-mpris-tail.py -f '{icon} {:artist:t10:{artist}:}{:artist: - :}{:t25:{title}:}'",
"on-click": "~/.scripts/polybar/player-mpris-tail.py play-pause &",
"on-click-middle": "~/.scripts/polybar/player-mpris-tail.py next &",
"on-click-right": "~/.scripts/polybar/player-mpris-tail.py previous &"
}
}

View File

@ -0,0 +1,145 @@
* {
/* `otf-font-awesome` is required to be installed for icons */
font-family: FontAwesome, Fira Sans, sans-serif;
font-size: 12px;
padding-left: 5px;
padding-right: 5px;
}
window#waybar {
/*background-color: rgba(43, 48, 59, 0.5);*/
background-color: rgba(51, 2, 47, 0.6);
border: 0px;
border-top: 2px solid rgba(93, 4, 86, 0.8);
/*border-bottom: 3px solid rgba(100, 114, 125, 0.5);*/
color: #f2daf0;
/*color: #ffffff;*/
transition-property: background-color;
transition-duration: 0.5s;
}
window#waybar.hidden {
opacity: 0.2;
}
/*
window#waybar.empty {
background-color: transparent;
}
window#waybar.solo {
background-color: #FFFFFF;
}
*/
button {
/* Use box-shadow instead of border so the text isn't offset */
box-shadow: inset 0 -3px transparent;
/* Avoid rounded borders under each button name */
border: none;
border-radius: 0;
}
/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
button:hover {
background: inherit;
box-shadow: inset 0 -3px #ffffff;
}
#workspaces button {
padding: 0 5px;
background-color: transparent;
color: #ffffff;
}
#workspaces button:hover {
background: rgba(0, 0, 0, 0.2);
}
#workspaces button.focused {
background-color: #64727d;
box-shadow: inset 0 -3px #ffffff;
}
#workspaces button.urgent {
background-color: #eb4d4b;
}
#mode {
background-color: #64727d;
border-bottom: 3px solid #ffffff;
}
#clock,
#battery,
#tray,
#mode,
#idle_inhibitor,
#window,
#workspaces {
margin: 0 4px;
}
/* If workspaces is the leftmost module, omit left margin */
.modules-left > widget:first-child > #workspaces {
margin-left: 0;
}
/* If workspaces is the rightmost module, omit right margin */
.modules-right > widget:last-child > #workspaces {
margin-right: 0;
}
#clock {
background-color: #5d0456;
}
#battery {
background-color: #5d0456;
color: #f2daf0;
/*color: #000000;*/
}
@keyframes blink {
to {
background-color: #f2daf0;
color: #000000;
}
}
#battery.critical:not(.charging) {
background-color: #ca3232;
color: #f2daf0;
animation-name: blink;
animation-duration: 0.5s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-direction: alternate;
}
label:focus {
background-color: #000000;
}
/*
#tray {
background-color: #2980b9;
}
#tray > .passive {
-gtk-icon-effect: dim;
}
#tray > .needs-attention {
-gtk-icon-effect: highlight;
background-color: #eb4d4b;
}
*/
#idle_inhibitor {
background-color: #5d0456;
}
#idle_inhibitor.activated {
background-color: #f2daf0;
color: #5d0456;
}

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<channel name="thunar" version="1.0">
<property name="last-view" type="string"
value="ThunarDetailsView" />
<property name="last-icon-view-zoom-level" type="string"
value="THUNAR_ZOOM_LEVEL_400_PERCENT" />
<property name="last-separator-position" type="int"
value="189" />
<property name="last-show-hidden" type="bool" value="true" />
<property name="last-window-width" type="int" value="956" />
<property name="last-window-height" type="int" value="1056" />
<property name="last-window-maximized" type="bool"
value="false" />
<property name="last-details-view-zoom-level" type="string"
value="THUNAR_ZOOM_LEVEL_38_PERCENT" />
<property name="last-details-view-column-widths" type="string"
value="50,155,155,148,150,237,50,79,370,379,50,92,50,775" />
<property name="misc-date-style" type="string"
value="THUNAR_DATE_STYLE_ISO" />
<property name="misc-single-click" type="bool" value="false" />
<property name="misc-show-delete-action" type="bool"
value="true" />
<property name="misc-full-path-in-title" type="bool"
value="true" />
<property name="last-location-bar" type="string"
value="ThunarLocationEntry" />
<property name="last-sort-column" type="string"
value="THUNAR_COLUMN_NAME" />
<property name="last-sort-order" type="string"
value="GTK_SORT_ASCENDING" />
<property name="misc-recursive-permissions" type="string"
value="THUNAR_RECURSIVE_PERMISSIONS_ALWAYS" />
<property name="last-details-view-visible-columns" type="string"
value="THUNAR_COLUMN_DATE_MODIFIED,THUNAR_COLUMN_NAME,THUNAR_COLUMN_SIZE,THUNAR_COLUMN_TYPE" />
<property name="misc-folders-first" type="bool" value="true" />
<property name="last-side-pane" type="string"
value="ThunarShortcutsPane" />
<property name="last-menubar-visible" type="bool" value="true" />
<property name="misc-confirm-close-multiple-tabs" type="bool"
value="false" />
<property name="default-view" type="string"
value="ThunarDetailsView" />
<property name="misc-middle-click-in-tab" type="bool"
value="true" />
<property name="misc-volume-management" type="bool"
value="false" />
<property name="misc-parallel-copy-mode" type="string"
value="THUNAR_PARALLEL_COPY_MODE_ONLY_LOCAL" />
<property name="misc-transfer-verify-file" type="string"
value="THUNAR_VERIFY_FILE_MODE_REMOTE" />
<property name="last-splitview-separator-position" type="int"
value="717" />
<property name="misc-folder-item-count" type="string"
value="THUNAR_FOLDER_ITEM_COUNT_ALWAYS" />
<property name="misc-transfer-use-partial" type="string"
value="THUNAR_USE_PARTIAL_MODE_REMOTE" />
</channel>

View File

@ -0,0 +1,39 @@
{ config, ... }:
{
programs.fish = {
enable = true;
interactiveShellInit = (builtins.readFile ./config/fish/conf.d/interactive.fish);
shellAliases = {
# open emacs in terminal
emacs = "emacs --no-window-system";
# colored wget output
wget = "wget -c";
# copy terminfo to remote server with kitty
sshkp = "kitty +kitten ssh use-python";
sshk = "kitty +kitten ssh";
# colored ls output
ls = "ls --color=auto";
# kill all wine processes
killwine = "ls -l /proc/*/exe 2>/dev/null | grep -E 'wine(64)?-preloader|wineserver' | perl -pe 's;^.*/proc/(\d+)/exe.*$;$1;g;' | xargs -n 1 kill";
# colored grep output
grep = "grep --color=auto";
# yt-dlp aliases
# best audio
yta-best = "yt-dlp -f bestaudio --extract-audio ";
# best video
ytv-best = "yt-dlp -f bestvideo+bestaudio ";
# download video including metadata from youtube
ytv-metadata = "yt-dlp -f bestvideo+bestaudio --add-metadata --parse-metadata \"%(title)s:%(meta_title)s\" --parse-metadata \"%(uploader)s:%(meta_artist)s\" --write-info-json --write-thumbnail --embed-thumbnail --embed-subs --sub-langs \"en.*\" --merge-output-format mkv ";
# activate venv called "venv" in the local directory
activate = "source venv/bin/activate.fish";
# lsblk including file system type
lsblkf = "lsblk -o NAME,FSTYPE,LABEL,MOUNTPOINT,SIZE,MODEL,UUID";
# color ip command
ip = "ip -c";
};
functions = {
fish_prompt = (builtins.readFile ./config/fish/functions/fish_prompt.fish);
};
};
}

View File

@ -0,0 +1,20 @@
{pkgs, ...}:
let
flake-compat = builtins.fetchTarball "https://github.com/edolstra/flake-compat/archive/master.tar.gz";
hyprland = (import flake-compat {
src = builtins.fetchTarball "https://github.com/hyprwm/Hyprland/archive/master.tar.gz";
}).defaultNix;
in
{
imports = [
hyprland.homeManagerModules.default
];
wayland.windowManager.hyprland = {
enable = true;
extraConfig = (builtins.readFile ./config/hypr/hyprland.conf);
};
}

View File

@ -0,0 +1,530 @@
#!/usr/bin/env python3
import sys
import dbus
import os
from operator import itemgetter
import argparse
import re
from urllib.parse import unquote
import time
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib
DBusGMainLoop(set_as_default=True)
FORMAT_STRING = '{icon} {artist} - {title}'
FORMAT_REGEX = re.compile(r'(\{:(?P<tag>.*?)(:(?P<format>[wt])(?P<formatlen>\d+))?:(?P<text>.*?):\})', re.I)
FORMAT_TAG_REGEX = re.compile(r'(?P<format>[wt])(?P<formatlen>\d+)')
SAFE_TAG_REGEX = re.compile(r'[{}]')
class PlayerManager:
def __init__(self, blacklist = [], connect = True):
self.blacklist = blacklist
self._connect = connect
self._session_bus = dbus.SessionBus()
self.players = {}
self.print_queue = []
self.connected = False
self.player_states = {}
self.refreshPlayerList()
if self._connect:
self.connect()
loop = GLib.MainLoop()
try:
loop.run()
except KeyboardInterrupt:
print("interrupt received, stopping…")
def connect(self):
self._session_bus.add_signal_receiver(self.onOwnerChangedName, 'NameOwnerChanged')
self._session_bus.add_signal_receiver(self.onChangedProperties, 'PropertiesChanged',
path = '/org/mpris/MediaPlayer2',
sender_keyword='sender')
def onChangedProperties(self, interface, properties, signature, sender = None):
if sender in self.players:
player = self.players[sender]
# If we know this player, but haven't been able to set up a signal handler
if 'properties_changed' not in player._signals:
# Then trigger the signal handler manually
player.onPropertiesChanged(interface, properties, signature)
else:
# If we don't know this player, get its name and add it
bus_name = self.getBusNameFromOwner(sender)
if bus_name is None:
return
self.addPlayer(bus_name, sender)
player = self.players[sender]
player.onPropertiesChanged(interface, properties, signature)
def onOwnerChangedName(self, bus_name, old_owner, new_owner):
if self.busNameIsAPlayer(bus_name):
if new_owner and not old_owner:
self.addPlayer(bus_name, new_owner)
elif old_owner and not new_owner:
self.removePlayer(old_owner)
else:
self.changePlayerOwner(bus_name, old_owner, new_owner)
def getBusNameFromOwner(self, owner):
player_bus_names = [ bus_name for bus_name in self._session_bus.list_names() if self.busNameIsAPlayer(bus_name) ]
for player_bus_name in player_bus_names:
player_bus_owner = self._session_bus.get_name_owner(player_bus_name)
if owner == player_bus_owner:
return player_bus_name
def busNameIsAPlayer(self, bus_name):
return bus_name.startswith('org.mpris.MediaPlayer2') and bus_name.split('.')[3] not in self.blacklist
def refreshPlayerList(self):
player_bus_names = [ bus_name for bus_name in self._session_bus.list_names() if self.busNameIsAPlayer(bus_name) ]
for player_bus_name in player_bus_names:
self.addPlayer(player_bus_name)
if self.connected != True:
self.connected = True
self.printQueue()
def addPlayer(self, bus_name, owner = None):
player = Player(self._session_bus, bus_name, owner = owner, connect = self._connect, _print = self.print)
self.players[player.owner] = player
def removePlayer(self, owner):
if owner in self.players:
self.players[owner].disconnect()
del self.players[owner]
# If there are no more players, clear the output
if len(self.players) == 0:
_printFlush(ICON_NONE)
# Else, print the output of the next active player
else:
players = self.getSortedPlayerOwnerList()
if len(players) > 0:
self.players[players[0]].printStatus()
def changePlayerOwner(self, bus_name, old_owner, new_owner):
player = Player(self._session_bus, bus_name, owner = new_owner, connect = self._connect, _print = self.print)
self.players[new_owner] = player
del self.players[old_owner]
# Get a list of player owners sorted by current status and age
def getSortedPlayerOwnerList(self):
players = [
{
'number': int(owner.split('.')[-1]),
'status': 2 if player.status == 'playing' else 1 if player.status == 'paused' else 0,
'owner': owner
}
for owner, player in self.players.items()
]
return [ info['owner'] for info in reversed(sorted(players, key=itemgetter('status', 'number'))) ]
# Get latest player that's currently playing
def getCurrentPlayer(self):
playing_players = [
player_owner for player_owner in self.getSortedPlayerOwnerList()
if
self.players[player_owner].status == 'playing' or
self.players[player_owner].status == 'paused'
]
return self.players[playing_players[0]] if playing_players else None
def print(self, status, player):
self.player_states[player.bus_name] = status
if self.connected:
current_player = self.getCurrentPlayer()
if current_player != None:
_printFlush(self.player_states[current_player.bus_name])
else:
_printFlush(ICON_STOPPED)
else:
self.print_queue.append([status, player])
def printQueue(self):
for args in self.print_queue:
self.print(args[0], args[1])
self.print_queue.clear()
class Player:
def __init__(self, session_bus, bus_name, owner = None, connect = True, _print = None):
self._session_bus = session_bus
self.bus_name = bus_name
self._disconnecting = False
self.__print = _print
self.metadata = {
'artist' : '',
'album' : '',
'title' : '',
'track' : 0
}
self._rate = 1.
self._positionAtLastUpdate = 0.
self._timeAtLastUpdate = time.time()
self._positionTimerRunning = False
self._metadata = None
self.status = 'stopped'
self.icon = ICON_NONE
self.icon_reversed = ICON_PLAYING
if owner is not None:
self.owner = owner
else:
self.owner = self._session_bus.get_name_owner(bus_name)
self._obj = self._session_bus.get_object(self.bus_name, '/org/mpris/MediaPlayer2')
self._properties_interface = dbus.Interface(self._obj, dbus_interface='org.freedesktop.DBus.Properties')
self._introspect_interface = dbus.Interface(self._obj, dbus_interface='org.freedesktop.DBus.Introspectable')
self._media_interface = dbus.Interface(self._obj, dbus_interface='org.mpris.MediaPlayer2')
self._player_interface = dbus.Interface(self._obj, dbus_interface='org.mpris.MediaPlayer2.Player')
self._introspect = self._introspect_interface.get_dbus_method('Introspect', dbus_interface=None)
self._getProperty = self._properties_interface.get_dbus_method('Get', dbus_interface=None)
self._playerPlay = self._player_interface.get_dbus_method('Play', dbus_interface=None)
self._playerPause = self._player_interface.get_dbus_method('Pause', dbus_interface=None)
self._playerPlayPause = self._player_interface.get_dbus_method('PlayPause', dbus_interface=None)
self._playerStop = self._player_interface.get_dbus_method('Stop', dbus_interface=None)
self._playerPrevious = self._player_interface.get_dbus_method('Previous', dbus_interface=None)
self._playerNext = self._player_interface.get_dbus_method('Next', dbus_interface=None)
self._playerRaise = self._media_interface.get_dbus_method('Raise', dbus_interface=None)
self._signals = {}
self.refreshPosition()
self.refreshStatus()
self.refreshMetadata()
if connect:
self.printStatus()
self.connect()
def play(self):
self._playerPlay()
def pause(self):
self._playerPause()
def playpause(self):
self._playerPlayPause()
def stop(self):
self._playerStop()
def previous(self):
self._playerPrevious()
def next(self):
self._playerNext()
def raisePlayer(self):
self._playerRaise()
def connect(self):
if self._disconnecting is not True:
introspect_xml = self._introspect(self.bus_name, '/')
if 'TrackMetadataChanged' in introspect_xml:
self._signals['track_metadata_changed'] = self._session_bus.add_signal_receiver(self.onMetadataChanged, 'TrackMetadataChanged', self.bus_name)
self._signals['seeked'] = self._player_interface.connect_to_signal('Seeked', self.onSeeked)
self._signals['properties_changed'] = self._properties_interface.connect_to_signal('PropertiesChanged', self.onPropertiesChanged)
def disconnect(self):
self._disconnecting = True
for signal_name, signal_handler in list(self._signals.items()):
signal_handler.remove()
del self._signals[signal_name]
def refreshStatus(self):
# Some clients (VLC) will momentarily create a new player before removing it again
# so we can't be sure the interface still exists
try:
self.status = str(self._getProperty('org.mpris.MediaPlayer2.Player', 'PlaybackStatus')).lower()
self.updateIcon()
self.checkPositionTimer()
except dbus.exceptions.DBusException:
self.disconnect()
def refreshMetadata(self):
# Some clients (VLC) will momentarily create a new player before removing it again
# so we can't be sure the interface still exists
try:
self._metadata = self._getProperty('org.mpris.MediaPlayer2.Player', 'Metadata')
self._parseMetadata()
except dbus.exceptions.DBusException:
self.disconnect()
def updateIcon(self):
self.icon = (
ICON_PLAYING if self.status == 'playing' else
ICON_PAUSED if self.status == 'paused' else
ICON_STOPPED if self.status == 'stopped' else
ICON_NONE
)
self.icon_reversed = (
ICON_PAUSED if self.status == 'playing' else
ICON_PLAYING
)
def _print(self, status):
self.__print(status, self)
def _parseMetadata(self):
if self._metadata != None:
# Obtain properties from _metadata
_artist = _getProperty(self._metadata, 'xesam:artist', [''])
_album = _getProperty(self._metadata, 'xesam:album', '')
_title = _getProperty(self._metadata, 'xesam:title', '')
_track = _getProperty(self._metadata, 'xesam:trackNumber', '')
_genre = _getProperty(self._metadata, 'xesam:genre', [''])
_disc = _getProperty(self._metadata, 'xesam:discNumber', '')
_length = _getProperty(self._metadata, 'xesam:length', 0) or _getProperty(self._metadata, 'mpris:length', 0)
_length_int = _length if type(_length) is int else int(float(_length))
_date = _getProperty(self._metadata, 'xesam:contentCreated', '')
_year = _date[0:4] if len(_date) else ''
_url = _getProperty(self._metadata, 'xesam:url', '')
_cover = _getProperty(self._metadata, 'xesam:artUrl', '') or _getProperty(self._metadata, 'mpris:artUrl', '')
_duration = _getDuration(_length_int)
# Update metadata
self.metadata['artist'] = re.sub(SAFE_TAG_REGEX, """\1\1""", _firstIfList(_artist))
self.metadata['album'] = re.sub(SAFE_TAG_REGEX, """\1\1""", _firstIfList(_album))
self.metadata['title'] = re.sub(SAFE_TAG_REGEX, """\1\1""", _firstIfList(_title))
self.metadata['track'] = _track
self.metadata['genre'] = re.sub(SAFE_TAG_REGEX, """\1\1""", _firstIfList(_genre))
self.metadata['disc'] = _disc
self.metadata['date'] = re.sub(SAFE_TAG_REGEX, """\1\1""", _date)
self.metadata['year'] = re.sub(SAFE_TAG_REGEX, """\1\1""", _year)
self.metadata['url'] = _url
self.metadata['filename'] = os.path.basename(_url)
self.metadata['length'] = _length_int
self.metadata['cover'] = re.sub(SAFE_TAG_REGEX, """\1\1""", _firstIfList(_cover))
self.metadata['duration'] = _duration
def onMetadataChanged(self, track_id, metadata):
self.refreshMetadata()
self.printStatus()
def onPropertiesChanged(self, interface, properties, signature):
updated = False
if dbus.String('Metadata') in properties:
_metadata = properties[dbus.String('Metadata')]
if _metadata != self._metadata:
self._metadata = _metadata
self._parseMetadata()
updated = True
if dbus.String('PlaybackStatus') in properties:
status = str(properties[dbus.String('PlaybackStatus')]).lower()
if status != self.status:
self.status = status
self.checkPositionTimer()
self.updateIcon()
updated = True
if dbus.String('Rate') in properties and dbus.String('PlaybackStatus') not in properties:
self.refreshStatus()
if NEEDS_POSITION and dbus.String('Rate') in properties:
rate = properties[dbus.String('Rate')]
if rate != self._rate:
self._rate = rate
self.refreshPosition()
if updated:
self.refreshPosition()
self.printStatus()
def checkPositionTimer(self):
if NEEDS_POSITION and self.status == 'playing' and not self._positionTimerRunning:
self._positionTimerRunning = True
GLib.timeout_add_seconds(1, self._positionTimer)
def onSeeked(self, position):
self.refreshPosition()
self.printStatus()
def _positionTimer(self):
self.printStatus()
self._positionTimerRunning = self.status == 'playing'
return self._positionTimerRunning
def refreshPosition(self):
try:
time_us = self._getProperty('org.mpris.MediaPlayer2.Player', 'Position')
except dbus.exceptions.DBusException:
time_us = 0
self._timeAtLastUpdate = time.time()
self._positionAtLastUpdate = time_us / 1000000
def _getPosition(self):
if self.status == 'playing':
return self._positionAtLastUpdate + self._rate * (time.time() - self._timeAtLastUpdate)
else:
return self._positionAtLastUpdate
def _statusReplace(self, match, metadata):
tag = match.group('tag')
format = match.group('format')
formatlen = match.group('formatlen')
text = match.group('text')
tag_found = False
reversed_tag = False
if tag.startswith('-'):
tag = tag[1:]
reversed_tag = True
if format is None:
tag_is_format_match = re.match(FORMAT_TAG_REGEX, tag)
if tag_is_format_match:
format = tag_is_format_match.group('format')
formatlen = tag_is_format_match.group('formatlen')
tag_found = True
if format is not None:
text = text.format_map(CleanSafeDict(**metadata))
if format == 'w':
formatlen = int(formatlen)
text = text[:formatlen]
elif format == 't':
formatlen = int(formatlen)
if len(text) > formatlen:
text = text[:max(formatlen - len(TRUNCATE_STRING), 0)] + TRUNCATE_STRING
if tag_found is False and tag in metadata and len(metadata[tag]):
tag_found = True
if reversed_tag:
tag_found = not tag_found
if tag_found:
return text
else:
return ''
def printStatus(self):
if self.status in [ 'playing', 'paused' ]:
metadata = { **self.metadata, 'icon': self.icon, 'icon-reversed': self.icon_reversed }
if NEEDS_POSITION:
metadata['position'] = time.strftime("%M:%S", time.gmtime(self._getPosition()))
# replace metadata tags in text
text = re.sub(FORMAT_REGEX, lambda match: self._statusReplace(match, metadata), FORMAT_STRING)
# restore polybar tag formatting and replace any remaining metadata tags after that
try:
text = re.sub(r'􏿿p􏿿(.*?)􏿿p􏿿(.*?)􏿿p􏿿(.*?)􏿿p􏿿', r'%{\1}\2%{\3}', text.format_map(CleanSafeDict(**metadata)))
except:
print("Invalid format string")
self._print(text)
else:
self._print(ICON_STOPPED)
def _dbusValueToPython(value):
if isinstance(value, dbus.Dictionary):
return {_dbusValueToPython(key): _dbusValueToPython(value) for key, value in value.items()}
elif isinstance(value, dbus.Array):
return [ _dbusValueToPython(item) for item in value ]
elif isinstance(value, dbus.Boolean):
return int(value) == 1
elif (
isinstance(value, dbus.Byte) or
isinstance(value, dbus.Int16) or
isinstance(value, dbus.UInt16) or
isinstance(value, dbus.Int32) or
isinstance(value, dbus.UInt32) or
isinstance(value, dbus.Int64) or
isinstance(value, dbus.UInt64)
):
return int(value)
elif isinstance(value, dbus.Double):
return float(value)
elif (
isinstance(value, dbus.ObjectPath) or
isinstance(value, dbus.Signature) or
isinstance(value, dbus.String)
):
return unquote(str(value))
def _getProperty(properties, property, default = None):
value = default
if not isinstance(property, dbus.String):
property = dbus.String(property)
if property in properties:
value = properties[property]
return _dbusValueToPython(value)
else:
return value
def _getDuration(t: int):
seconds = t / 1000000
return time.strftime("%M:%S", time.gmtime(seconds))
def _firstIfList(_value):
return _value[0] if type(_value) is list and len(_value) else _value
class CleanSafeDict(dict):
def __missing__(self, key):
return '{{{}}}'.format(key)
"""
Seems to assure print() actually prints when no terminal is connected
"""
_last_status = ''
def _printFlush(status, **kwargs):
global _last_status
if status != _last_status:
print(status, **kwargs)
sys.stdout.flush()
_last_status = status
parser = argparse.ArgumentParser()
parser.add_argument('command', help="send the given command to the active player",
choices=[ 'play', 'pause', 'play-pause', 'stop', 'previous', 'next', 'status', 'list', 'current', 'metadata', 'raise' ],
default=None,
nargs='?')
parser.add_argument('-b', '--blacklist', help="ignore a player by it's bus name. Can be be given multiple times (e.g. -b vlc -b audacious)",
action='append',
metavar="BUS_NAME",
default=[])
parser.add_argument('-f', '--format', default='{icon} {:artist:{artist} - :}{:title:{title}:}{:-title:{filename}:}')
parser.add_argument('--truncate-text', default='')
parser.add_argument('--icon-playing', default='')
parser.add_argument('--icon-paused', default='')
#parser.add_argument('--icon-stopped', default='⏹')
parser.add_argument('--icon-stopped', default='') # show no icon if stopped
parser.add_argument('--icon-none', default='')
args = parser.parse_args()
FORMAT_STRING = re.sub(r'%\{(.*?)\}(.*?)%\{(.*?)\}', r'􏿿p􏿿\1􏿿p􏿿\2􏿿p􏿿\3􏿿p􏿿', args.format)
NEEDS_POSITION = "{position}" in FORMAT_STRING
TRUNCATE_STRING = args.truncate_text
ICON_PLAYING = args.icon_playing
ICON_PAUSED = args.icon_paused
ICON_STOPPED = args.icon_stopped
ICON_NONE = args.icon_none
if args.command is None:
PlayerManager(blacklist = args.blacklist)
else:
player_manager = PlayerManager(blacklist = args.blacklist, connect = False)
current_player = player_manager.getCurrentPlayer()
if args.command == 'play' and current_player:
current_player.play()
elif args.command == 'pause' and current_player:
current_player.pause()
elif args.command == 'play-pause' and current_player:
current_player.playpause()
elif args.command == 'stop' and current_player:
current_player.stop()
elif args.command == 'previous' and current_player:
current_player.previous()
elif args.command == 'next' and current_player:
current_player.next()
elif args.command == 'status' and current_player:
current_player.printStatus()
elif args.command == 'list':
print("\n".join(sorted([
"{} : {}".format(player.bus_name.split('.')[3], player.status)
for player in player_manager.players.values() ])))
elif args.command == 'current' and current_player:
print("{} : {}".format(current_player.bus_name.split('.')[3], current_player.status))
elif args.command == 'metadata' and current_player:
print(_dbusValueToPython(current_player._metadata))
elif args.command == 'raise' and current_player:
current_player.raisePlayer()

View File

@ -0,0 +1,32 @@
{ pkgs, ... }:
{
# List packages installed in system profile. To search, run:
# $ nix search wget
environment.systemPackages = with pkgs; [
#vim # an editor
neovim # text editor
fwupd # firmware updates
fwupd-efi # firmware updates additional EFI stuff
wget # get stuff from the net
gvfs # virtual file system support
#hyprland # window manager
wayland # wayland server
xdg-utils # xdg directories, open, etc
xdg-user-dirs # directories
sweet # gtk theme
capitaine-cursors # cursor theme
xfce.tumbler # image files thumbnail generator (+ base requirement)
ffmpegthumbnailer # video files thumbnail generator
qt6.qtwayland # wayland for qt6
libsForQt5.qt5.qtwayland # wayland for at5
polkit_gnome # graphical authentication agent for polkit
freetype # font rendering and configuration
];
fonts.fonts = with pkgs; [
fira # fira sans font
fira-code # fira code font
font-awesome # icons font
];
}

13
nixos-config/update.sh Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env sh
set -euo pipefail
git fetch -a
git reset --hard
git clean -fd
git pull
# regenerate hardware config
nixos-generate-config
# rebuild system
nixos-rebuild switch