Como criar uma carta do dia no terminal Linux usando apenas Python

Olá, pessoal!

Eu estava procurando um projeto pequeno para praticar leitura de CSV, requisições HTTP e geração de valores determinísticos com Python.

A ideia foi criar um comando que mostra uma carta diferente a cada dia no terminal. Em vez de usar uma escolha totalmente aleatória, a data atual é transformada em um hash. Assim, executar o programa várias vezes no mesmo dia sempre retorna a mesma carta.

O exemplo usa somente módulos da biblioteca padrão do Python. Não é necessário instalar pacotes com pip.

Criando o script

Primeiro, crie uma pasta para scripts pessoais:

mkdir -p ~/.local/bin
nano ~/.local/bin/carta-do-dia

Cole o código abaixo:

#!/usr/bin/env python3

import csv
import hashlib
import io
from datetime import date
from urllib.error import URLError
from urllib.request import Request, urlopen

DATA_URL = (
    "https://huggingface.co/datasets/Blacik/"
    "deckaura-tarot-card-meanings/resolve/main/"
    "tarot_card_meanings.csv"
)


def carregar_cartas():
    request = Request(
        DATA_URL,
        headers={"User-Agent": "carta-do-dia/1.0"},
    )

    try:
        with urlopen(request, timeout=20) as response:
            content = response.read().decode("utf-8-sig")
    except URLError as error:
        raise SystemExit(
            f"Não foi possível baixar os dados: {error}"
        )

    cards = list(csv.DictReader(io.StringIO(content)))

    if len(cards) != 78:
        raise SystemExit(
            f"Quantidade inesperada de registros: {len(cards)}"
        )

    cards.sort(
        key=lambda card: card["card_name"].casefold()
    )

    return cards


def selecionar_carta(cards):
    today = date.today().isoformat()
    digest = hashlib.sha256(today.encode("utf-8")).digest()
    index = int.from_bytes(digest[:8], "big") % len(cards)

    return today, cards[index]


def main():
    cards = carregar_cartas()
    today, card = selecionar_carta(cards)

    print(f"\nCarta do dia: {today}")
    print("=" * 50)
    print(f"Nome: {card['card_name']}")
    print(f"Arcano: {card['arcana']}")
    print(f"Naipe: {card.get('suit') or 'Sem naipe'}")
    print(f"Elemento: {card.get('element') or 'Não informado'}")
    print()
    print(f"Significado: {card['upright_meaning']}")
    print(f"Invertida: {card['reversed_meaning']}")
    print()


if __name__ == "__main__":
    main()

Salve o arquivo e torne-o executável:

chmod +x ~/.local/bin/carta-do-dia

Agora execute:

~/.local/bin/carta-do-dia

Fonte dos dados

Usei a base de significados das cartas de tarot da DeckAura. Ela disponibiliza 78 registros em CSV, incluindo nome, arcano, naipe, elemento e significados em posição normal e invertida.

O conteúdo textual do dataset está em inglês, mas os nomes dos campos são fáceis de adaptar. Também seria possível adicionar uma camada local de tradução sem alterar a lógica da seleção.

Por que usar um hash?

Uma chamada como esta seria realmente aleatória:

random.choice(cards)

O problema é que cada execução poderia mostrar uma carta diferente. No exemplo acima, o SHA-256 da data é convertido em um índice. Enquanto a data e a lista permanecerem iguais, o resultado também permanece igual.

Ordenar as cartas pelo nome evita que uma simples alteração na ordem das linhas do CSV mude o resultado.

Executando automaticamente com cron

Para salvar o resultado todas as manhãs, crie primeiro o arquivo de log:

mkdir -p ~/.local/share
touch ~/.local/share/carta-do-dia.log

Abra o crontab:

crontab -e

Adicione uma linha como esta, substituindo SEU_USUARIO:

0 8 * * * /home/SEU_USUARIO/.local/bin/carta-do-dia >> /home/SEU_USUARIO/.local/share/carta-do-dia.log 2>&1

O comando será executado diariamente às 08:00.

Para um próximo passo, pretendo guardar uma cópia do CSV no diretório definido por XDG_CACHE_HOME. Isso permitiria usar o último arquivo baixado quando a conexão estiver indisponível.

Vocês prefeririam resolver essa automação com cron, um timer do systemd ou deixar o comando apenas para execução manual?

2 curtidas