尚未收集儲存庫資訊。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗Nova versão do Anime Tracker (antes em Streamlit), no visual "Neo-Tokyo + Cinema + Gacha". Lê a planilha do Google, mostra a coleção como cartas, estatísticas e acompanha a temporada atual semana a semana (com gravação de volta na planilha).
Stack: Next.js 16 (App Router, Turbopack), React 19, TypeScript, PapaParse. Gráficos feitos à mão em HTML/SVG (sem biblioteca de gráficos). Fontes: Chakra Petch (títulos) e JetBrains Mono.
Regra do projeto: toda alteração no código deve vir acompanhada da atualização deste README (funcionalidades, fontes de dados, variáveis, estrutura). Ver
CLAUDE.md.
npm install
npm run dev # http://localhost:3000
npm run build # roda os testes e, se passarem, o build de produção
npm run start # serve o build
npm test # testes das regras (tests/*.test.ts)
npm run typecheck # checagem de tipos (gera os tipos das rotas antes)
npm test roda os testes com o test runner do Node (via tsx, sem servidor nem planilha):
tests/temporada.test.ts — regra da estreia (- → X na segunda da semana), ✓ automático ao
marcar o último episódio lançado (e que nunca vira X sozinho, caso Bleach), leitura da aba
Temporada Atual (gviz), escolha do resultado do AniList, nome do site pelo link.tests/planilha.test.ts — leitura das abas Animes Completos e Historico (formatos de data,
colunas, ligação pelo nome, linhas sem par e sugestão de nome), raridade.tests/protecao.test.ts — origem permitida e limite de senhas erradas da rota que grava.tests/filtros.test.ts — filtros, ordenação, endereço de cada aba e filtros no endereço.tests/franquias.test.ts — agrupamento (temporada faltando, OVA, spin-off separado, coluna
Franquia juntando com o grupo automático), resumo e filtro/endereço.tests/retro.test.ts — retrospectiva/comparação de anos, filtro de status da Temporada no
endereço e formato da hora de atualização.tests/appsScript.test.ts — roda o apps-script/Temporada.gs de verdade numa planilha falsa, com
data e fuso controlados: gatilho diário (estreias, virada semanal de V, fuso da planilha),
links/imagens das células e senha do doPost.Ao mudar uma regra, atualize o teste correspondente. Os testes rodam sozinhos em dois lugares:
build é npm test && next build. Se um teste falhar, o
build falha, a Vercel não publica e a versão anterior continua no ar..github/workflows/testes.yml): checagem de tipos e testes; o resultado
aparece como ✓/✗ no commit.No Windows, se o PowerShell bloquear o npm.ps1, use npm.cmd run dev.
Repositório: github.com/tiagogarcea/anime-view (branch main). A Vercel publica sozinha a cada push.
A pasta Anime-View/ é o próprio repositório: para publicar, npm test, npm run build, commit e
push (ou rode Git_Push.bat, que faz git add ., commit com data/hora e push). A antiga
Anime-View-Git/ não é mais usada.
/, /stats, /stats/retrospectiva, /temporada) é gerada no
build e servida pronta pela Vercel; a cada 60 s, na visita seguinte, é renovada em segundo plano
(revalidate em app/(site)/layout.tsx). Ninguém espera a planilha, o script ou o AniList.lib/dados.ts) e, se uma leitura falhar, continua
valendo a anterior. Se a renovação da página inteira falhar, a Vercel mantém no ar a última que
funcionou. A hora no rodapé diz de quando são os dados.components/Pagina.tsx): Temporada (~7 s com cache vazio) e franquias
(~12 s) não seguram a renovação: se passarem do prazo, a página sai sem elas e a busca termina em
segundo plano (after). As franquias, se faltarem, o navegador busca em GET /api/franquias.AbortSignal.timeout: planilha 15 s, script de leitura (links e logos) 30 s — ele leva 5 a 18 s, por isso é lido à parte da lista (lerExtras, cache de 120 s): se falhar, o cache mantém a versão anterior e a lista da Temporada nunca fica vazia por causa dele,
AniList 10 s): nada fica pendurado.components/Seguro.tsx,
que mostra "Não consegui mostrar ... TENTAR DE NOVO" só no lugar dele. Erro geral: app/error.tsx
(tela com "tentar de novo") e app/global-error.tsx.useDeferredValue em
components/App.tsx: o campo atualiza na hora e a lista refiltra logo depois); os cards fora da tela
não são desenhados (content-visibility em .card); a animação dourada dos cards SSR só roda no hover
(antes ficava repintando todos os SSR o tempo todo).next.config.mjs): Content-Security-Policy (só o próprio site
executa script e faz requisição; imagens aceitam qualquer https porque as capas vêm de vários sites),
X-Frame-Options: DENY e frame-ancestors 'none' (o site não abre dentro de iframe),
X-Content-Type-Options, Referrer-Policy, Permissions-Policy, HSTS. O X-Powered-By foi removido.
'unsafe-inline' no script é exigido pelo Next e pelo app/layout.tsx (sem nonce).POST /api/temporada, regras em lib/protecao.ts): recusa pedidos de outro
site (Origin diferente do host → 403), corpo grande (413) e bloqueia o IP depois de 5 senhas erradas
em 10 minutos (429). O contador fica na memória de cada instância da Vercel, então é uma barreira contra
tentativa em massa, não um limite exato. A senha em si é conferida só pelo Apps Script.| Variável | Padrão / uso |
|---|---|
SHEET_CSV_URL | CSV da aba principal "Animes Completos" (lib/sheet.ts) |
HISTORY_CSV_URL | CSV da aba "Historico" (lib/history.ts) |
TEMPORADA_SCRIPT_URL | URL /exec do App da Web do Apps Script (lib/temporada.ts) |
Sem elas, o código usa as URLs fixas da planilha 1a6Ylv7yKu8yb1DJkYpZynTSedbOzTUC_ti35fufDyWI.
Tudo vem de uma única planilha do Google, lida no servidor (components/Pagina.tsx → lib/dados.ts).
Se o Google falhar (fora do ar, resposta vazia), o site não mostra erro: continua com a última versão que funcionou e tenta de novo na visita seguinte. Cada aba é guardada com a hora em que foi lida, mostrada no rodapé ("planilha atualizada às 19:43:28 03/10/2026", horário de Brasília) e, na aba Temporada, abaixo da lista. Só aparece "Erro ao carregar a planilha" se a planilha nunca tiver sido lida com sucesso naquele servidor (cache vazio, ex.: logo após o primeiro deploy).
| Aba | Como é lida | Cache | Se falhar |
|---|---|---|---|
Animes Completos (gid=1713940120) | CSV público (lib/sheet.ts) | 60 s | Última versão boa; sem nenhuma, "Erro ao carregar a planilha" |
Historico (gid=1281634781) | CSV público (lib/history.ts) | 60 s | Última versão boa; sem nenhuma, só o "Last seen" |
| Temporada Atual | JSON do gviz (lib/temporada.ts) | 60 s, tag temporada | Última versão boa; sem nenhuma, "SEM DADOS" |
| Capas da Temporada Atual | Coluna Url Imagem (gviz); reserva: GET no Apps Script | 60 s | Mostra a inicial do nome |
| Streaming e link da Temporada | GET no Apps Script (colunas Onde assistir? e Link), cache próprio (lerExtras) | 120 s | Botão "assistir" não aparece |
| Episódios (total / lançados) | GraphQL do AniList | 1 h | Mostra "?" |
| Franquias (ligações entre títulos) | GraphQL do AniList, ~12 consultas (lib/franquias.ts) | 6 h | Última versão boa; sem nenhuma, site sem franquias |
O cabeçalho pode estar em qualquer uma das 10 primeiras linhas. Cada campo aceita alguns nomes de
coluna (o primeiro que existir vence; ver COLS em lib/sheet.ts):
N°, Nome, Nome_Ingles, Score, Episodes, Time/episode, Rewatched, Studio, Gênero,
Tema, Demografia, Temporada (ex.: "Fall 2024" → season + ano), Coments, Favorite
(contém "FAV" = favorito), Last seen (DD/MM/AAAA ou AAAA-MM-DD), Link / Imagem (capa),
URL_Pagina (MyAnimeList; o ID do link é usado para as franquias), Link do Anime (Crunchyroll),
Streaming e Franquia (opcional, ver "Franquias").
Valores de Gênero, Tema, Estúdio e Demografia que só diferem em maiúsculas são unificados (fica a grafia mais frequente).
Uma linha por vez que um anime foi assistido. Colunas: Data/Mês (DD/MM/AAAA, AAAA-MM ou
"Março 2023"; pode haver mais de uma, vale a primeira reconhecida), Nome/Anime, N° (formato
antigo, usado só se não houver nome) e Rewatch (0 = primeira vez, 1 = primeiro rewatch…).
A ligação com "Animes Completos" é pelo nome (ignorando maiúsculas e espaços); linhas sem
correspondência ficam de fora, mas não somem em silêncio: o Stats mostra um aviso amarelo
("⚠ N linhas da aba Historico não acharam o anime…", components/AvisoHistorico.tsx) com o mês, o
nome digitado e, quando há um nome parecido na lista, "você quis dizer …?" (historicoSemPar em
lib/history.ts). Corrigido o nome na planilha, o aviso some na renovação seguinte. Alimenta a
retrospectiva, o gráfico "Assistidos ao longo do tempo" e o histórico de visualizações no modal.
Colunas: Número, Anime, Dia de inicio (data), Dia da semana ("Segunda"…"Domingo"),
Último episódio visto, Semanal, Url Imagem (URL da capa, ex.:
https://cdn.myanimelist.net/images/anime/1154/159987l.jpg) e Imagem (imagem colada na célula
ou =IMAGE("url"), usada só quando Url Imagem está vazia), Onde assistir? (logo do streaming
colado na célula) e Link (texto com hiperlink, =HYPERLINK("url"; ...) ou a URL digitada).
Imagens coladas e a URL por trás do texto "Link" não saem no gviz: vêm do doGet do Apps Script.
Semanal: V = em dia, X = episódio novo não visto, - = não estreou, vazio = sem marcação.
Três abas no topo: ANIME LIST (/), STATS (/stats e /stats/retrospectiva) e
TEMPORADA (/temporada), definidas em lib/tabs.ts. Cada aba é uma página pronta, então o F5
abre direto nela. Os dados e o App ficam no layout comum (app/(site)/layout.tsx; as páginas só
marcam o endereço): trocar de aba é uma navegação do Next que não recarrega nada (a aba muda na hora, com useOptimistic, sem esperar o servidor responder a rota; o endereço acompanha), e voltar/avançar do
navegador funciona. Links antigos /?aba=stats e /?aba=temporada são redirecionados
(next.config.mjs); /#stats e /#temporada são convertidos no navegador.
Filtros (?busca=, ?raridade=...) e o filtro de status da Temporada (?status=) também ficam no
endereço, mas como a página pronta é igual para todos, eles são aplicados no navegador: um script no
app/layout.tsx esconde o conteúdo até aplicar (classe url-pendente), para a lista não piscar sem
filtro. Se o JavaScript falhar, o conteúdo aparece sozinho em 2,5 s.
lib/suggest.ts). O sorteio roda só no cliente para não quebrar a hidratação.lib/urlFiltros.ts): o F5 não os perde, trocar de
aba os mantém e dá para salvar ou compartilhar uma busca. Só entra o que difere do padrão. Parâmetros:
busca, score e eps (faixa min-max, ex.: 8-10, 8-), de e ate (AAAA-MM-DD), season,
ano, estudio, genero, tema, demografia, fav, rewatch, raridade, franquia (repetidos para vários
valores), ordem e crescente (1/0). Ex.: /?raridade=SSR&raridade=SR&ano=2024&ordem=score&crescente=0.Raridade das cartas: score 10 = SSR, 9 = SR, 8 = R, até 7 = N (tierOf em lib/types.ts).
Duas páginas, com abas internas VISÃO GERAL e RETROSPECTIVA E FRANQUIAS. Tudo responde aos filtros.
Visão geral (/stats): heatmap de atividade por ano (com seletor e nomes no tooltip; em tela larga a grade não rola, para o
tooltip da segunda-feira não ser cortado, e nas primeiras/últimas semanas ele abre para dentro), distribuição por score, ano de
lançamento, assistidos ao longo do tempo (por mês; a partir de jan/2023 usa a aba Historico e conta
rewatches), top 15 estúdios, top 12 temas, gêneros e demografia (barra empilhada).
Retrospectiva e franquias (/stats/retrospectiva): retrospectiva do ano, painel de franquias (ver
"Franquias") e mais reassistidos (top 24).
Retrospectiva (components/Retro.tsx, retrospectiva em lib/stats.ts): resumo de um ano pela
aba Historico — só de 2023 em diante, porque antes não há registro de cada vez assistida. Mostra vezes
que assistiu (1ª vez × rewatches), animes diferentes, episódios, horas, nota média, mês mais ativo,
gráfico por mês, top estúdios/gêneros/temas e as 12 maiores notas entre os animes vistos pela 1ª vez
no ano (rewatches ficam de fora; capas clicáveis, mesmo tamanho das de "mais reassistidos"). No ano em andamento
avisa até que mês vai. Comparar com outro ano mostra os dois lado a lado (tabela com diferença,
meses e gêneros/estúdios de cada um); se um dos anos estiver em andamento, compara por padrão o mesmo
período (jan até o mês atual) nos dois — dá para desmarcar.
?status=X&status=-; sem = sem marcação), então o F5 mantém.V),
vermelho = episódio novo não visto (X), azul = não estreou (-). Sem marcação fica neutro.Onde assistir?) + link (Link), abre em
nova aba. Sem logo (ou se o logo não carregar), mostra o nome do site tirado da URL
("ASSISTIR NO CRUNCHYROLL"). Só logo, sem link: mostra o logo sem ser clicável.POST /api/temporada → Apps Script.V (semanalAoMarcar). Nunca vira X sozinho: o AniList às vezes
conta episódios que atrasaram (Bleach: diz 10 lançados, só saíram 8), então aí o ✓ é manual.localStorage do navegador
(anime-view-senha). Senha errada → pede de novo.- (não estreou) vira X (não visto) a partir da
segunda-feira da semana da estreia — a semana começa na segunda. Ex.: estreia em 05/10/2026
(segunda) ou 06/10/2026 (terça) → muda em 05/10; estreia em 12/10 → só em 12/10. O site já mostra
assim (semanalEfetivo) e o gatilho diário do script grava na planilha. As datas são comparadas
como texto AAAA-MM-DD (no script, no fuso da planilha), então o fuso não adianta a mudança.
No script, o dia da célula de estreia é lido com 12 h de folga (isoDaCelula): se o fuso do script
e o da planilha diferirem, a meia-noite da célula caía no dia anterior e uma estreia de segunda
(ex.: Psyren, 05/10) mudava de - para X já no domingo.lib/franquias.ts junta os títulos da planilha que o AniList liga como continuação (SEQUEL/PREQUEL),
história paralela (SIDE_STORY: OVAs, especiais e filmes da mesma história) ou versão
alternativa (ALTERNATIVE: remakes e recontagens, como Kenpuu Denki Berserk, FMA 2003 e Brotherhood,
Trigun e Stampede, Steins;Gate 0). Spin-offs (ex.: Vigilante, de Boku no Hero; Gun Gale Online, de SAO)
e crossovers (Isekai Quartet) ficam separados.
O tipo PARENT não é usado de propósito: é por ele que os spin-offs apontam de volta para a série.
Franquia (opcional, na aba Animes Completos): o que estiver escrito manda. Se for igual
(sem ligar para maiúsculas) ao nome de uma franquia automática, o título entra nela. Serve para
corrigir o que o AniList ligar errado ou deixar de ligar.?franquia= no endereço) e linha FRANQUIA no modal do anime.O site é instalável (app/manifest.ts): no Android/Chrome, menu › Instalar app (ou "Adicionar à
tela inicial"); no iPhone/Safari, Compartilhar › Adicionar à Tela de Início. Abre em tela cheia,
sem a barra do navegador, com o ícone do site (public/icon-192.png, icon-512.png e
icon-maskable-512.png, que o Android recorta em círculo/quadrado). O app instalado abre o próprio
site, então toda mudança publicada já aparece nele.
Layout de celular (bloco @media (max-width: 640px) no fim de app/globals.css, pensado para uma mão):
viewportFit: "cover" em app/layout.tsx); o cabeçalho fica só com a marca..shell): o texto volta ao tamanho normal.POST /api/temporada (app/api/temporada/route.ts) — repassa para o Apps Script:
{ "numero": 3, "episodio": 5, "senha": "..." } // grava "Último episódio visto" (vazio apaga)
{ "numero": 3, "semanal": "V", "episodio": 5, "senha": "..." } // grava "Semanal"
Respostas: 200 { ok: true, ... }, 400 dados inválidos, 401 senha errada, 403 pedido de outro site, 413 corpo grande, 429 muitas senhas erradas, 502 script fora.
Em caso de sucesso, invalida o cache da tag temporada e todas as páginas.
GET /api/franquias (app/api/franquias/route.ts): ligações do AniList (cache de 6 h), usado pelo
navegador quando a página pronta saiu sem as franquias.
apps-script/Temporada.gs)Ponte entre o site e a aba "Temporada Atual". Não roda no Next: é colado na própria planilha.
doGet → { itens: [{ numero, imagem, streaming, link }] }: capa colada em Imagem (reserva para
linhas sem Url Imagem), logo colado em Onde assistir? e URL da coluna Link.doPost → grava episódio ou status, conferindo a senha da propriedade de script SENHA.atualizarEstreias (gatilho diário às 6h, criado rodando instalarGatilho uma vez):
- → X na semana da estreia; toda segunda, V → X (menos quem já completou todos os
episódios, consultando o AniList).Instalação e atualização (mantendo a mesma URL) estão descritas no topo do arquivo. Ao alterar o
.gs, é preciso reimplantar: Implantar › Gerenciar implantações › editar › Nova versão.
Link como está.123.jpg por 123l.jpg).realesr-animevideov3, fiel à arte) e ficam em public/covers/, listadas em
lib/hdCovers.ts. Anime novo na planilha não precisa de nada: usa a versão grande do MyAnimeList.Url Imagem como está; se vier da coluna Imagem (Google), é reduzida
de 2048 px para 360 px (=s360). Logos do streaming são reduzidos para 96 px (=s96).app/
layout.tsx fontes, metadados, cor do tema; script que esconde até aplicar filtros da URL
(site)/layout.tsx layout das abas: monta <Pagina> (dados + App), renovado a cada 60 s
(site)/page.tsx "/" (e stats/page.tsx, stats/retrospectiva/page.tsx, temporada/page.tsx):
só os endereços, vazios; a aba sai do endereço
error.tsx, global-error.tsx telas de erro com "tentar de novo"
manifest.ts manifesto para instalar no celular
globals.css todo o visual
api/temporada/ rota POST que grava na aba Temporada Atual
api/franquias/ rota GET com as ligações do AniList (reserva do navegador)
icon.svg, apple-icon.png
lib/
protecao.ts origem permitida e limite de senhas erradas (POST /api/temporada)
dados.ts cache das 3 abas (60 s) e das franquias (6 h), com hora da leitura e a última versão boa
franquias.ts ligações do AniList → franquias; resumo de cada uma
types.ts tipo Anime, raridades (tierOf)
tabs.ts abas e endereços (/, /stats, /stats/retrospectiva, /temporada)
urlFiltros.ts filtros e ordenação ↔ parâmetros do endereço (servidor e cliente)
sheet.ts CSV "Animes Completos" → Anime[]
history.ts CSV "Historico" → Viewing[], ligação por nome, linhas sem par
temporada.ts gviz "Temporada Atual" (com Url Imagem) + streaming/link/capas reserva
(Apps Script) + AniList
filters.ts filtros em cascata e ordenação
stats.ts agregações dos KPIs e gráficos, retrospectiva do ano
suggest.ts sorteio ponderado da puxada do dia
format.ts datas, números, hora de atualização, cor por nome
hdCovers.ts lista das capas ampliadas em public/covers/
components/
Pagina.tsx carrega a planilha (com prazo para fontes lentas) e monta o App
App.tsx estado (aba pelo endereço, filtros e ordenação, franquias; modal)
Seguro.tsx protege cada pedaço: erro mostra aviso só no lugar dele
AvisoHistorico.tsx aviso no Stats de linhas do Historico sem par na lista
Header.tsx marca e abas (barra de baixo no celular)
Hero.tsx puxada do dia
KpiStrip.tsx, FilterBar.tsx, FilterDrawer.tsx
Collection.tsx, Card.tsx, Poster.tsx, DetailModal.tsx
Stats.tsx as duas páginas do Stats (visão geral; retrospectiva e franquias)
Retro.tsx retrospectiva do ano e comparação entre anos
Franquias.tsx painel de franquias do Stats
Season.tsx aba Temporada (filtro de status, episódios, onde assistir, senha)
apps-script/
Temporada.gs script do Google colado na planilha
public/covers/ capas ampliadas
public/icon-*.png ícones do app instalado
tests/ testes das regras (npm test)
.github/workflows/ testes a cada push no GitHub
Anime-Tracker/app.py)| Streamlit | Anime View |
|---|---|
| KPIs: animes, score médio, tempo assistido, episódios + eps de rewatch | Faixa de KPIs (agora respondem aos filtros) |
| Busca por nome JP ou EN | Campo > buscar_titulo no topo |
| Filtro score (slider) | Slider duplo na gaveta de filtros |
| Filtro "Visto entre" | Datas De/Até (animes sem data não somem mais) |
| Season, Ano, Estúdio, Gênero, Tema, Demografia, Favorito, Rewatched | Mesmos filtros, em cascata como antes, com contagem por opção |
| — | Novo: filtro por raridade (SSR/SR/R/N) |
| Limpar todos os filtros | "limpar tudo" na barra e na gaveta |
| Ordenar por N°, Nome, Score, Episódios, Visto em, Ano, Studio + crescente/decrescente | Igual, na barra e na gaveta; padrão agora é "Visto em" decrescente |
| Cards com capa, score, favorito, rewatch; overlay com detalhes, comentário, MAL, Crunchyroll | Cartas com moldura por raridade; clique abre modal com tudo isso + streaming + histórico |
| Sugestão do Dia (sorteio ponderado) | "Puxada do dia" no topo, mesma regra de peso, sobre os filtros atuais |
| Empty state | Igual |
| Heatmap de atividade | Heatmap por ano, com seletor de ano e nomes no tooltip |
| Distribuição por score | Colunas coloridas por raridade |
| Animes por ano de lançamento | Colunas com o pico destacado |
| Assistidos ao longo do tempo | Área por mês, com rewatches da aba Historico desde 2023 |
| Top 20 rewatches | Top 24, em grade de capas clicáveis |
| Top 15 estúdios, Top 12 temas | Barras horizontais |
| Pizza de demografia e de gênero | Barra empilhada (demografia) e barras (gêneros) |
| — | Novo: aba Temporada com gravação na planilha |
AGENTS.md é reescrito pelo next dev; instruções do projeto ficam em CLAUDE.md.