Skip to content

labdev2025-cmd/clipboard_history

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

ClipboardHistory

Monitor de área de transferência (clipboard) multiplataforma em Java que registra automaticamente tudo o que é copiado. Escreve em texto (prepend no .txt, estilo diário) e em JSON Lines (.jsonl, append — ideal para integrações). Conta com configuração externa (via argumentos de linha de comando e/ou system properties), log estruturado com rotação e normalização opcional do conteúdo.

✅ Sem dependências externas. ✅ Empacotado em um único JAR executável (via maven-shade-plugin). ✅ Padrões de projeto aplicados (Strategy + Chain of Responsibility) para extração de conteúdo.


Sumário


Recursos

  • 🧠 Captura inteligente do conteúdo do clipboard:

    • Texto simples (stringFlavor).
    • HTML como string/reader (text/html).
    • Lista de arquivos (exibe paths).
    • Imagens (gera placeholder com dimensões quando possível).
    • Fallback para qualquer text/* via Reader.
  • 🧾 Registro em dois formatos:

    • TXT: estilo diário, com prepend (a entrada mais recente fica no topo).
    • JSONL: append (uma linha JSON por entrada), ideal para ETL, indexação e consultas.
  • ⚙️ Configuração externa:

    • Args (--history=..., --jsonl=..., --poll=..., etc.)
    • System properties (-Dclipboard.history.path=..., etc.)
  • 🧹 Normalização opcional do conteúdo: quebra de linha, trim trailing por linha e colapso de linhas em branco.

  • 📜 Log estruturado com rotação por tamanho e contagem de arquivos (via java.util.logging).

  • 🧩 Padrões de design: Strategy + Chain of Responsibility para extratores.

  • 🧵 Agendamento com ScheduledExecutorService (sem while(true)), shutdown hook para desligamento limpo.


Arquitetura e decisões de design

  • Classe principal: ClipboardHistory (definida como Main-Class no shade).

  • Agendador: ScheduledExecutorService executa varreduras a cada intervaloMs (default: 250ms).

  • Assinatura: hash (hex) de tipos (flavors) + conteúdo, evitando duplicações.

  • Escrita:

    • TXT: prepend via arquivo temporário + Files.move(...) (tenta ATOMIC_MOVE e faz fallback).
    • JSONL: cada evento é uma linha JSON (append).
  • Normalização (opcional, habilitada por padrão):

    • Converte quebras para \n.
    • Remove espaços à direita por linha.
    • Colapsa blocos de linhas em branco (\n\n\n\n\n).
  • Logs: console + arquivo com rotação (tamanho e count configuráveis).


Pré-requisitos

  • JDK 25 (conforme maven.compiler.source/target: 25).

  • Maven 3.8+ (recomendado 3.9+).

  • Ambiente com clipboard do AWT disponível:

    • Windows / macOS: normalmente presente.
    • Linux: requer ambiente gráfico (X11/Wayland). Em servidores, considere Xvfb.
    • Evite modo headless (java.awt.headless=true) — o AWT Clipboard não funciona em headless.

Build (Maven)

O projeto já inclui o maven-shade-plugin para gerar um JAR executável único.

# Clonar o repositório e entrar na pasta (exemplo)
git clone <URL_DO_SEU_REPO>.git
cd clipboard_history

# Build
mvn -q -DskipTests package

Artefato gerado em target/. O nome geralmente será clipboard_history-1.0.jar (ou clipboard_history-1.0-shaded.jar, conforme a versão do plugin/empacotamento). Confira com:

ls -lh target/

Execução

Argumentos de linha de comando

Chave Descrição Exemplo
--history Caminho do TXT (prepend) --history=/caminho/clipboard-history.txt
--jsonl Caminho do JSONL (append) --jsonl=/caminho/clipboard-history.jsonl
--poll Intervalo de varredura em ms (default: 250) --poll=500
--tz Timezone (ex.: America/Fortaleza) --tz=America/Fortaleza
--log Caminho do arquivo de log --log=/caminho/clipboard-history.log
--log-level Nível de log (FINE, INFO, WARNING, SEVERE) --log-level=FINE
--log-rotate-size Tamanho máx. (bytes) antes de rotacionar --log-rotate-size=2097152
--log-rotate-count Quantidade de arquivos de rotação --log-rotate-count=3
--normalize Ativa/desativa normalização (true/false) --normalize=false
--normalize-trim-trailing Remove espaços à direita por linha --normalize-trim-trailing=false
--normalize-collapse-blank Colapsa linhas em branco --normalize-collapse-blank=false

System properties (-D)

Equivalentes às flags acima (precedência menor que args):

Propriedade Exemplo
-Dclipboard.history.path -Dclipboard.history.path=/caminho/clipboard-history.txt
-Dclipboard.jsonl.path -Dclipboard.jsonl.path=/caminho/clipboard-history.jsonl
-Dclipboard.poll.ms -Dclipboard.poll.ms=250
-Dclipboard.tz -Dclipboard.tz=America/Fortaleza
-Dclipboard.log.path -Dclipboard.log.path=/caminho/clipboard-history.log
-Dclipboard.log.level -Dclipboard.log.level=INFO
-Dclipboard.log.rotate.size -Dclipboard.log.rotate.size=2097152
-Dclipboard.log.rotate.count -Dclipboard.log.rotate.count=3
-Dclipboard.normalize -Dclipboard.normalize=true
-Dclipboard.normalize.trim_trailing -Dclipboard.normalize.trim_trailing=true
-Dclipboard.normalize.collapse_blank -Dclipboard.normalize.collapse_blank=true

Precedência de configuração

  1. Args (--chave=valor)
  2. System properties (-Dchave=valor)
  3. Defaults (os mesmos do código original)

Exemplos de uso

Linux/macOS:

java -jar target/clipboard_history-1.0.jar \
  --history=$HOME/desenvolvimento/temporarios/clipboard-history.txt \
  --jsonl=$HOME/desenvolvimento/temporarios/clipboard-history.jsonl \
  --poll=250 \
  --tz=America/Fortaleza \
  --log=$HOME/desenvolvimento/temporarios/clipboard-history.log \
  --log-level=INFO \
  --log-rotate-size=2097152 \
  --log-rotate-count=3 \
  --normalize=true \
  --normalize-trim-trailing=true \
  --normalize-collapse-blank=true

Windows (PowerShell):

java -jar target\clipboard_history-1.0.jar `
  --history="C:\Users\Daniel\desenvolvimento\temporarios\clipboard-history.txt" `
  --jsonl="C:\Users\Daniel\desenvolvimento\temporarios\clipboard-history.jsonl" `
  --poll=250 `
  --tz=America/Fortaleza `
  --log="C:\Users\Daniel\desenvolvimento\temporarios\clipboard-history.log" `
  --log-level=INFO `
  --log-rotate-size=2097152 `
  --log-rotate-count=3 `
  --normalize=true `
  --normalize-trim-trailing=true `
  --normalize-collapse-blank=true

Via System Properties (-D):

java \
  -Dclipboard.history.path=$HOME/desenvolvimento/temporarios/clipboard-history.txt \
  -Dclipboard.jsonl.path=$HOME/desenvolvimento/temporarios/clipboard-history.jsonl \
  -Dclipboard.poll.ms=250 \
  -Dclipboard.tz=America/Fortaleza \
  -Dclipboard.log.path=$HOME/desenvolvimento/temporarios/clipboard-history.log \
  -Dclipboard.log.level=INFO \
  -Dclipboard.log.rotate.size=2097152 \
  -Dclipboard.log.rotate.count=3 \
  -Dclipboard.normalize=true \
  -Dclipboard.normalize.trim_trailing=true \
  -Dclipboard.normalize.collapse_blank=true \
  -jar target/clipboard_history-1.0.jar

Saídas geradas

Arquivo TXT (prepend)

Formato humano e fácil de consultar:

[21-10-2025 11:22:33]
--------------------------------------------------------------------------------
Texto copiado (normalizado)...
pode ter múltiplas linhas
--------------------------------------------------------------------------------

  • Sempre escreve no topo (entrada mais recente primeiro).
  • timestamp usa o timezone configurado (--tz / -Dclipboard.tz).

Arquivo JSONL (append)

Cada linha é um JSON autocontido:

{"ts_iso":"2025-10-21T11:22:33-03:00","timestamp_formatado":"21-10-2025 11:22:33","assinatura":"a4f9b12","flavors":["text/plain; charset=unicode","text/html; class=java.lang.String"],"conteudo":"Texto copiado (normalizado)...\nlinha 2"}

Campos:

  • ts_iso: timestamp ISO-8601 com offset.
  • timestamp_formatado: no padrão configurado (default dd-MM-yyyy HH:mm:ss).
  • assinatura: hash (hex) de tipos + conteúdo (usado para evitar duplicação).
  • flavors: lista de MIME types disponíveis no snapshot.
  • conteudo: texto/placeholder (após normalização, se habilitada).

Dica: consulte com jq, envie para Logstash/Fluent Bit, grep, etc.


Logs e rotação

  • Saída: console + arquivo (configurável).
  • Formato: uma linha por evento — timestamp ISO | nível | logger | mensagem.
  • Rotação: por tamanho (--log-rotate-size) e contagem (--log-rotate-count).

Exemplo de mensagem:

2025-10-21T11:22:33-03:00 [INFO] ClipboardHistory - Entrada textual registrada em: /home/.../clipboard-history.txt

Normalização de conteúdo

Ativada por padrão. Pode ser controlada por:

  • --normalize=true|false
  • --normalize-trim-trailing=true|false
  • --normalize-collapse-blank=true|false

Aplicações:

  1. \r\n e \r\n
  2. Remoção de espaços à direita por linha
  3. Colapso de blocos de linhas em branco (≥3) para 2 linhas em branco

Exemplo:

Entrada original:

"foo  \r\n\r\n\r\nbar  \r\n"

Após normalização:

"foo\n\nbar\n"

Execução como serviço (systemd)

Crie /etc/systemd/system/clipboard-history.service:

[Unit]
Description=Clipboard History (Java)
After=network.target

[Service]
User=SEU_USUARIO
WorkingDirectory=/caminho/do/projeto
ExecStart=/usr/bin/java -jar /caminho/do/projeto/target/clipboard_history-1.0.jar --tz=America/Fortaleza --poll=250
Restart=on-failure
Environment="JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8"

[Install]
WantedBy=multi-user.target

Depois:

sudo systemctl daemon-reload
sudo systemctl enable clipboard-history
sudo systemctl start clipboard-history
sudo systemctl status clipboard-history

Nota: o serviço precisa ter acesso a um servidor gráfico (clipboard do AWT). Em ambientes servidores, avalie Xvfb/XWayland. Em headless puro, o AWT Clipboard não funcionará.


Solucionando problemas (Troubleshooting)

  • java.awt.HeadlessException O AWT precisa de ambiente gráfico. Execute com um display válido (X11/Wayland) ou utilize Xvfb.

  • IllegalStateException / “clipboard ocupado” Outro processo está usando o clipboard. O app ignora e tenta novamente automaticamente (próximo tick).

  • Nada é gravado

    • Verifique permissões de escrita nos caminhos de TXT/JSONL/LOG.
    • Confirme se o timezone está correto.
    • Aumente a verbosidade: --log-level=FINE.
  • Wayland Em alguns ambientes Wayland, a implementação do clipboard pode variar. Usar XWayland pode melhorar a compatibilidade.


Extensibilidade (novos extratores)

A extração de conteúdo usa Strategy + Chain of Responsibility. Para suportar novos formatos (ex.: RTF, custom MIME):

  1. Crie uma classe que implemente a interface EstrategiaExtracao com:

    • boolean suporta(Transferable t)
    • Optional<String> extrair(Transferable t)
  2. Adicione a nova estratégia à lista (extratores) na inicialização, respeitando a ordem de prioridade.


Boas práticas e considerações de privacidade

  • Dados sensíveis: o clipboard pode conter senhas, tokens, dados pessoais.

    • Armazene os arquivos (TXT/JSONL/LOG) em local seguro.
    • Avalie criptografia em disco (LUKS/BitLocker/FileVault) ou partição protegida.
    • Se necessário, implemente exclusões/mascaramento por regex antes de gravar.
  • Tamanho do histórico: JSONL cresce continuamente; considere logrotate do sistema para TXT/JSONL também, se desejado.

  • Intervalo de poll: --poll. Valores menores → mais responsivo; maiores → menor uso de CPU.


Licença

Defina a licença conforme sua necessidade (por exemplo, MIT). Se optar por MIT, adicione um arquivo LICENSE com o texto correspondente.


Manifest / empacotamento

O pom.xml já define o shade plugin com:

<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
  <mainClass>ClipboardHistory</mainClass>
</transformer>

Ou seja, o JAR final é executável com java -jar e usa ClipboardHistory como entrypoint.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages