openjutsu
영상에서 원클릭으로 인물 교체, ComfyUI·MiniMax H3 기반 오픈소스 로컬 힉스필드 겐주츠 대안, FLUX.3 Klein 재조명 지원
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. 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.