major zsh cleanup

This commit is contained in:
sebastian committed 2026-09-17 13:20:08 +02:00
1 parent c9ab492c60
commit a9ef0503c7
4 files changed
+335 -210

No files matched your search

+10
View File
@@ -107,3 +107,13 @@ set -ga update-environment TERM_PROGRAM
run '~/.config/tmux/plugins/tpm/tpm' run '~/.config/tmux/plugins/tpm/tpm'
# Pane-Titel anzeigen
set -g pane-border-status top
set -g pane-border-format ' #{pane_index}: #{pane_title} '
set -g window-status-format \
' 🪟 #I:#W '
set -g window-status-current-format \
'#[bold] 🟢 #I:#W #[default]'
+85
View File
@@ -0,0 +1,85 @@
# --- Bandcamp ----------------------------------------------------------------
# bandcampdl <url>: download an album/track as MP3 (best quality) with
# metadata and cover art, sorted into Artist/Year - Album/
bandcampdl() {
if [[ -z "$1" ]]; then
echo "Usage: bandcampdl <bandcamp-url>"
return 1
fi
yt-dlp \
-x \
--audio-format mp3 \
--audio-quality 0 \
--embed-metadata \
--embed-thumbnail \
--convert-thumbnails jpg \
-o "%(album_artist)s/%(release_year)s - %(album)s/%(album_artist)s - %(album)s - %(track_number)02d - %(title)s.%(ext)s" \
"$1"
}
# bandcampbatch <file>: run bandcampdl for every URL in a file
# (empty lines and lines starting with # are skipped)
bandcampbatch() {
local file="$1" url
if [[ ! -r "$file" ]]; then
echo "Usage: bandcampbatch <url-file>"
return 1
fi
while IFS= read -r url; do
[[ -z "$url" || "$url" == \#* ]] && continue
bandcampdl "$url"
done < "$file"
}
# bandcamplist <https://band.bandcamp.com/music> [output.txt]:
# write all album/track URLs of an artist to a file
# (default: bandcamp-<band>.txt) - input for bandcampbatch
bandcamplist() {
local url outfile tmpfile band count
if (( ! $+commands[yt-dlp] )); then
echo "Fehler: yt-dlp wurde nicht gefunden."
return 1
fi
if (( $# < 1 || $# > 2 )); then
echo "Usage:"
echo " bandcamplist <https://band.bandcamp.com/music> [output.txt]"
return 1
fi
url="$1"
# zsh stores capture groups of =~ in $match
if [[ ! "$url" =~ ^https?://([^.]+)\.bandcamp\.com/music/?$ ]]; then
echo "Fehler: Keine gueltige Bandcamp-/music-URL:"
echo " $url"
return 1
fi
band="${match[1]}"
outfile="${2:-bandcamp-${band}.txt}"
tmpfile=$(mktemp)
if ! yt-dlp --flat-playlist --print webpage_url "$url" | sort -u > "$tmpfile"; then
rm -f "$tmpfile"
echo "Fehler beim Abrufen der Links."
return 1
fi
count=$(wc -l < "$tmpfile")
if (( count == 0 )); then
rm -f "$tmpfile"
echo "Keine Album- oder Track-Links gefunden."
return 1
fi
mv "$tmpfile" "$outfile"
echo "✓ $count Links nach '$outfile' geschrieben."
}
+118
View File
@@ -0,0 +1,118 @@
if [[ -n "$TMUX" ]]; then
autoload -Uz add-zsh-hook
# -------------------------------------------------------------------------
# Basisname des Windows aus aktuellem Verzeichnis
# -------------------------------------------------------------------------
_tmux_set_base_window_name() {
local name
if [[ "$PWD" == "$HOME" ]]; then
name="sebastian"
else
name="${PWD:t}"
fi
# Basisnamen separat merken
tmux set-option \
-w \
-t "$TMUX_PANE" \
@base_window_name "$name" \
2>/dev/null
_tmux_update_window_name
}
# -------------------------------------------------------------------------
# Window-Name aus Basisname + allen SSH-Sessions dieses Windows bauen
#
# Beispiel:
# projects 🔐 P1→labgw P4→prod
# -------------------------------------------------------------------------
_tmux_update_window_name() {
local base ssh_info line
base="$(
tmux show-options \
-w \
-v \
-t "$TMUX_PANE" \
@base_window_name \
2>/dev/null
)"
[[ -z "$base" ]] && base="${PWD:t}"
ssh_info=""
while IFS= read -r line; do
[[ -z "$line" ]] && continue
if [[ -n "$ssh_info" ]]; then
ssh_info+=" "
fi
ssh_info+="$line"
done < <(
tmux list-panes \
-t "$TMUX_PANE" \
-F '#{?@ssh_host,P#{pane_index}→#{@ssh_host},}' \
2>/dev/null
)
if [[ -n "$ssh_info" ]]; then
tmux rename-window \
-t "$TMUX_PANE" \
"${base} 🔐 ${ssh_info}" \
2>/dev/null
else
tmux rename-window \
-t "$TMUX_PANE" \
"$base" \
2>/dev/null
fi
}
add-zsh-hook chpwd _tmux_set_base_window_name
_tmux_set_base_window_name
# -------------------------------------------------------------------------
# SSH wrapper
# -------------------------------------------------------------------------
ssh() {
local host rc
# Bewusst SSH-Alias nehmen:
# ssh labgw
# zeigt "labgw", nicht die dahinterliegende IP.
host="$(
command ssh -G "$@" 2>/dev/null |
awk '$1 == "host" { print $2; exit }'
)"
if [[ -n "$host" ]]; then
tmux set-option \
-p \
-t "$TMUX_PANE" \
@ssh_host "$host" \
2>/dev/null
_tmux_update_window_name
fi
command ssh "$@"
rc=$?
# SSH-Markierung dieses Panes entfernen
tmux set-option \
-p \
-u \
-t "$TMUX_PANE" \
@ssh_host \
2>/dev/null
_tmux_update_window_name
return $rc
}
fi
+122 -210
View File
@@ -1,46 +1,55 @@
# ============================================================================= # =============================================================================
# ~/.zshrc # ~/.zshrc
# ============================================================================= # =============================================================================
# Reihenfolge ist hier Absicht: # Interactive shell configuration. Environment and PATH live in ~/.zshenv.
# 1. Profiling-Schalter
# 2. tmux-exec (ganz oben, damit die aeussere Shell sich die Init spart)
# 3. billige Optionen / Keybindings / History
# 4. teure Sachen: compinit + gecachte eval-Ausgaben
# 5. Aliases, Funktionen, PATH
# #
# Cache leeren nach Theme-/Tool-Update: zshrc-refresh # Order matters:
# Startzeit messen: ZSHRC_PROFILE=1 zsh -i -c exit # 1. Profiling switch
# 2. tmux autostart (exec early, so the outer shell skips all init work)
# 3. Cheap stuff: options, keybindings, history
# 4. Expensive stuff: completion system, cached init output, prompt
# 5. Aliases
# 6. Functions
# 7. tmux integration (~/.zsh/tmux.zsh)
# 8. Finish: self-compile, profiling report
#
# Clear caches after a theme/tool update: zshrc-refresh
# Measure startup time: ZSHRC_PROFILE=1 zsh -i -c exit
# ============================================================================= # =============================================================================
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# 1. Profiling (optional, per Env-Variable) # 1. Profiling (opt-in via environment variable)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
if [[ -n "$ZSHRC_PROFILE" ]]; then [[ -n "$ZSHRC_PROFILE" ]] && zmodload zsh/zprof
zmodload zsh/zprof
fi
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# 2. tmux-Autostart # 2. tmux autostart
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Muss vor allem anderen stehen: die aeussere Shell wird durch tmux ersetzt und # Must come first: the outer shell gets replaced by tmux, so there's no point
# muss deshalb gar nicht erst komplett initialisiert werden. Frueher lief das # initializing it. The shell inside tmux runs this file again with $TMUX set.
# zshrc pro Terminalstart zweimal komplett durch (einmal aussen, einmal im
# tmux-Fenster) - das faellt damit weg.
# #
# Terminalerkennung laeuft ueber Environment-Variablen statt ueber ps/proc, # Terminals are detected via environment variables instead of ps//proc, which
# das spart ~6 Forks pro Shellstart. # saves a handful of forks per shell start.
#
# Note: none of these variables survive an SSH login, so SSH sessions don't
# autostart tmux. Use ZSH_FORCE_TMUX=1 or uncomment the SSH line below.
#
# Overrides:
# ZSH_FORCE_TMUX=1 always start tmux
# ZSH_NO_TMUX=1 never start tmux
if [[ -o interactive && -z "$TMUX" && -z "$ZSHRC_PROFILE" && $UID -ne 0 && -t 1 ]]; then if [[ -o interactive && -z "$TMUX" && -z "$ZSHRC_PROFILE" && $UID -ne 0 && -t 1 ]]; then
# IDEs und eingebettete Terminals explizit ausnehmen # Leave IDEs and embedded terminals alone
if [[ -z "$TERMINAL_EMULATOR" && -z "$INSIDE_EMACS" \ if [[ -z "$TERMINAL_EMULATOR" && -z "$INSIDE_EMACS" \
&& -z "$VSCODE_INJECTION" && -z "$NVIM" ]]; then && -z "$VSCODE_INJECTION" && -z "$NVIM" ]]; then
_zsh_want_tmux=0 _zsh_want_tmux=0
[[ "$TERM_PROGRAM" == ghostty || -n "$GHOSTTY_RESOURCES_DIR" ]] && _zsh_want_tmux=1 [[ "$TERM_PROGRAM" == ghostty || -n "$GHOSTTY_RESOURCES_DIR" ]] && _zsh_want_tmux=1 # Ghostty
[[ -n "$KITTY_WINDOW_ID" ]] && _zsh_want_tmux=1 [[ -n "$KITTY_WINDOW_ID" ]] && _zsh_want_tmux=1 # Kitty
[[ -n "$VTE_VERSION" ]] && _zsh_want_tmux=1 # xfce4-terminal, gnome-terminal [[ -n "$VTE_VERSION" ]] && _zsh_want_tmux=1 # GNOME Terminal, xfce4-terminal, Tilix
[[ -n "$ZSH_FORCE_TMUX" ]] && _zsh_want_tmux=1 # manueller Override # [[ -n "$SSH_CONNECTION" ]] && _zsh_want_tmux=1 # SSH logins
[[ -n "$ZSH_FORCE_TMUX" ]] && _zsh_want_tmux=1
[[ -n "$ZSH_NO_TMUX" ]] && _zsh_want_tmux=0 [[ -n "$ZSH_NO_TMUX" ]] && _zsh_want_tmux=0
if (( _zsh_want_tmux )) && (( $+commands[tmux] )); then if (( _zsh_want_tmux )) && (( $+commands[tmux] )); then
@@ -53,63 +62,58 @@ fi
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# 3. Grundoptionen, Keybindings, History # 3. Options, keybindings, history
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
bindkey -e # Emacs-Keybindings, auch wenn EDITOR=vi bindkey -e # Emacs keybindings, even if EDITOR=vi
setopt interactivecomments # "#" auf der Kommandozeile = Kommentar setopt interactive_comments # allow "# comments" on the command line
HISTFILE=~/.zsh_history HISTFILE=~/.zsh_history
HISTSIZE=50000 # Eintraege im RAM HISTSIZE=50000 # entries kept in memory
SAVEHIST=50000 # Eintraege in der Datei SAVEHIST=50000 # entries written to $HISTFILE
# (vorher stand SAVEHIST auf 1000 - HISTFILESIZE
# ist eine Bash-Variable und hat nichts getan)
setopt hist_ignore_all_dups # aeltere Duplikate rauswerfen setopt hist_ignore_all_dups # drop older duplicates
setopt hist_ignore_space # Zeilen mit fuehrendem Leerzeichen nicht merken setopt hist_ignore_space # don't record lines starting with a space
setopt hist_reduce_blanks setopt hist_reduce_blanks # squeeze superfluous whitespace
setopt hist_verify # Expansion erst anzeigen, dann ausfuehren setopt hist_verify # show history expansion before running it
setopt extended_history # mit Zeitstempel (Ersatz fuer HISTTIMEFORMAT) setopt extended_history # store timestamps
setopt share_history # History zwischen laufenden Shells teilen setopt share_history # share history between running shells
# Falls die Shell sich beim Start traege anfuehlt, obwohl sonst alles schnell # If prompts ever feel sluggish: share_history re-reads the history file on
# ist: share_history liest bei jedem Prompt die History-Datei neu ein. Dann # every prompt. Alternative that only appends:
# stattdessen mal testen:
# unsetopt share_history # unsetopt share_history
# setopt inc_append_history # setopt inc_append_history
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# 4a. Cache-Verzeichnis # 4a. Cache directory and prompt theme
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
ZSH_CACHE_DIR=${XDG_CACHE_HOME:-$HOME/.cache}/zsh ZSH_CACHE_DIR=${XDG_CACHE_HOME:-$HOME/.cache}/zsh
[[ -d $ZSH_CACHE_DIR ]] || mkdir -p $ZSH_CACHE_DIR [[ -d $ZSH_CACHE_DIR ]] || mkdir -p $ZSH_CACHE_DIR
# Pfad zum oh-my-posh-Theme
OMP_CONFIG=$HOME/.zsh/rudolfs-dark.omp.json OMP_CONFIG=$HOME/.zsh/rudolfs-dark.omp.json
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# 4b. Completion-System # 4b. Completion system
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Nacktes "compinit" laeuft bei jedem Start compaudit und statet alle # A bare "compinit" runs compaudit and stats every $fpath directory on each
# $fpath-Verzeichnisse ab - hunderte stat()-Calls. Bei warmem Page-Cache egal, # start - hundreds of stat() calls, noticeable with a cold page cache.
# bei kaltem Cache (also genau nach Idle) der teuerste Einzelposten. # So: full check once a day, otherwise load straight from the dump.
# Deshalb: voller Audit nur einmal pro Tag, sonst direkt aus dem Dump.
() { () {
emulate -L zsh emulate -L zsh
setopt local_options extended_glob setopt extended_glob
local zdump=$ZSH_CACHE_DIR/zcompdump local zdump=$ZSH_CACHE_DIR/zcompdump
autoload -Uz compinit autoload -Uz compinit
if [[ -n $zdump(#qNmh-24) ]]; then if [[ -n $zdump(#qNmh-24) ]]; then
compinit -C -d $zdump # Dump juenger als 24h -> Check ueberspringen compinit -C -d $zdump # dump younger than 24h -> skip the audit
else else
compinit -d $zdump # einmal taeglich voll durchlaufen compinit -d $zdump # full run, once a day
touch $zdump touch $zdump
fi fi
# Dump kompilieren: laedt deutlich schneller, gerade von kalter Platte # Compiled dump loads noticeably faster
if [[ ! -s ${zdump}.zwc || $zdump -nt ${zdump}.zwc ]]; then if [[ ! -s ${zdump}.zwc || $zdump -nt ${zdump}.zwc ]]; then
zcompile $zdump 2>/dev/null zcompile $zdump 2>/dev/null
fi fi
@@ -126,41 +130,38 @@ zstyle ':completion:*' select-prompt %SScrolling active: current selection at %p
zstyle ':completion:*' use-compctl false zstyle ':completion:*' use-compctl false
zstyle ':completion:*' verbose true zstyle ':completion:*' verbose true
# Completion-Ergebnisse cachen (z.B. apt-Paketlisten) # Cache expensive completion results (e.g. apt package lists)
zstyle ':completion:*' use-cache on zstyle ':completion:*' use-cache on
zstyle ':completion:*' cache-path $ZSH_CACHE_DIR/compcache zstyle ':completion:*' cache-path $ZSH_CACHE_DIR/compcache
# list-colors: die Zeile "zstyle ':completion:*' list-colors ''" im alten zshrc # kill: colored process list
# hat die LS_COLORS-Zuweisung direkt darueber wieder plattgemacht - deshalb hier
# nur noch einmal, weiter unten nach dircolors.
zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#)*=0=01;31' zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#)*=0=01;31'
zstyle ':completion:*:kill:*' command 'ps -u $USER -o pid,%cpu,tty,cputime,cmd' zstyle ':completion:*:kill:*' command 'ps -u $USER -o pid,%cpu,tty,cputime,cmd'
# SSH-Hosts: mit "zstyle -e" wird das erst beim Tab-Druck ausgewertet, # ssh: hosts from ~/.ssh/config (+ config.d). "zstyle -e" evaluates this lazily
# nicht mehr bei jedem Shellstart. # on <Tab>, not on every shell start. Wildcard patterns are filtered out.
zstyle -e ':completion:*:*:ssh:*' hosts \ zstyle -e ':completion:*:*:ssh:*' hosts \
'reply=(${(f)"$(grep -h "^Host " ~/.ssh/config ~/.ssh/config.d/*(N) 2>/dev/null | sed "s/^Host //" | tr " " "\n" | grep -v "[*?]")"})' 'reply=(${(f)"$(grep -h "^Host " ~/.ssh/config ~/.ssh/config.d/*(N) 2>/dev/null | sed "s/^Host //" | tr " " "\n" | grep -v "[*?]")"})'
# (list-colors for files is set further down, once LS_COLORS exists)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# 4c. Gecachte Init-Ausgaben (television, dircolors) # 4c. Cached init output (television, dircolors)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Beide Tools geben bei jedem Start denselben statischen Shell-Code aus. Statt # Both tools print the same static shell code on every run. Instead of forking
# sie jedes Mal zu starten, wird die Ausgabe einmal in eine Datei geschrieben, # them each time, their output is written to one file, compiled, and sourced.
# kompiliert und danach nur noch gesourct. # The cache is rebuilt when ~/.dircolors or the tv binary is newer than it.
# #
# WICHTIG: die Bloecke brauchen eine Trennzeile. Manche Tools beenden ihre # Each block is followed by an explicit newline: some tools end their output
# Ausgabe ohne Newline, dann klebt die erste Zeile des naechsten Blocks hinten # without one, which would glue the next block onto the last line.
# an der letzten Zeile des vorigen - und man bekommt kaputte Pfade wie
# ".../init.26.0.5.abc..zsh#compdef".
() { () {
emulate -L zsh emulate -L zsh
local cache=$ZSH_CACHE_DIR/init.zsh local cache=$ZSH_CACHE_DIR/init.zsh
local stale=0 local stale=0
[[ -s $cache ]] || stale=1 [[ -s $cache ]] || stale=1
[[ -f ~/.dircolors && ~/.dircolors -nt $cache ]] && stale=1 [[ -f ~/.dircolors && ~/.dircolors -nt $cache ]] && stale=1
[[ -n $commands[tv] && $commands[tv] -nt $cache ]] && stale=1 [[ -n $commands[tv] && $commands[tv] -nt $cache ]] && stale=1
if (( stale )); then if (( stale )); then
@@ -185,46 +186,26 @@ zstyle -e ':completion:*:*:ssh:*' hosts \
[[ -s $cache ]] && source $cache [[ -s $cache ]] && source $cache
} }
# oh-my-posh cacht seinen Init-Code seit v26 selbst unter ~/.cache/oh-my-posh/ # LS_COLORS is set now -> colorize file completion
# (Dateiname enthaelt Version + Config-Hash). "oh-my-posh init zsh" gibt nur zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}
# noch einen kleinen Stub aus, der diese Datei sourct. Ein eigener Cache
# darueber bringt deshalb nichts und bricht, sobald sich Version oder Theme
# aendert - der Stub zeigt dann auf einen Pfad, den es nicht mehr gibt. # -----------------------------------------------------------------------------
# 4d. Prompt (oh-my-posh)
# -----------------------------------------------------------------------------
# Since v26, oh-my-posh caches its init code itself under ~/.cache/oh-my-posh/
# (file name contains version + config hash); "init zsh" only prints a small
# stub that sources it. Caching that stub again would break on every update.
#
# If the prompt is suddenly plain ("host%"), oh-my-posh isn't in PATH -
# check ~/.zshenv.
if (( $+commands[oh-my-posh] )); then if (( $+commands[oh-my-posh] )); then
eval "$(oh-my-posh init zsh --config "$OMP_CONFIG")" eval "$(oh-my-posh init zsh --config "$OMP_CONFIG")"
fi fi
# Jetzt steht LS_COLORS -> Completion einfaerben
zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}
# Cache verwerfen und Shell neu starten
zshrc-refresh() {
rm -f $ZSH_CACHE_DIR/init.zsh{,.zwc} \
$ZSH_CACHE_DIR/zcompdump{,.zwc} \
~/.zshrc.zwc
# oh-my-posh raeumt seinen eigenen Cache normalerweise selbst auf.
# Falls das Prompt nach einem Update zickt, zusaetzlich:
# rm -rf ~/.cache/oh-my-posh
echo "Cache geleert, starte Shell neu ..."
exec zsh
}
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# 5. PATH # 5. Aliases
# -----------------------------------------------------------------------------
typeset -U path PATH # automatisch dedupliziert
path=(
$HOME/.local/bin # pip3 --user
$path
$HOME/go/bin
$HOME/.cargo/bin
)
path=($^path(N-/)) # nur existierende Verzeichnisse behalten
# -----------------------------------------------------------------------------
# 6. Aliases
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
alias ls='ls --color=auto' alias ls='ls --color=auto'
alias grep='grep --color=auto' alias grep='grep --color=auto'
@@ -236,113 +217,23 @@ alias egrep='egrep --color=auto'
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# 7. tmux-Fenstername = aktuelles Verzeichnis # 6. Functions
# -----------------------------------------------------------------------------
# Vorher via PROMPT_COMMAND - das ist eine Bash-Variable und hat in zsh nie
# funktioniert. Jetzt korrekt als chpwd-Hook: laeuft nur beim Verzeichnis-
# wechsel, nicht bei jedem Prompt.
if [[ -n "$TMUX" ]]; then
autoload -Uz add-zsh-hook
_tmux_rename_window() { tmux rename-window "${PWD:t}" 2>/dev/null }
add-zsh-hook chpwd _tmux_rename_window
_tmux_rename_window
fi
# -----------------------------------------------------------------------------
# 8. Funktionen
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# yazi mit cwd-Uebernahme # zshrc-refresh: clear all zsh caches and restart the shell
function y() { zshrc-refresh() {
local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" cwd rm -f $ZSH_CACHE_DIR/init.zsh{,.zwc} \
yazi "$@" --cwd-file="$tmp" $ZSH_CACHE_DIR/zcompdump{,.zwc} \
IFS= read -r -d '' cwd < "$tmp" ~/.zshrc.zwc
[ -n "$cwd" ] && [ "$cwd" != "$PWD" ] && builtin cd -- "$cwd" # oh-my-posh normally cleans up its own cache. If the prompt misbehaves
rm -f -- "$tmp" # after an update, additionally run:
# rm -rf ~/.cache/oh-my-posh
echo "Cache removed, restart shell"
exec zsh
} }
# --- Bandcamp ----------------------------------------------------------------- # tm [name]: create or switch to a tmux session (default: main)
tm() {
function bandcampdl() {
yt-dlp \
-x \
--audio-format mp3 \
--audio-quality 0 \
--embed-metadata \
--embed-thumbnail \
--convert-thumbnails jpg \
-o "%(album_artist)s/%(release_year)s - %(album)s/%(album_artist)s - %(album)s - %(track_number)02d - %(title)s.%(ext)s" \
"$1"
}
function bandcampbatch() {
local file="$1"
while IFS= read -r url; do
[[ -z "$url" || "$url" == \#* ]] && continue
bandcampdl "$url"
done < "$file"
}
function bandcamplist() {
local url outfile tmpfile band count
command -v yt-dlp >/dev/null 2>&1 || {
echo "Fehler: yt-dlp wurde nicht gefunden."
return 1
}
if (( $# < 1 || $# > 2 )); then
echo "Usage:"
echo " bandcamplist <https://band.bandcamp.com/music> [output.txt]"
return 1
fi
url="$1"
if [[ ! "$url" =~ ^https?://([^.]+)\.bandcamp\.com/music/?$ ]]; then
echo "Fehler: Keine gueltige Bandcamp-/music-URL:"
echo " $url"
return 1
fi
band="${match[1]}"
if [[ $# -eq 2 ]]; then
outfile="$2"
else
outfile="bandcamp-${band}.txt"
fi
tmpfile=$(mktemp)
if ! yt-dlp \
--flat-playlist \
--print webpage_url \
"$url" \
| sort -u > "$tmpfile"
then
rm -f "$tmpfile"
echo "Fehler beim Abrufen der Links."
return 1
fi
count=$(wc -l < "$tmpfile")
if (( count == 0 )); then
rm -f "$tmpfile"
echo "Keine Album- oder Track-Links gefunden."
return 1
fi
mv "$tmpfile" "$outfile"
echo "✓ $count Links nach '$outfile' geschrieben."
}
# tm [name] -> Session anlegen oder hinwechseln (Default: main)
function tm() {
local s=${1:-main} local s=${1:-main}
if [[ -n "$TMUX" ]]; then if [[ -n "$TMUX" ]]; then
tmux has-session -t "=$s" 2>/dev/null || tmux new-session -d -s "$s" tmux has-session -t "=$s" 2>/dev/null || tmux new-session -d -s "$s"
@@ -352,16 +243,37 @@ function tm() {
fi fi
} }
# y: run yazi and cd into the directory it was closed in
y() {
local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" cwd
yazi "$@" --cwd-file="$tmp"
IFS= read -r -d '' cwd < "$tmp"
[[ -n "$cwd" && "$cwd" != "$PWD" ]] && builtin cd -- "$cwd"
rm -f -- "$tmp"
}
# Bandcamp Aliases
[[ -f ~/.zsh/bandcamp.zsh ]] && source ~/.zsh/bandcamp.zsh
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# 9. Abschluss # 7. tmux integration
# -----------------------------------------------------------------------------
# Window names from the current directory plus active SSH hosts per pane.
# Only does something inside tmux.
[[ -f ~/.zsh/tmux.zsh ]] && source ~/.zsh/tmux.zsh
# -----------------------------------------------------------------------------
# 8. Finish
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# zshrc selbst kompilieren - zsh benutzt die .zwc-Datei automatisch, solange sie # Compile this file. zsh picks up ~/.zshrc.zwc automatically as long as it is
# neuer ist als das Original. Nach jeder Aenderung wird sie hier neu gebaut. # newer than ~/.zshrc, and it gets rebuilt here after every change.
if [[ ! -s ~/.zshrc.zwc || ~/.zshrc -nt ~/.zshrc.zwc ]]; then if [[ ! -s ~/.zshrc.zwc || ~/.zshrc -nt ~/.zshrc.zwc ]]; then
zcompile ~/.zshrc 2>/dev/null zcompile ~/.zshrc 2>/dev/null
fi fi
if [[ -n "$ZSHRC_PROFILE" ]]; then [[ -n "$ZSHRC_PROFILE" ]] && zprof
zprof
fi