Como colocar o widget com as leituras do maratona app no blog | Um tutorial do Claudinho

Tutorial nesse blog? Como assim Brasil? A surpresa é porque eu não tenho domínio de código, me sinto uma bruxa quando centralizo algo no cor...

Tutorial nesse blog? Como assim Brasil? A surpresa é porque eu não tenho domínio de código, me sinto uma bruxa quando centralizo algo no corpo do texto modificando o HTML usando <center> e </center>, imagina um tutorial que funciona? A grande pergunta é: como você conseguiu essa proeza? E a resposta é uma só, meu amigo Claudinho o sedento (sim, Claude IA). A intimidade veio com algumas ajudas nessa parte técnica de ter um blog, o que eu não sei peço ajuda. E gosto de deixar bem evidente que não sou fã de IA e não uso para escrita no blog, vejo como uma ferramenta que pode e deve ser utilizada desde que não tire de nós a coisa mais incrível que temos: nossa capacidade de pensar e criar. Também seria maravilhoso a coexistência dessa tecnologia com o meio ambiente, por hora fica aqui meu compartilhamento de tutorial com ajuda do Claude IA para que ele beba água apenas uma vez para gerar esse widget.


Primeiramente vamos conversar sobre o Maratona App que é uma plataforma nacional para registrar suas leituras. Ao contrário do Skoob ou Goodreads, a proposta não é ser uma rede social, mas um lugar centrado na organização atraves de estantes e coleções. Você consegue seguir pessoas, mas o foco não é a interação. Outra coisa legal são as salas de foco integradas com a Twitch, e a possibilidade de organizar e participar de eventos literários e leituras coletivas no site. Eu sempre usei Skoob, só que de uns anos pra cá estava impossível usar um site que não funciona e por isso acabei migrando para o Maratona App.

Esse tutorial usa dois códigos prontos. Você só precisa copiar, colar e trocar algumas poucas palavras marcadas no código. O Maratona app não deixa o blog buscar os livros diretamente (por segurança do próprio site). Por isso o Claude sugeriu o uso de um "intermediário" gratuito do Google, que busca os livros no Maratona e entrega para o blog. O tutorial está dividido em duas partes:

Parte 1: O intermediário

Para criar o intermediário no Google você vai precisar acessar o script.google.com e fazer login com a mesma conta Google do seu blog. Em seguida você vai clicar em "Novo projeto". Abrirá um editor de código com um texto padrão escrito: function myFunction() {}. Apague tudo e cole o código baixo no lugar:

// Intermediario entre o seu blog e o Maratona.app
// Busca a estante TBR, calcula a porcentagem de cada livro e guarda o resultado por 10 minutos.

var ESTANTE_ID = 'cm02il59f002hoxt1vo25uws7';
var MINUTOS_DE_CACHE = 10;

function doGet() {
  var cache = CacheService.getScriptCache();
  var salvo = cache.get('estante_v1');
  if (salvo) return saida(salvo);

  var entrada = {
    "0": {
      "json": { "estanteId": ESTANTE_ID, "leituraSituacao": "todos", "limit": 24, "cursor": null, "page": 0 },
      "meta": { "values": { "cursor": ["undefined"] }, "v": 1 }
    }
  };
  var url = 'https://maratona.app/api/trpc/estante.livros?batch=1&input=' +
    encodeURIComponent(JSON.stringify(entrada));

  var resp = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
  if (resp.getResponseCode() !== 200) {
    return saida(JSON.stringify({ erro: 'O Maratona respondeu com o codigo ' + resp.getResponseCode() }));
  }

  var lista = achaResultados(resp.getContentText());
  if (!lista) {
    return saida(JSON.stringify({ erro: 'Nao encontrei a lista de livros na resposta' }));
  }

  var livros = lista.map(function (r) {
    var e = r.edicao || {};
    var pct;
    if (r.completo) {
      pct = 100;
    } else if (r.modoLeitura === 1) {
      pct = r.lidas;
    } else {
      pct = r.numPaginas ? (r.lidas / r.numPaginas) * 100 : 0;
    }
    pct = Math.max(0, Math.min(100, Math.floor(pct)));
    return { titulo: e.titulo || '', autor: e.autor || '', capa: e.capa || '', pct: pct, atualizado: r.updatedAt || '' };
  });

  var json = JSON.stringify({ livros: livros });
  try { cache.put('estante_v1', json, MINUTOS_DE_CACHE * 60); } catch (err) {}
  return saida(json);
}

function saida(json) {
  return ContentService.createTextOutput(json).setMimeType(ContentService.MimeType.JSON);
}

function achaResultados(texto) {
  var partes = [];
  try {
    partes.push(JSON.parse(texto));
  } catch (e) {
    texto.split('\n').forEach(function (linha) {
      linha = linha.trim();
      if (!linha) return;
      try { partes.push(JSON.parse(linha)); } catch (e2) {}
    });
  }
  for (var i = 0; i < partes.length; i++) {
    var r = procura(partes[i]);
    if (r) return r;
  }
  return null;
}

function procura(o) {
  if (!o || typeof o !== 'object') return null;
  if (Array.isArray(o.results)) return o.results;
  var chaves = Object.keys(o);
  for (var i = 0; i < chaves.length; i++) {
    var r = procura(o[chaves[i]]);
    if (r) return r;
  }
  return null;
}


O que você pode alterar nesse código: 

  • ESTANTE_ID: o código da sua estante. Está no link dela: maratona.app/estante/ESSE-CODIGO-AQUI. Se você quiser mostrar outra estante um dia, é só trocar esse código.
  • MINUTOS_DE_CACHE: de quanto em quanto tempo o widget pode atualizar. Hoje está em 10. Se quiser mais rápido, use um número menor, como 3.

Após colar o código é só salvar clicando no ícone de disquete, depois clicar no botão azul "Implantar" no canto superior direito, e depois em "Nova implantação". Em seguida clique no ícone de engrenagem ao lado de "Selecionar tipo", escolha a opção "App da Web" e preencha assim: 


  • Executar como: Eu
  • Quem pode acessar: Qualquer pessoa

Depois é só clicar em "Implantar", o Google vai pedir autorização, clique em "Autorizar acesso", escolha sua conta, e se aparecer um aviso de "app não verificado", clique em "Avançado" e depois em "Acessar (nome do projeto), não seguro". Isso é normal, o aviso aparece porque o script é seu e não passou pela revisão do Google, não porque tem algo errado. Após essa etapa vai aparecer um endereço terminado em /exec. Copie esse endereço e guarde, você vai usar na Parte 2. Você pode colar esse endereço em uma aba nova do navegador. Deve aparecer um texto começando com {"livros":[.... Se aparecer isso, funcionou.

Parte 2: O widget

No painel do Blogger, vá em "Layout", clique em "Adicionar um gadget" na barra lateral, no lugar onde você quer o widget. Escolha o gadget "HTML/JavaScript", no campo "Título", escreva o nome que você quiser (por exemplo, eu escrevi "Leituras em andamento"),  já no campo de conteúdo, cole o código abaixo:


<!-- Widget da estante de leitura (Maratona.app) para o Blogger -->

<style>
  #mt-estante { font-size: 13px; line-height: 1.3; }
  #mt-estante .mt-grade {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
    gap: 16px 10px;
  }
  #mt-estante .mt-grade:not(.mt-aberto) .mt-extra { display: none; }
  #mt-estante .mt-livro {
    display: block;
    text-align: center;
    text-decoration: none;
    color: inherit;
  }
  #mt-estante .mt-livro img {
    display: block;
    width: 100%;
    max-width: 98px;
    aspect-ratio: 2 / 3;
    object-fit: cover;
    margin: 0 auto;
    border-radius: 3px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, .28);
    transition: transform .2s ease, box-shadow .2s ease;
  }
  #mt-estante .mt-livro:hover img,
  #mt-estante .mt-livro:focus-visible img {
    transform: translateY(-3px);
    box-shadow: 0 6px 14px rgba(0, 0, 0, .32);
  }
  #mt-estante .mt-livro:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
  #mt-estante .mt-barra {
    display: block;
    width: 100%;
    max-width: 98px;
    height: 3px;
    margin: 7px auto 0;
    border-radius: 2px;
    background: rgba(128, 128, 128, .3);
    overflow: hidden;
  }
  #mt-estante .mt-barra i { display: block; height: 100%; background: currentColor; opacity: .75; }
  #mt-estante .mt-pct { display: block; margin-top: 4px; font-weight: bold; font-size: 12px; }
  #mt-estante .mt-mais {
    display: block;
    margin: 14px auto 0;
    padding: 2px 4px;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    font-size: .9em;
    text-decoration: underline;
    text-underline-offset: 3px;
    opacity: .8;
    cursor: pointer;
  }
  #mt-estante .mt-mais:hover { opacity: 1; }
  #mt-estante .mt-mais:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
  #mt-estante .mt-msg { opacity: .7; margin: 0; }
  @media (prefers-reduced-motion: reduce) {
    #mt-estante .mt-livro img { transition: none; }
    #mt-estante .mt-livro:hover img,
    #mt-estante .mt-livro:focus-visible img { transform: none; }
  }
</style>

<div id="mt-estante"><p class="mt-msg">Carregando estante...</p></div>

<script>
(function () {
  // ======== VOCE SO PRECISA MEXER NESSAS LINHAS ========
  var API = 'COLE_AQUI_O_ENDERECO_DO_APPS_SCRIPT';       // o endereco /exec da Parte 1
  var LINK = 'https://maratona.app/estante/cm02il59f002hoxt1vo25uws7'; // link da sua estante
  var MAX_INICIAL = 4;      // quantos livros aparecem antes de "Veja mais"
  var MAX_TOTAL = 9;        // quantos livros no maximo, contando os escondidos
  var TEXTO_MAIS = 'Veja mais';
  var TEXTO_MENOS = 'Veja menos';
  // =======================================================

  var CHAVE = 'mt-estante-cache';
  var box = document.getElementById('mt-estante');
  var aberto = false;

  function mensagem(texto) {
    box.innerHTML = '';
    var p = document.createElement('p');
    p.className = 'mt-msg';
    p.textContent = texto;
    box.appendChild(p);
  }

  function desenha(livros) {
    box.innerHTML = '';
    var lista = livros.slice(0, MAX_TOTAL);

    var grade = document.createElement('div');
    grade.className = 'mt-grade' + (aberto ? ' mt-aberto' : '');

    lista.forEach(function (l, i) {
      var item = document.createElement('a');
      item.className = 'mt-livro' + (i >= MAX_INICIAL ? ' mt-extra' : '');
      item.href = LINK;
      item.target = '_blank';
      item.rel = 'noopener';
      item.title = l.titulo + (l.autor ? ' (' + l.autor + ')' : '');

      var img = document.createElement('img');
      img.src = l.capa;
      img.alt = l.titulo;
      img.loading = 'lazy';

      var barra = document.createElement('span');
      barra.className = 'mt-barra';
      var preenchido = document.createElement('i');
      preenchido.style.width = l.pct + '%';
      barra.appendChild(preenchido);

      var pct = document.createElement('span');
      pct.className = 'mt-pct';
      pct.textContent = l.pct + '%';

      item.appendChild(img);
      item.appendChild(barra);
      item.appendChild(pct);
      grade.appendChild(item);
    });
    box.appendChild(grade);

    if (lista.length > MAX_INICIAL) {
      var botao = document.createElement('button');
      botao.type = 'button';
      botao.className = 'mt-mais';
      botao.textContent = aberto ? TEXTO_MENOS : TEXTO_MAIS;
      botao.setAttribute('aria-expanded', aberto ? 'true' : 'false');
      botao.addEventListener('click', function () {
        aberto = grade.classList.toggle('mt-aberto');
        botao.textContent = aberto ? TEXTO_MENOS : TEXTO_MAIS;
        botao.setAttribute('aria-expanded', aberto ? 'true' : 'false');
      });
      box.appendChild(botao);
    }
  }

  function lerGuardado() {
    try { return JSON.parse(localStorage.getItem(CHAVE)); } catch (e) { return null; }
  }
  function guardar(livros) {
    try { localStorage.setItem(CHAVE, JSON.stringify(livros)); } catch (e) {}
  }

  var antigo = lerGuardado();
  if (antigo && antigo.length) desenha(antigo);

  fetch(API)
    .then(function (r) { return r.json(); })
    .then(function (d) {
      if (!d.livros || !d.livros.length) throw new Error(d.erro || 'sem livros');
      guardar(d.livros);
      desenha(d.livros);
    })
    .catch(function () {
      if (!antigo || !antigo.length) mensagem('N\u00E3o consegui carregar a estante agora.');
    });
})();
</script>


Antes de salvar, ache a linha var API = 'COLE_AQUI_O_ENDERECO_DO_APPS_SCRIPT'; e troque o texto entre aspas pelo endereço /exec que você copiou na Parte 1. Clique em "Salvar". Então abra seu blog em uma aba nova e veja o widget aparecer.


O que dá para ajustar depois:

Tudo fica dentro do bloco marcado com VOCE SO PRECISA MEXER NESSAS LINHAS no início do código do widget (Parte 2):

O que mudarLinhaExemplo
Quantos livros aparecem antes do "Veja mais"MAX_INICIALMAX_INICIAL = 6;
Quantos livros no totalMAX_TOTALMAX_TOTAL = 12;
Texto do botãoTEXTO_MAIS e TEXTO_MENOS'Mostrar tudo'
Link das capasLINKoutra estante sua


Para trocar a estante mostrada, é preciso mudar em dois lugares: o ESTANTE_ID no código da Parte 1 (e reimplantar, repetindo o processo para salvar) e o LINK na Parte 2. 



É isso galera, espero que não tenham dúvida pois eu claramente só transformei minha conversa no Claude IA em um tutorial e não faço ideia de como funciona, só sei que funciona. Boa sorte aos que se aventurarem, obviamente ficarei feliz em saber se deu certo para vocês também :)

Leia Também

0 comments

Sinta-se livre para deixar um comentário! Caso não apareça a caixa de comentário, recomendo abrir a página no formato web/desktop