dotfiles

Repositório dotfiles
git clone git://git.sivaldodavi.com/dotfiles.git
Log | Files | Refs | README

commit d0b08e8adc353e0ac07cf2b20bdb36bb37d32713
parent 02361b2dbaa755c0da360f3788c35a38e5a908ad
Author: Sivaldo <gxixtx@xsxixvxaxlxdxoxdxaxvxix.xcxoxm>
Date:   Sun,  9 Aug 2026 15:26:28 -0300

refactor(culto): usa hinário local em JSON em vez de baixar do Codeberg

Diffstat:
M.local/bin/culto | 256++++++++++++++++++++++++++++++++++++++++++-------------------------------------
1 file changed, 137 insertions(+), 119 deletions(-)

diff --git a/.local/bin/culto b/.local/bin/culto @@ -4,17 +4,14 @@ # Configuração # ============================================================================== -MUSICAS_URL="https://codeberg.org/sivaldodavi/ipp/archive/main.tar.gz" -PIX_URL="https://codeberg.org/sivaldodavi/ipp/raw/branch/main/pix-igreja.png" - -CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/culto" +CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}" BIBLE_FILE="$CACHE_DIR/biblia" -BIBLE_URL="https://codeberg.org/sivaldodavi/ipp/raw/branch/main/biblia" -MUSICAS_DIR="$CACHE_DIR/musicas" -PIX_FILE="$CACHE_DIR/pix.png" +MUSICAS_FILE="$CACHE_DIR/musicas.json" +PIX_FILE="$CACHE_DIR/pix-igreja.png" +AGENDA_FILE="$CACHE_DIR/agenda.jpeg" SENT_FILE="/tmp/sent_presentation" -: "${EDITOR:=vi}" +: "${EDITOR:=vim}" LITURGIA_FIXA=( "T: oração inicial" @@ -38,38 +35,28 @@ Domingo (18:00) - Culto solene" # Utilitários # ============================================================================== -# Verifica/Instala o xrandr if ! command -v xrandr >/dev/null 2>&1; then echo "'xrandr' não encontrado. Instalando..." >&2 doas apk add xrandr || { echo "ERRO: Falha ao instalar xrandr." >&2; exit 1; } fi -_download() { - local url="$1" dest="$2" - if command -v curl >/dev/null 2>&1; then - curl -fsSL "$url" -o "$dest" - elif command -v wget >/dev/null 2>&1; then - wget -q "$url" -O "$dest" - else - echo "Erro: curl ou wget necessário." >&2 - return 1 - fi -} - # ============================================================================== -# Bíblia +# Bíblia Local # ============================================================================== _ensure_bible() { - [ -f "$BIBLE_FILE" ] && return 0 - mkdir -p "$(dirname "$BIBLE_FILE")" - echo "Baixando bíblia..." >&2 - _download "$BIBLE_URL" "$BIBLE_FILE" + if [ ! -f "$BIBLE_FILE" ]; then + echo "ERRO: Arquivo de bíblia não encontrado em: $BIBLE_FILE" >&2 + return 1 + fi } _bible_python() { BIBLE_FILE="$BIBLE_FILE" python3 - "$@" <<'PYEOF' -import os, re, sys +import os, re, sys, signal + +# Ignora erro de Broken Pipe quando pipeamos pro fzf ou less +signal.signal(signal.SIGPIPE, signal.SIG_DFL) BIBLE_FILE = os.environ["BIBLE_FILE"] SLIDE_WIDTH = 180 @@ -151,7 +138,6 @@ def slides_read(rows, ref_label, no_cover, resp): return "\n".join(out) def terminal_read(rows, ref_label): - USE_COLOR = sys.stdout.isatty() print(azul(ref_label)) print() for r in rows: @@ -202,7 +188,7 @@ PYEOF } # ============================================================================== -# Integração com o 'sent' +# Integração ao 'sent' # ============================================================================== format_sent() { @@ -227,92 +213,138 @@ clear_sent() { # Músicas # ============================================================================== -ensure_musicas() { - if [ ! -d "$MUSICAS_DIR" ] || [ -z "$(ls -A "$MUSICAS_DIR"/*.md 2>/dev/null)" ]; then - echo "Baixando hinário..." >&2 - local tmp_tar="$CACHE_DIR/musicas.tar.gz" - mkdir -p "$CACHE_DIR" - _download "$MUSICAS_URL" "$tmp_tar" || return 1 - rm -rf "$MUSICAS_DIR" - mkdir -p "$MUSICAS_DIR" - tar -xzf "$tmp_tar" -C "$MUSICAS_DIR" --strip-components=1 2>/dev/null \ - || tar -xzf "$tmp_tar" -C "$MUSICAS_DIR" - find "$MUSICAS_DIR" -mindepth 2 -name "*.md" -exec mv {} "$MUSICAS_DIR/" \; 2>/dev/null - rm -f "$tmp_tar" +_ensure_musicas() { + if [ ! -f "$MUSICAS_FILE" ]; then + echo "{}" > "$MUSICAS_FILE" # Cria vazio se não existir fi } -_song_title() { - basename "$1" .md | sed -E 's/^[0-9]+[a-z]?\s*-\s*//; s/\s*\(.*\)\s*$//' -} - -_show_md_song() { - local filepath="$1" - local title - title=$(_song_title "$filepath") - - { - printf '%s\n\n\n' "$title" +_render_json_song() { + local title="$1" + MUSICAS_FILE="$MUSICAS_FILE" python3 - "$title" <<'PYEOF' +import sys, json, os, signal - python3 - "$filepath" <<'PYEOF' -import sys, re +signal.signal(signal.SIGPIPE, signal.SIG_DFL) -with open(sys.argv[1], encoding='utf-8') as f: - content = f.read() +musicas_file = os.environ["MUSICAS_FILE"] +target_title = sys.argv[1] -content = re.sub(r'^#.*\n?', '', content, flags=re.MULTILINE) +with open(musicas_file, encoding='utf-8') as f: + songs = json.load(f) -for block in re.split(r'\n{2,}', content.strip()): - block = block.strip() - if block: - print(block) +if target_title in songs: + print(target_title) + print("\n\n") + for stanza in songs[target_title]: + print(stanza) print("\n") +else: + print(f"Erro: Música '{target_title}' não encontrada.", file=sys.stderr) + sys.exit(1) PYEOF - } | format_sent } pick_song() { - ensure_musicas || return 1 + _ensure_musicas || return 1 local chosen - chosen=$(ls "$MUSICAS_DIR"/*.md 2>/dev/null \ - | xargs -I{} basename {} .md \ - | sed -E 's/^[0-9]+[a-z]?\s*-\s*//; s/\s*\(.*\)\s*$//' \ - | sort \ + # Adicionado o signal import e handler aqui também no one-liner + chosen=$(python3 -c "import json, signal; signal.signal(signal.SIGPIPE, signal.SIG_DFL); data=json.load(open('$MUSICAS_FILE')); print('\n'.join(sorted(data.keys())))" \ | fzf --reverse --prompt="Música: ") [ -z "$chosen" ] && return 0 - local match - match=$(ls "$MUSICAS_DIR"/*.md 2>/dev/null \ - | while IFS= read -r f; do - t=$(_song_title "$f") - [ "$t" = "$chosen" ] && printf '%s\n' "$f" && break - done) + _render_json_song "$chosen" | format_sent +} - if [ -n "$match" ]; then - _show_md_song "$match" - else - echo "Música não encontrada: $chosen" >&2 - fi +# ============================================================================== +# Adicionar / Editar Músicas (JSON <-> MD temporário) +# ============================================================================== + +_update_json_from_md() { + local action="$1" + local title="$2" + local tmp_md="$3" + + MUSICAS_FILE="$MUSICAS_FILE" python3 - "$action" "$title" "$tmp_md" <<'PYEOF' +import json, sys, os, re + +musicas_file = os.environ["MUSICAS_FILE"] +action = sys.argv[1] +title = sys.argv[2] +tmp_md = sys.argv[3] + +if os.path.exists(musicas_file): + with open(musicas_file, 'r', encoding='utf-8') as f: + try: + songs = json.load(f) + except json.JSONDecodeError: + songs = {} +else: + songs = {} + +if action == "extract": + text = "\n\n".join(songs.get(title, [])) + with open(tmp_md, 'w', encoding='utf-8') as f: + f.write(f"# {title}\n\n{text}\n") + +elif action == "save": + with open(tmp_md, 'r', encoding='utf-8') as f: + content = f.read() + + # Remove o título em markdown (ex: # Nome da música) + content = re.sub(r'^#.*\n?', '', content, flags=re.MULTILINE) + + # Separa os blocos (estrofes) por linhas em branco + stanzas = [b.strip() for b in re.split(r'\n{2,}', content) if b.strip()] + + if stanzas: + songs[title] = stanzas + with open(musicas_file, 'w', encoding='utf-8') as f: + json.dump(songs, f, ensure_ascii=False, indent=2) + print(f"✅ Música salva com sucesso no JSON!") + else: + print("⚠️ Nenhuma estrofe encontrada. Alteração descartada.") +PYEOF } -song_by_name() { - ensure_musicas || return 1 - local query="${1,,}" +add_song() { + _ensure_musicas + echo -n "Digite o título da nova música: " + read -r title + [ -z "$title" ] && return 1 + + local tmp_md="/tmp/culto_musica_$$.md" + echo -e "# $title\n\nEstrofe 1...\n\nEstrofe 2..." > "$tmp_md" + + # Abre no Vim forçando o modo markdown + ${EDITOR} -c "set filetype=markdown" "$tmp_md" + + # Salva o resultado no json + _update_json_from_md "save" "$title" "$tmp_md" + rm -f "$tmp_md" +} - local match - match=$(ls "$MUSICAS_DIR"/*.md 2>/dev/null \ - | while IFS= read -r f; do - t=$(_song_title "$f" | tr '[:upper:]' '[:lower:]') - [[ "$t" == *"$query"* ]] && printf '%s\n' "$f" && break - done) +edit_song() { + _ensure_musicas || return 1 - if [ -n "$match" ]; then - _show_md_song "$match" - else - echo "Música não encontrada: $1" >&2 - fi + local chosen + chosen=$(python3 -c "import json, signal; signal.signal(signal.SIGPIPE, signal.SIG_DFL); data=json.load(open('$MUSICAS_FILE')); print('\n'.join(sorted(data.keys())))" \ + | fzf --reverse --prompt="Editar Música: ") + + [ -z "$chosen" ] && return 0 + + local tmp_md="/tmp/culto_musica_$$.md" + + # Extrai o array do JSON e converte em texto pra editar + _update_json_from_md "extract" "$chosen" "$tmp_md" + + # Abre no Vim forçando o modo markdown + ${EDITOR} -c "set filetype=markdown" "$tmp_md" + + # Pega o arquivo editado e devolve pro JSON + _update_json_from_md "save" "$chosen" "$tmp_md" + rm -f "$tmp_md" } # ============================================================================== @@ -328,13 +360,12 @@ get_bible() { [ "$no_cover" = "true" ] && flags="$flags --no-cover" [ "$resp" = "true" ] && flags="$flags --resp" - # shellcheck disable=SC2086 _ensure_bible || exit 1 _bible_python read $flags "$query" | format_sent } # ============================================================================== -# Liturgia fixa (menu fzf) +# Liturgia # ============================================================================== show_menu() { @@ -358,13 +389,15 @@ show_menu() { } # ============================================================================== -# Lógica principal +# Lógica Principal # ============================================================================== case "${1:-}" in m|menu) show_menu ;; + cm) pick_song ;; - song) song_by_name "$2" ;; + as|add-song) add_song ;; + es|edit-song) edit_song ;; b|bible) get_bible "$2" "false" "false" ;; bd|bible-clean) get_bible "$2" "true" "false" ;; @@ -392,48 +425,33 @@ case "${1:-}" in p|pix) if [ ! -f "$PIX_FILE" ]; then - echo "Baixando imagem PIX..." >&2 - mkdir -p "$CACHE_DIR" - _download "$PIX_URL" "$PIX_FILE" || exit 1 + echo "Erro: Arquivo PIX não encontrado em $PIX_FILE" >&2 + exit 1 fi nohup nsxiv "$PIX_FILE" >/dev/null 2>&1 & ;; - bible-reset) - rm -f "$BIBLE_FILE" - _ensure_bible && echo "Bíblia atualizada." - ;; - musicas-reset) - rm -rf "$MUSICAS_DIR" - ensure_musicas && echo "Hinário atualizado." - ;; - pix-reset) - rm -f "$PIX_FILE" - mkdir -p "$CACHE_DIR" - _download "$PIX_URL" "$PIX_FILE" && echo "Imagem PIX atualizada." - ;; - *) cat <<'USAGE' culto <comando> [arg] m / menu Liturgia (fzf) - cm Músicas (fzf) - song <nome> Música por nome parcial + + cm Selecionar música (fzf) + as / add-song Adicionar nova música (via Vim) + es / edit-song Editar música existente (via Vim) + b / bible <ref> Bíblia (com capa) bd <ref> Bíblia (sem capa) r / resp <ref> Responsivo (DIRIGENTE / IGREJA) v / ver <ref> Bíblia no terminal s / search <pal> Buscar na bíblia + t / text <texto> Texto livre ag / agenda Agenda da semana i / index Índice dos slides atuais x / clear Limpar tela do sent p / pix Abrir QR code PIX - - bible-reset Rebaixar bíblia - musicas-reset Rebaixar hinário - pix-reset Rebaixar imagem PIX USAGE ;; esac