#!/bin/zsh # AOS 3D Tools · Conector do Fatiador (macOS) # Recebe links aos3d://?root=&rel=&... # Ações: # open -> abre o arquivo no fatiador escolhido (app=anycubic|bambu|orca|creality|padrao) # trash -> manda para a Lixeira, sempre depois de confirmar numa janela do próprio Mac # ping -> teste: abre a página de confirmação do site (endereço fixo) # Regras de segurança: só arquivos 3D (.3mf .stl .obj .step .stp), só dentro da pasta do # usuário, sem acesso à internet, nada é enviado para lugar nenhum. Registro local em # ~/Library/Logs/AOS3DTools-Conector.log setopt null_glob url="$1" LOG="$HOME/Library/Logs/AOS3DTools-Conector.log" DADOS="$HOME/Library/Application Support/AOS3DTools"; mkdir -p "$DADOS"; PASTAS="$DADOS/pastas.txt"; touch "$PASTAS" log() { print -r -- "$(date '+%F %T') $*" >> "$LOG"; } aviso() { osascript -e "display notification \"${1//\"/'}\" with title \"Conector do Fatiador\"" >/dev/null 2>&1; } urldecode() { local s="${1//+/ }"; printf '%b' "${s//\%/\\x}"; } resto="${url#*://}"; acao="${resto%%[/?]*}" typeset -A p; rels=() q="${url#*\?}"; [[ "$q" == "$url" ]] && q="" for par in ${(s:&:)q}; do k="${par%%=*}"; v="$(urldecode "${par#*=}")" if [[ "$k" == rel ]]; then rels+=("$v"); else p[$k]="$v"; fi done root="${p[root]}"; name="${p[name]}" log "acao=$acao root=$root arquivos=${#rels} name=$name dl=${p[dl]} app=${p[app]}" so3d() { [[ "${1:l}" == *.(3mf|stl|obj|step|stp) ]]; } dentro_de_casa() { local r="${1:A}"; [[ "$r" == "$HOME"/* ]]; } [[ "$name" == */* || "$root" == */* || "$root" == *..* ]] && { log "recusado: nome invalido"; exit 1; } # Descobre o caminho completo da pasta escolhida no site (o navegador não informa) acha_raiz() { local rel="$1" linha c f alvo="/$root/$1" linha="$(grep -F -- "${root}"$'\t' "$PASTAS" | tail -1)"; c="${linha#*$'\t'}" [[ -n "$linha" && -e "$c/$rel" ]] && { print -r -- "$c"; return; } for c in "$HOME/$root" "$HOME/Downloads/$root" "$HOME/Desktop/$root" "$HOME/Documents/$root" "$HOME/Downloads"; do [[ "${c:t}" == "$root" && -e "$c/$rel" ]] && { print -r -- "$c"; return; } done while IFS= read -r f; do [[ "$f" == "$HOME"/*"$alvo" ]] && { print -r -- "${f%$alvo}/$root"; return; } done < <(mdfind -onlyin "$HOME" -name "${rel:t}" 2>/dev/null) } lembra() { grep -v -F -- "${root}"$'\t' "$PASTAS" > "$PASTAS.tmp"; print -r -- "${root}"$'\t'"$1" >> "$PASTAS.tmp"; mv "$PASTAS.tmp" "$PASTAS"; } caminho() { # devolve o caminho completo do arquivo pedido local rel="$1" raiz [[ "$rel" == *..* ]] && return 1 if [[ -n "${p[dl]}" ]]; then print -r -- "$HOME/Downloads/$name"; return; fi raiz="$(acha_raiz "$rel")"; [[ -z "$raiz" ]] && return 1 lembra "$raiz" if [[ -n "$name" ]]; then print -r -- "$raiz/${rel:h}/$name" | sed 's#/\./#/#'; else print -r -- "$raiz/$rel"; fi } espera() { local i; for i in {1..60}; do [[ -e "$1" ]] && return 0; sleep 0.5; done; return 1; } case "$acao" in ping) # teste pedido pelo site: responde abrindo a página de confirmação (endereço fixo) open "https://aos3dtools.pages.dev/conector/ok/" && log "teste ok" ;; open) alvo="$(caminho "${rels[1]}")" || { aviso "Não achei o arquivo ${rels[1]:t} no computador."; exit 1; } so3d "$alvo" && dentro_de_casa "$alvo" || { log "recusado: $alvo"; exit 1; } espera "$alvo" || { aviso "O arquivo ${alvo:t} não apareceu a tempo."; exit 1; } case "${p[app]}" in anycubic) bid=com.anycubic.anycubicslicer ;; bambu) bid=com.bambulab.bambu-studio ;; orca) bid=com.softfever3d.orca-slicer ;; creality) bid=com.creality.crealityprint ;; *) bid="" ;; esac if [[ -n "$bid" ]] && open -b "$bid" "$alvo" 2>/dev/null; then log "aberto com $bid" elif open "$alvo"; then log "aberto com o programa padrão"; [[ -n "$bid" ]] && aviso "Não achei o fatiador escolhido. Abri com o programa padrão." else aviso "Não consegui abrir ${alvo:t}."; fi ;; trash) alvos=() for r in "${rels[@]}"; do a="$(caminho "$r")" || continue so3d "$a" && dentro_de_casa "$a" && [[ -e "$a" ]] && alvos+=("$a") done (( ${#alvos} )) || { aviso "Nenhum arquivo para mandar para a Lixeira."; exit 1; } lista="$(printf '%s\n' "${alvos[@]:t}" | head -8)"; (( ${#alvos} > 8 )) && lista+=$'\n'"e mais $(( ${#alvos} - 8 ))" resp="$(osascript -e "button returned of (display dialog \"Mandar ${#alvos} arquivo(s) para a Lixeira?\n\n${lista//\"/'}\" buttons {\"Cancelar\", \"Mandar para a Lixeira\"} default button 2 cancel button 1 with title \"Conector do Fatiador\")" 2>/dev/null)" [[ "$resp" == "Mandar para a Lixeira" ]] || { log "lixeira cancelada"; exit 0; } for a in "${alvos[@]}"; do osascript -e "tell application \"Finder\" to delete (POSIX file \"${a//\"/\\\"}\" as alias)" >/dev/null 2>&1 && log "lixeira: $a" || aviso "Não consegui mandar ${a:t} para a Lixeira." done ;; *) log "ação desconhecida: $acao" ;; esac