Ir para o conteúdo

Documentação oficial

Central de Ajuda

Tudo sobre o WatchVerse: como instalar, usar cada recurso, resolver problemas e entender a arquitetura.

Atualizado em 03/11/2026 · watchverse.fun/documentacao

O WatchVerse é um aplicativo Android que reúne rádio online, TV ao vivo, notícias, futebol, filmes, séries, animes, mangás e jogos em um só lugar. O acesso ao catálogo é liberado por uma conta Google (Gmail) e por um acesso ativo de 30 dias, vendido por US$ 1.

Esta Central de Ajuda é a documentação oficial. Ela é publicada em https://watchverse.fun/documentacao e também é aberta pelo botão Ajuda dentro do aplicativo, em Perfil → Ajuda.

Por onde começar

Para quem desenvolve ou administra

O que o WatchVerse não faz

  • Não hospeda filmes, séries, canais ou mangás. O app organiza catálogos e abre players/leitores de terceiros.
  • Não vende assinatura recorrente: o acesso é uma compra única de 30 dias.
  • Não funciona em iPhone nesta versão. O alvo é Android 10 ou superior.
  • Não garante disponibilidade de conteúdo de terceiros. Catálogo, canais e capítulos podem mudar sem aviso.

Versão documentada

Esta documentação descreve o aplicativo 4.4.13 (versionCode 19) e o site publicado em watchverse.fun. Quando uma funcionalidade existe no código mas não é usada na versão atual, isso é indicado explicitamente no capítulo correspondente.

Usuário

Primeiros passos

Requisitos

ItemValor
SistemaAndroid 10 (API 29) ou superior
ConexãoInternet obrigatória para login, catálogo, canais, notícias e pagamento
ContaGoogle/Gmail verificada
EspaçoO APK atual tem cerca de 120 MB
OrientaçãoRetrato e paisagem (inclui tablets, Samsung DeX e TVs compatíveis)

O WatchVerse não está disponível para iPhone nesta versão. Em aparelhos sem os serviços do Google Play, o login pode não funcionar.

1. Baixar e instalar

  1. Abra https://watchverse.fun e toque em Baixar APK para Android.
  2. Confira o SHA-256 exibido na página de download, se quiser validar o arquivo. O site publica também o arquivo .sha256.
  3. Ao abrir o APK, o Android pode pedir permissão para instalar aplicativos de fonte desconhecida. Autorize apenas para o navegador ou gerenciador de arquivos usado no download.
  4. Conclua a instalação e abra o WatchVerse.

O aplicativo não pede permissão de câmera, armazenamento, mídia ou notificações. Essas permissões foram removidas do manifesto.

2. Entrar com Google

Na primeira abertura, o app mostra a tela de login. Toque em Continuar com Google e escolha uma conta Gmail.

  • Contas que não sejam Gmail são recusadas.
  • O login usa o Google Sign-In e o Firebase Authentication.
  • A conta fica vinculada a um único aparelho. Se a mesma conta for usada em outro aparelho, o acesso é bloqueado com a mensagem de aparelho não autorizado.

3. Confirmar o código de 8 dígitos

Em alguns casos o Worker exige uma verificação adicional por e-mail. O app abre a tela de código.

RegraValor
Formato8 dígitos
Validade5 minutos
Tentativas3 por código
ReenvioA partir de 60 segundos
LimiteAté 5 códigos por hora por conta

Digite o código recebido no e-mail da conta. Se ele expirar, peça outro. Verifique também a pasta de spam.

Depois da confirmação, o app guarda um token de sessão no armazenamento seguro do Android (SecureStore). Esse token é exigido pelas rotas de acesso e de conteúdo pago.

4. Ativar o acesso

Se a conta ainda não tiver acesso ativo, o app abre a tela Ative seu acesso.

  • Valor: US$ 1 por 30 dias.
  • Pagamento único com cartão de crédito ou débito, processado pelo Stripe.
  • Depois de pagar, o app verifica o status automaticamente por até 30 segundos (15 tentativas a cada 2 segundos).
  • Se o pagamento já tiver sido feito, use Já paguei, verificar.
  • A tela também permite Sair da conta.

Quando o acesso é confirmado, o app libera a navegação principal. O status, a data de expiração e a chave de ativação (quando existir) aparecem em Perfil.

5. Renovar

O acesso não renova sozinho. Quando expirar, o app volta à tela de ativação e o cartão de acesso no Perfil mostra Expirado.

  1. Abra Perfil.
  2. No cartão de acesso, toque em Renovar (ou Pagar 1 USD).
  3. Conclua o pagamento e use Já paguei, verificar se necessário.

Primeira execução: o que acontece

  1. A splash nativa é exibida.
  2. O app executa as verificações de integridade em produção (ambiente de desenvolvimento, emulador, root e assinatura).
  3. Uma animação curta da marca é exibida.
  4. O Firebase, os provedores de player e o catálogo são inicializados.
  5. Se a inicialização falhar, aparece uma tela de erro com opção de tentar novamente.

Em produção, o app bloqueia emuladores, aparelhos com root e builds com assinatura diferente da oficial. A captura de tela também é prevenida enquanto o app está em uso.

Atualizações

A versão atual não executa atualização OTA dentro do app. Para atualizar, baixe o APK mais recente no site oficial e instale sobre a versão existente. A assinatura precisa ser a mesma; por isso, não instale APKs de outras fontes.

Se algo der errado

  • Login recusado: confirme que a conta é Gmail e que os serviços do Google Play estão disponíveis.
  • Código não chega: aguarde 60 segundos, confira spam e tente novamente dentro do limite de 5 por hora.
  • Pagamento não libera: aguarde alguns instantes e toque em Já paguei, verificar. Se persistir, use o contato do site.
  • Aparelho não autorizado: a conta já está vinculada a outro aparelho. O suporte precisa liberar a troca.
  • Erro de conexão: veja Solução de problemas.

↑ Voltar ao início

Usuário

TV ao vivo e rádio

TV ao vivo

A TV usa listas públicas de canais (iptv-org) e listas de reserva mantidas pelo app. A tela permite:

  • escolher o país nas abas horizontais;
  • buscar por nome, categoria ou grupo;
  • ver o indicador de saúde do canal (online, lento, offline ou verificando);
  • favoritar canais;
  • abrir o canal no player interno.

Países disponíveis

Brasil, Estados Unidos, Espanha, Argentina, México, Colômbia, Chile, Peru, Portugal, Itália, França, Alemanha, Reino Unido, Canadá, Japão, Coreia do Sul e Uruguai. A opção Todos reúne os países.

Como os canais são carregados

  1. O app baixa a lista M3U do país.
  2. Aplica a blocklist pública do iptv-org.
  3. Remove canais HTTP; somente HTTPS é aceito.
  4. Mescla canais de reserva para Brasil, Espanha e Estados Unidos.
  5. Guarda o resultado em cache por 24 horas.
  6. Verifica a saúde dos streams e guarda o resultado por 12 horas.
  7. Canais marcados como offline três vezes seguidas deixam de aparecer na lista padrão.

O indicador de saúde é uma estimativa: ele testa a resposta HTTP do stream, não a qualidade real do vídeo.

Player de TV

O player usa expo-video com suporte a HLS. Ele oferece:

  • carregamento/buffering;
  • mensagem de erro quando o canal não abre;
  • ajuste de enquadramento (preencher a tela ou esticar);
  • botão para abrir o rádio;
  • reprodução em retrato ou paisagem.

Alguns canais exigem cabeçalhos Referer/User-Agent específicos. O app repassa esses cabeçalhos quando a lista os informa.

Limitações

  • Canais podem sair do ar, mudar de URL ou bloquear a região.
  • Canais privados/geobloqueados não são contornados pelo app.
  • A disponibilidade varia por país e provedor.
  • O WatchVerse não hospeda nem redistribui os streams.
  • O modo de catálogo via Worker (/api/iptv/*, com URLs assinadas) existe no código, mas é opcional e desligado por padrão. Na configuração padrão, o app usa as listas públicas.

Rádio

A rádio usa o Radio Browser, consultado pelo Worker. A tela permite:

  • escolher o país nas abas (as mesmas da TV, incluindo Todos);
  • buscar por nome, país, gênero ou idioma;
  • favoritar estações;
  • abrir o player de rádio.

O Worker retorna até 100 estações por país, ocultando estações quebradas e ordenando por popularidade. A lista é normalizada e duplicatas de URL são removidas.

Player de rádio

  • Reprodução em segundo plano e controles na tela de bloqueio (título, artista e capa quando disponíveis).
  • Botões de play/pause, reconectar e favoritar.
  • Indicador “Ao vivo”.
  • Reconexão automática com aviso quando o stream cai.
  • Player dedicado com barras de “now playing”.

Espectro de áudio (limitado)

O player pode exibir um espectro de áudio, mas o recurso depende da permissão de gravação de áudio do Android. O APK atual não declara RECORD_AUDIO, então o espectro tende a aparecer como indisponível ou exigir uma permissão que o sistema não concede. A reprodução do rádio continua funcionando normalmente.

Limitações

  • Estações podem estar offline ou mudar de URL.
  • A ordem e a disponibilidade vêm do Radio Browser e podem variar.
  • Streams HTTP são recusados pelo app.
  • Não há download de estações para ouvir offline.

↑ Voltar ao início

Usuário

Notícias e futebol

Notícias

A seção Notícias reúne manchetes por país, com resumo e link para a fonte original.

Países

Brasil, Estados Unidos, Reino Unido, França, Alemanha, Espanha, Itália, Portugal, Japão e China.

Como funciona

  1. O Worker coleta manchetes e conteúdo de fontes públicas.
  2. O texto é resumido automaticamente e limitado a 3.000 caracteres.
  3. O resumo, a imagem e os metadados ficam no banco D1 do Worker.
  4. O app pede 20 artigos por página e mostra os mais recentes.
  5. Ao abrir um artigo, o app carrega o resumo e a mídia disponível.

O Worker atualiza um país a cada 20 minutos, em rodízio. Os artigos são mantidos para o dia local do país e limpos depois.

O que aparece no app

  • título, fonte, país e horário;
  • selo de “recente” para itens das últimas 6 horas;
  • imagem de capa, quando disponível;
  • resumo em português ou no idioma da fonte, conforme o país;
  • até 4 itens de mídia (imagens ou vídeo) quando a fonte e a licença permitem;
  • botão para abrir a notícia original.

Licenças e créditos

O Worker só aceita mídia com licença compatível (por exemplo, Creative Commons CC BY ou CC BY-SA) e mantém o nome e o link da licença. O artigo no app exibe a fonte e o crédito. Se a licença não for reconhecida, a mídia é descartada.

Avisos importantes

  • O resumo é gerado automaticamente e pode conter imprecisões. Confira sempre a fonte original.
  • O WatchVerse não é o autor da notícia e não controla o conteúdo de terceiros.
  • Links externos são abertos no navegador do aparelho.
  • Não há leitura offline nem armazenamento permanente dos artigos.

Futebol

A seção Futebol mostra dados de oito competições, obtidos do football-data.org v4 por meio do Worker.

País/regiãoCompetição
BrasilCampeonato Brasileiro Série A
ItáliaSerie A
AlemanhaBundesliga
EspanhaLa Liga (Primera Division)
InglaterraPremier League
FrançaLigue 1
PortugalPrimeira Liga
Países BaixosEredivisie

Abas

  • Classificação — posição, time, pontos, jogos, vitórias, empates, derrotas, gols pró/contra e saldo.
  • Resultados — partidas encerradas, com placar e rodada.
  • Próximos jogos — partidas futuras, com data, hora e local quando disponíveis.

Atualização e cache

  • O Worker guarda os dados em cache por cerca de 5 minutos.
  • A tela permite atualizar manualmente.
  • Quando a atualização falha, o app pode mostrar dados antigos com o aviso de cache/instabilidade.
  • Partidas em andamento recebem o selo AO VIVO quando a fonte informa esse estado.

Limitações

  • O futebol é somente informativo: não há transmissão de jogos na seção.
  • A fonte pode atrasar placares ou não cobrir competições menores.
  • Escudos e nomes de times dependem do retorno da API.
  • A classificação pode aparecer incompleta em períodos de atualização da fonte.

↑ Voltar ao início

Usuário

Mangás e jogos

Mangás

Os mangás vêm da MangaDex. O app consulta a API diretamente; no site, o mesmo catálogo usa um proxy Netlify para evitar CORS.

  • grade com 3 colunas e 24 títulos por página;
  • rolagem infinita;
  • busca com atraso de digitação;
  • filtro por idioma de tradução;
  • apenas títulos com classificação safe são solicitados à MangaDex.

Idiomas disponíveis no filtro: todos, português (BR), inglês, espanhol, francês, italiano, alemão, russo, indonésio, polonês, vietnamita, turco, árabe, chinês, japonês e coreano.

Detalhes do mangá

A tela mostra capa, título, ano, status, autores, descrição e a lista de capítulos. É possível:

  • filtrar capítulos por idioma;
  • continuar do capítulo salvo;
  • abrir qualquer capítulo no leitor.

Os capítulos buscados incluem, por padrão, português (BR) e inglês, além do idioma selecionado no catálogo. Isso evita que um mangá pareça “sem capítulos” quando o filtro está em outro idioma.

Leitor

  • leitura vertical contínua;
  • contador de páginas;
  • pré-carregamento das duas próximas páginas;
  • navegação para o capítulo anterior/próximo;
  • tela mantida acesa durante a leitura;
  • modo imersivo (barra de status oculta).

O progresso é salvo no aparelho por mangá, com o ID do capítulo, o rótulo, o idioma e a data. A chave usada é wv_manga_progress_v1, a mesma do leitor do site, o que facilita exportar/importar no futuro.

Limitações

  • A disponibilidade de capítulos depende da MangaDex e dos grupos de scanlation.
  • Não há download para leitura offline.
  • O progresso de mangá é local; não sincroniza entre aparelhos.
  • Conteúdo adulto não é solicitado pelo app (contentRating=safe).

Jogos

O catálogo de jogos usa RAWG, com enriquecimento opcional de descrições e trailers da Steam, tudo por meio do Worker.

Catálogo

  • ordenação por populares, recentes ou futuros;
  • filtro por gênero;
  • busca por nome;
  • 30 jogos por página, em grade de 2 colunas;
  • cache local de 10 minutos para listas e 6 horas para detalhes.

Detalhes do jogo

A ficha pode mostrar:

  • capa, imagem de fundo, ano e nota;
  • nota Metacritic, tempo médio de jogo e plataformas;
  • descrição (RAWG ou Steam, conforme disponibilidade);
  • gêneros, desenvolvedoras, publicadoras e site oficial;
  • capturas de tela em visualizador com zoom;
  • trailers da Steam;
  • botão para ouvir a descrição por voz (TTS do aparelho).

A tela Mídia reúne capturas e trailers em uma grade dedicada.

Limitações

  • O WatchVerse não vende, baixa ou executa jogos. É um catálogo informativo.
  • Trailers só aparecem quando o Worker consegue enriquecer o jogo com dados da Steam.
  • Descrições e imagens podem variar conforme o idioma e a fonte.
  • Alguns jogos não têm capturas, trailers ou descrição.
  • O TTS depende das vozes instaladas no Android; se não houver voz para o idioma, o app avisa.

↑ Voltar ao início

Usuário

Conta, acesso e privacidade

Conta

O WatchVerse usa apenas login Google. A conta precisa ser Gmail verificada. O perfil exibe nome, e-mail e foto do Google; o avatar pode ser trocado por uma opção pronta ou por uma imagem da galeria.

A conta é vinculada a um aparelho. O identificador usado é o Android ID (SSAID). Se a conta for aberta em outro aparelho, o Worker retorna DEVICE_MISMATCH e o app bloqueia o acesso até que o suporte libere a troca.

Licença

ItemValor
PreçoUS$ 1
Duração30 dias
CobrançaPagamento único com cartão (Stripe)
RenovaçãoManual; não há débito automático
Status possíveisACTIVE, EXPIRED, NONE, DEVICE_MISMATCH, OTP_REQUIRED

O cartão de acesso em Perfil mostra:

  • status atual e dias restantes;
  • data de expiração;
  • chave de ativação, quando o backend fornece uma;
  • botão de renovação;
  • botão de atualizar o status.

Como o status é verificado

O app chama GET /access/status com o token do Firebase, o ID do aparelho e o token de sessão. O Worker responde com o status, a expiração e os dias restantes.

  • ACTIVE: libera o app.
  • EXPIRED ou NONE: abre a tela de pagamento.
  • OTP_REQUIRED: abre a verificação por código.
  • DEVICE_MISMATCH: bloqueia e orienta a falar com o suporte.
  • ERROR: mostra erro de conexão com opção de tentar novamente ou sair.

Pagamento

O app cria uma sessão de checkout no Worker e abre a página do Stripe em uma WebView. Quando o pagamento é concluído, o Stripe chama o webhook do Worker, que grava o acesso no Firebase. O app consulta o status por até 30 segundos.

Se o pagamento foi feito mas o acesso não apareceu, use Já paguei, verificar. Não pague duas vezes sem antes verificar o status.

Biometria

A biometria é opcional e configurada em Perfil → Configurações. Ela protege a sessão já autenticada; não substitui o login Google.

  • Requer biometria forte cadastrada no Android.
  • A preferência é salva no armazenamento seguro.
  • Se a autenticação falhar, o app oferece sair da conta.
  • Em aparelhos sem biometria compatível, a opção não funciona.

Sair da conta

Perfil → Sair encerra a sessão do Firebase, revoga o token de sessão no Worker quando possível e limpa o token local. Favoritos e progresso locais permanecem no aparelho; os dados sincronizados continuam na conta.

Dados coletados

O WatchVerse coleta o mínimo necessário para autenticar, liberar o acesso e manter o serviço. De forma geral:

DadoFinalidade
Nome, e-mail e foto do GooglePerfil e identificação da conta
UID do FirebaseVincular favoritos, progresso e licença
Android ID (SSAID)Vincular a conta a um aparelho
Modelo, marca, versão do Android e versão do appDiagnóstico e registro do dispositivo
Endereço IP (hash) e país/região/cidade aproximadosSegurança, antifraude e estatísticas
Status da licença e expiraçãoLiberar o acesso
Favoritos e progresso de reprodução/leituraSincronizar a experiência
Estado de leitura das notificaçõesContador de não lidas
Identificador de instalação de anúnciosMedir impressões e cliques
Eventos de anúncio (impressão, clique, fechamento)Relatório de campanhas
Diagnósticos de erro (Sentry)Corrigir falhas

O app não pede câmera, armazenamento, mídia ou permissão de notificações. O backup do aplicativo está desativado (allowBackup=false).

Armazenamento local

  • AsyncStorage: favoritos locais, progresso, preferências da Home, cache de catálogo, avatar escolhido, notificações lidas e cache do banner.
  • SecureStore: token de sessão, preferência de biometria, estado de licença e idioma.

Nada disso é acessível a outros aplicativos em um aparelho sem root.

Anúncios

O banner é carregado do Firebase Realtime Database e exibido após 60 segundos de uso para contas ativas. O app envia eventos de impressão, clique e fechamento ao Worker, com identificador de instalação, versão do app e dados aproximados de região. O conteúdo do anúncio é HTML fornecido pelo backend; ao tocar em um link, o app valida o URL e abre no navegador.

Segurança do aplicativo

Em builds de produção:

  • emuladores, root e ambiente de desenvolvimento são bloqueados;
  • a assinatura do APK é verificada;
  • a captura de tela é prevenida;
  • todo tráfego é HTTPS (cleartext bloqueado);
  • o app não permite backup dos dados;
  • WebViews de player e anúncio aplicam whitelist de hosts e bloqueiam navegação insegura.

Privacidade e termos

  • Política de Privacidade: https://watchverse.fun/privacidade.html
  • Termos de Uso: https://watchverse.fun/termos.html
  • Contato: https://watchverse.fun/contato.html

Para solicitar exclusão de dados ou troca de aparelho, use o formulário de contato com o e-mail da conta. Não há exclusão automática de conta dentro do app nesta versão.

↑ Voltar ao início

Usuário

Solução de problemas

Antes de pedir suporte

  1. Confirme que está usando o APK oficial de watchverse.fun.
  2. Verifique a conexão com a internet.
  3. Feche e abra o app novamente.
  4. Em Perfil, toque no botão de atualizar o status do acesso.
  5. Se o problema for em um conteúdo específico, teste outro título/canal para separar falha do app de falha do provedor.

Instalação

“App não instalado” ou “pacote inválido”

  • Baixe novamente o APK; o arquivo pode ter chegado incompleto.
  • Confira o SHA-256 publicado no site.
  • Desinstale uma versão de outra origem antes de instalar a oficial. Assinaturas diferentes não podem coexistir.
  • Verifique se há espaço livre suficiente (cerca de 120 MB para o APK, mais o espaço de instalação).

Android bloqueia a instalação

  • Autorize “instalar apps desconhecidos” para o navegador ou gerenciador de arquivos usado.
  • Em Android 14+, pode ser necessário liberar o instalador de pacotes nas configurações.

App fecha ao abrir

  • Em produção, o app bloqueia emuladores, root e builds com assinatura diferente.
  • Se aparecer a tela de segurança, use um aparelho sem root e o APK oficial.
  • Reinicie o aparelho e tente novamente.

Login

“Entre com uma conta Gmail”

  • O WatchVerse só aceita contas Gmail. Contas corporativas ou de outros domínios são recusadas.

O Google não abre ou falha

  • Atualize os serviços do Google Play.
  • Verifique se há uma conta Google configurada no aparelho.
  • Teste outra rede.
  • Se o erro persistir, saia e tente novamente.

A conta funciona em outro aparelho, mas não neste

  • A conta já está vinculada a outro aparelho. Use o contato do site para solicitar a troca. O app não permite desvincular sozinho.

Código de verificação

O código não chega

  • Aguarde até 60 segundos antes de pedir outro.
  • Confira a pasta de spam/lixo eletrônico.
  • Confirme que o e-mail é o mesmo da conta Google.
  • Há limite de 5 códigos por hora.

“Código expirado”

  • Peça um novo código. A validade é de 5 minutos.

“Muitas tentativas”

  • O código permite 3 tentativas. Peça outro e digite com cuidado.
  • Se o limite por hora foi atingido, aguarde antes de tentar novamente.

Pagamento e acesso

Paguei, mas o app continua pedindo pagamento

  • Aguarde alguns instantes e toque em Já paguei, verificar.
  • Confirme se o pagamento foi aprovado no cartão.
  • Verifique se o e-mail da compra é o mesmo da conta logada.
  • Se o cartão foi recusado, tente outro meio de pagamento.

“Aparelho não autorizado”

  • A conta está vinculada a outro aparelho. Solicite a liberação pelo contato.

“Não foi possível verificar seu acesso”

  • É falha de conexão ou instabilidade do Worker. Toque em Tentar novamente.
  • Se persistir, saia e entre novamente.
  • Em último caso, use o contato.

O acesso expirou antes do esperado

  • O cartão do Perfil mostra a data real de expiração.
  • Renove normalmente; não há renovação automática.

TV ao vivo

O canal não abre

  • Teste outro canal do mesmo país.
  • O canal pode estar offline ou geobloqueado.
  • O indicador de saúde pode estar desatualizado; atualize a lista.
  • Canais que falharam três vezes podem sumir da lista padrão.

A lista está vazia

  • Troque o país e volte.
  • Puxe para atualizar.
  • Verifique a conexão. A lista é cacheada por 24 horas.

O vídeo trava ou fica em buffering

  • Teste outra rede (Wi-Fi/dados).
  • Feche outros apps que usam banda.
  • Alguns canais são naturalmente instáveis; isso não é controlado pelo WatchVerse.

Rádio

Não toca

  • Toque em Reconectar.
  • Teste outra estação.
  • Verifique se o stream está disponível no seu país.
  • Confirme que o volume de mídia está alto.

Para ao bloquear a tela

  • O app suporta reprodução em segundo plano, mas o Android pode encerrar o processo em aparelhos com economia de bateria agressiva. Libere o WatchVerse nas configurações de bateria.

O espectro de áudio não aparece

  • Esse recurso depende de permissão de gravação de áudio, que o APK atual não declara. A rádio funciona sem o espectro.

Player de filmes e séries

Tela preta ou “link inválido”

  • O provedor pode ter bloqueado incorporação ou saído do ar.
  • Volte aos detalhes e escolha outro provedor.
  • Teste outro título para confirmar se o problema é do provedor.

O vídeo não retoma de onde parei

  • O progresso é salvo a cada 15 segundos e ao sair do player. Se o app foi encerrado à força, o último trecho pode ser perdido.
  • A retomada só ocorre quando a diferença é maior que 20 segundos.

O player abre em paisagem e não volta

  • Use o botão de rotação no canto superior direito.
  • Saia do player e abra novamente.

Notícias e futebol

Notícias vazias

  • Troque o país.
  • Puxe para atualizar.
  • O Worker atualiza um país a cada 20 minutos; pode haver atraso.
  • Se a fonte não tiver artigos válidos no dia, a lista pode ficar vazia.

Classificação ou placar desatualizado

  • Use o botão de atualizar.
  • O cache é de cerca de 5 minutos.
  • A fonte pode estar lenta; o app mostra dados antigos com aviso.

Mangás e jogos

Mangá sem capítulos

  • Troque o filtro de idioma para Todos.
  • Nem todo título tem tradução em português ou inglês.
  • A MangaDex pode estar instável.

Páginas não carregam

  • Teste outra rede.
  • O leitor pré-carrega apenas as próximas páginas; role com calma.
  • Se o capítulo estiver quebrado na fonte, escolha outro.

Jogo sem trailer ou screenshots

  • O enriquecimento com a Steam é opcional e depende do jogo.
  • Nem todo título tem mídia disponível.

Notificações

Não recebo notificações com o app fechado

  • Comportamento esperado nesta versão: o Android não registra token de push. As notificações são in-app e aparecem quando o app consulta o Firebase.

O sino não aparece

  • Ele só aparece para contas com acesso ativo e sessão desbloqueada.
  • Se não houver mensagens não lidas, o sino pode ficar oculto.

Ajuda e site

A Central de Ajuda não abre no app

  • Use Tentar novamente.
  • Use Abrir no navegador.
  • Confirme se https://watchverse.fun/documentacao abre no navegador.
  • O app exige HTTPS; redes que bloqueiam o domínio impedem a abertura.

Desempenho, dados e bateria

  • Limpe o cache do app nas configurações do Android se o armazenamento crescer.
  • Use Wi-Fi para catálogo, trailers e canais.
  • A reprodução em segundo plano consome bateria; feche o player quando não estiver usando.
  • Em aparelhos com pouca memória, o Android pode encerrar o app ao alternar entre tarefas.

Como pedir suporte

Use https://watchverse.fun/contato.html e informe:

  • e-mail da conta (sem enviar senha ou código);
  • modelo do aparelho e versão do Android;
  • versão do app (Perfil ou tela inicial);
  • o que você tentou fazer;
  • a mensagem de erro exata;
  • se possível, um print da tela.

Nunca envie código de verificação, token, senha ou dados de cartão.

↑ Voltar ao início

Desenvolvedor

Arquitetura

Visão geral

O WatchVerse é um aplicativo Expo / React Native para Android, com um Worker Cloudflare como backend. O app não hospeda mídia: ele consome catálogos públicos e abre players de terceiros.

CamadaTecnologia
AppExpo SDK 57, React Native 0.86.3, React 19.2.3, TypeScript
NavegaçãoReact Navigation 7 (stack + bottom tabs)
Estado globalReact Context (AuthContext, HomeBootstrapContext, RadioPlaybackContext)
Persistência localAsyncStorage e SecureStore
AutenticaçãoFirebase Authentication + Google Sign-In
Banco em tempo realFirebase Realtime Database
BackendCloudflare Worker (TypeScript) + D1 + R2 + Workers AI
PagamentoStripe Checkout + webhook no Worker
Crash/erroSentry React Native
BuildEAS Build / Gradle (assembleRelease)

Estrutura de pastas

wv/
├── App.tsx                  # raiz, gate de segurança, navegação autenticada
├── index.ts                 # entry point do Expo
├── src/
│   ├── components/          # UI reutilizável (banner, notificações, biometria…)
│   ├── config/              # Config, NewsConfig, FootballConfig, GamesConfig, MangaLanguageConfig
│   ├── context/             # AuthContext, HomeBootstrapContext, RadioPlaybackContext
│   ├── data/                # coleções curadas (Sci-Fi Top 100, ranked collections)
│   ├── hooks/               # useRadioPlayer, useNetworkConnectivity, useRefresh
│   ├── localization/        # ptBR, enUS, dicionários completos, localeStore
│   ├── navigation/          # MainTabNavigator, navigationRef
│   ├── screens/             # 34 telas
│   ├── security/            # AppSecurityService, root/emulador/assinatura
│   ├── services/            # 34 serviços de domínio e infraestrutura
│   ├── theme/               # Theme (cores, espaçamentos)
│   ├── types/               # tipos de API, IPTV, rádio, navegação, playback
│   └── utils/               # safeUrl, mangaLabels e utilitários
├── android/                 # projeto nativo gerado (manifest, gradle)
├── docs/                    # esta documentação (fonte única)
├── quality-gate/            # verificações de qualidade e segurança
├── scripts/                 # check-translations, generate-icons
└── __tests__/               # testes Jest

Inicialização

O fluxo real de abertura é:

  1. index.ts registra o componente raiz.
  2. App executa as verificações de segurança (AppSecurityService) com timeout de 15 s.
  3. Enquanto verifica, mostra a splash/indicador.
  4. Se o aparelho for bloqueado (root, emulador, assinatura divergente em produção), abre SecurityBlockedScreen.
  5. Se liberado, monta AuthProvider, HomeBootstrapProvider e RadioPlaybackProvider.
  6. RootNavigator decide entre Login, VerifyCodeScreen, CheckoutScreen ou o app autenticado.
  7. BiometricGate protege a sessão quando a biometria está ativa.
  8. AuthenticatedNavigator monta o stack principal e a tab bar.

Há um watchdog de inicialização de 20 s e um timeout de 15 s para o carregamento da autenticação, para evitar tela travada em redes ruins.

Navegação

O stack raiz (App.tsx) contém:

  • Main — tab navigator;
  • Details, Player, LivePlayer;
  • Checkout;
  • Help — Central de Ajuda em WebView;
  • MangaDetails, MangaReader;
  • GameDetails, GameMedia;
  • HomeCollection — listas “Ver tudo” (Sci-Fi Top 100 etc.);
  • PerformanceTests e QualityGate — apenas em desenvolvimento.

As cinco abas (MainTabNavigator.tsx) têm stacks próprios:

AbaStack
InícioHomeFeed, Manga, Games, LiveTv, Radio, RadioPlayer, News, NewsArticle, Football
ConteúdoContentHome, Movies, Series, Anime, Manga, Games
Ao VivoLiveHome, LiveTv, Radio, RadioPlayer, News, NewsArticle, Football
+MoreHome, Search, Favorites
Perfiltela única ProfileScreen

A duplicação de telas entre stacks é intencional: cada aba mantém seu próprio histórico. navigationRef permite navegar fora de componentes (por exemplo, ao tocar em uma notificação).

Contextos

AuthContext

Concentra o estado de autenticação e acesso:

  • usuário Firebase e estado de inicialização;
  • status de acesso (ACTIVE, EXPIRED, NONE, DEVICE_MISMATCH, OTP_REQUIRED, UNKNOWN, ERROR);
  • refreshAccess() e logout();
  • desbloqueio por biometria (sessionUnlocked);
  • registro do aparelho e sincronização de dados.

HomeBootstrapContext

Carrega em paralelo os dados da Home (tendências, populares, animes, etc.) para reduzir espera e evitar requisições repetidas. Expõe estado de carregamento e erro por bloco.

RadioPlaybackContext

Mantém o player de rádio vivo entre telas:

  • estação atual e status de reprodução;
  • reprodução em segundo plano e controles de tela de bloqueio;
  • reconexão automática;
  • espectro de áudio (quando permitido).

Serviços

Os serviços são organizados por domínio. Os principais:

ServiçoResponsabilidade
AuthService / GoogleAuthServiceLogin Google, logout, perfil
AccessServiceStatus da licença, OTP, checkout, sessão
SecureApiClientRequisições autenticadas ao Worker
TmdbServiceCatálogo de filmes, séries e animes
ProviderServiceProvedores de player e montagem de embed
IptvService / WorkerIptvService / LiveTvHealthServiceCanais, cache, saúde e modo Worker
RadioServiceEstações via Worker
NewsServiceNotícias e artigos
FootballServiceCompetições, tabelas e partidas
MangaDexService / MangaProgressServiceCatálogo, capítulos e progresso
GamesServiceCatálogo RAWG e detalhes
FavoritesServiceFavoritos locais e sincronizados
PlaybackProgressServiceProgresso de reprodução
NotificationsServiceMensagens in-app e leitura
BannerHtmlService / AdTrackingServiceBanner e eventos de anúncio
DeviceTrackingServiceRegistro e atualização do aparelho
NetworkServiceConectividade e tratamento de offline
PersistentCacheCache com TTL em AsyncStorage
StorageServiceChaves e leitura/gravação segura

Armazenamento

AsyncStorage

Guarda dados não sensíveis e caches:

  • favoritos locais;
  • progresso de reprodução e de mangá;
  • preferências da Home;
  • cache de catálogo;
  • avatar escolhido;
  • estado de leitura das notificações;
  • cache do banner.

SecureStore

Guarda dados sensíveis:

  • token de sessão do Worker;
  • preferência de biometria;
  • estado de licença em cache;
  • idioma.

O app usa allowBackup=false, então esses dados não entram em backup do Android.

Localização

  • src/localization/ptBR.ts e enUS.ts são os dicionários base.
  • ptBR.full.ts e enUS.full.ts estendem os dicionários com chaves adicionais.
  • LanguageContext expõe useT() e o idioma atual.
  • localeStore persiste a escolha e informa o locale ao TMDb.
  • O script npm run check:translations valida paridade de chaves.

Tema e layout

Theme centraliza cores, espaçamentos e tipografia. O app é dark-only, com vermelho #E50914 como destaque. As telas usam SafeAreaView, grades responsivas e ajustes para tablet/DeX. A orientação padrão é livre (orientation: default), com players em paisagem imersiva.

Segurança estrutural

  • AppSecurityService bloqueia root, emulador, debug e assinatura divergente em produção.
  • expo-screen-capture impede captura de tela.
  • network_security_config bloqueia cleartext.
  • WebViews validam HTTPS e hosts permitidos.
  • O Worker valida Firebase ID token, e-mail Gmail verificado, entitlement ativo e deviceId.

Detalhes em Modelo de segurança.

↑ Voltar ao início

Desenvolvedor

Ambiente e build

Requisitos

FerramentaVersão/comentário
Node.js20 LTS ou superior (recomendado)
npm10 ou superior
JDK17 (exigido pelo Android Gradle Plugin atual)
Android SDKAPI 36, build-tools compatíveis
Gradlevia wrapper do projeto
Conta Expo/EASnecessária para build na nuvem
Wranglerpara publicar o Worker

O projeto usa expo@^57, react-native@0.86.3, minSdk 29 e targetSdk 36.

Instalação

cd wv
npm ci

O postinstall executa patch-package, aplicando os patches em patches/. Não remova essa etapa.

Variáveis de ambiente

O app lê variáveis EXPO_PUBLIC_* em tempo de build. Nunca comite valores reais. As chaves esperadas são:

VariávelUso
EXPO_PUBLIC_FIREBASE_API_KEYFirebase
EXPO_PUBLIC_FIREBASE_AUTH_DOMAINFirebase Auth
EXPO_PUBLIC_FIREBASE_DATABASE_URLRealtime Database
EXPO_PUBLIC_FIREBASE_PROJECT_IDFirebase
EXPO_PUBLIC_FIREBASE_STORAGE_BUCKETStorage (avatares)
EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_IDFirebase
EXPO_PUBLIC_FIREBASE_APP_IDFirebase
EXPO_PUBLIC_FIREBASE_MEASUREMENT_IDAnalytics (opcional)
EXPO_PUBLIC_WORKER_ORIGINOrigem do Worker (padrão: https://ad-server-worker.gabrieldossantoselizeu3.workers.dev)
EXPO_PUBLIC_ANDROID_SIGNATURE_SHA256SHA-256 do certificado esperado em produção
EXPO_PUBLIC_USE_WORKER_IPTV1 ativa o catálogo IPTV via Worker
EXPO_PUBLIC_ENABLE_LICENSE_GATELiga/desliga o gate de licença
EXPO_PUBLIC_PURCHASE_URLURL alternativa de compra (quando usada)
EXPO_PUBLIC_IMAGE_BASE_URLBase de imagens (quando configurada)
EXPO_PUBLIC_QUALITY_GATE1 habilita a tela de quality gate em dev
EXPO_PUBLIC_QUALITY_GATE_STRESSmodo de estresse do quality gate
EXPO_PUBLIC_PERFORMANCE_TESTS1 habilita testes de performance em dev
EXPO_PUBLIC_PERF_STRESSmodo de estresse de performance
EXPO_PUBLIC_QG_FORCE_OFFLINEforça cenário offline no quality gate

Para desenvolvimento local, crie .env a partir do seu cofre de segredos. O arquivo .env não deve ser versionado.

Credenciais nativas

  • google-services.json — Android/Firebase.
  • GoogleService-Info.plist — iOS (o app não é distribuído para iOS nesta versão).
  • @c_4_rl0s__WatchVerse.jks — keystore de release. Não versione a senha.

Scripts

ComandoO que faz
npm startExpo dev server
npm run androidbuild e execução no Android
npm run iosbuild e execução no iOS
npm run webExpo web (não é o alvo de produção)
npm testJest
npm run lintESLint
npm run check:translationsvalida chaves de tradução
npm run quality-checktraduções + quality gate
npm run docs:buildgera a Central de Ajuda publicada (pt + en)
npm run docs:checkverifica se as páginas geradas estão atualizadas
npm run build:android:apk:qualityquality check + EAS productionApk
npm run obfuscateofuscação opcional de dist

Build do APK

EAS (recomendado)

npm run build:android:apk:quality

O perfil productionApk usa:

  • autoIncrement: true (incrementa versionCode no servidor EAS);
  • :app:assembleRelease;
  • apenas arm64-v8a por padrão;
  • appVersionSource: remote.

Gradle local

cd android
./gradlew :app:assembleRelease

O APK sai em android/app/build/outputs/apk/release/.

Assinatura

O build atual usa v3 only (AGP 8.12). Como minSdk é 29, isso é aceito pelos aparelhos suportados. Se precisar de compatibilidade com verificadores antigos, pós-assine com apksigner incluindo v2:

apksigner sign --ks <keystore> --v1-signing-enabled false --v2-signing-enabled true --v3-signing-enabled true app-release.apk

A assinatura precisa corresponder ao SHA-256 configurado em EXPO_PUBLIC_ANDROID_SIGNATURE_SHA256 (padrão 19d85449…6f7f). Builds com assinatura diferente são bloqueados em produção.

Testes

npm test
npm test -- newsService.test.ts

O projeto usa Jest com jest.setup.js e mocks em __mocks__/. Há testes de serviços, segurança, biometria, player e componentes.

Estado conhecido na versão 4.4.13: a suíte principal passa, mas existem falhas pré-existentes em biometricGate.test.tsx, radioService.test.ts e iptvMemorySafety.test.ts. Elas não são causadas pela documentação nem pelo botão Ajuda.

Quality gate

quality-gate/quality-check.mjs e securityChecks.mjs verificam:

  • paridade de traduções;
  • configuração de segurança do Android;
  • permissões declaradas;
  • presença de segredos em arquivos versionados;
  • alvos e configurações de build.

Rode npm run quality-check antes de publicar.

Publicação do site

O site fica em quase_dev_org/watchverse_webpage e é publicado pelo Netlify a partir do repositório watchverse_website. O APK é armazenado com Git LFS em apk/.

cd quase_dev_org/watchverse_webpage
git add .
git commit -m "docs: ..."
git push origin main

A documentação publicada é gerada a partir de wv/docs (português) e wv/docs/en (inglês) pelo script wv/scripts/build-docs.mjs (ver README). Não edite o HTML gerado à mão.

Checklist de release

  1. Atualizar version e versionCode em app.json.
  2. Rodar npm run quality-check e npm test.
  3. Gerar o APK e calcular o SHA-256.
  4. Publicar o APK e o .sha256 no site.
  5. Gerar a documentação (node scripts/build-docs.mjs).
  6. Validar a página de documentação em desktop e mobile.
  7. Testar o botão Ajuda no APK.
  8. Commitar e publicar o site.

↑ Voltar ao início

Desenvolvedor

Integrações

Mapa de integrações

IntegraçãoAcessoAutenticaçãoUsada para
Firebase AuthenticationSDK no appGoogle ID tokenLogin Gmail
Firebase Realtime DatabaseSDK no appRegras do FirebasePerfil, favoritos, progresso, mensagens, banner, acesso
Firebase StorageSDK no appRegras do FirebaseAvatar do usuário
Worker CloudflareHTTPSFirebase ID token + sessão + deviceCatálogo e dados
TMDbWorkerChave no WorkerFilmes, séries, animes
MangaDexapp direto / proxy no siteNenhumaMangás
RAWGWorkerChave no WorkerCatálogo de jogos
Steam StoreWorkerNenhumaDescrição e trailers
football-data.org v4WorkerToken no WorkerFutebol
freenewsapi.aiWorkerChave opcionalNotícias
Workers AIWorkerBindingResumos de notícias
Radio BrowserWorkerNenhumaRádio
iptv-orgapp diretoNenhumaListas de TV
StripeWorkerChave secreta + webhookPagamento
SentrySDK no appDSNErros e crashes
Expo PushWorkerToken ExpoFan-out (sem registro no Android atual)

Nenhuma chave é distribuída no APK, exceto as variáveis EXPO_PUBLIC_FIREBASE_* (que são configuração pública do Firebase) e o SHA-256 esperado da assinatura. Chaves de TMDb, RAWG, futebol, notícias, Stripe e Firebase Admin ficam apenas no Worker.

Firebase

Authentication

  • Provedor: Google.
  • O app usa @react-native-google-signin/google-signin para obter o ID token e o Firebase para criar a sessão.
  • O Worker valida o ID token com a chave pública do Google e exige email_verified e domínio Gmail.

Realtime Database

Caminhos observados no código do app:

CaminhoConteúdo
users/{uid}Perfil (nome, avatar, datas)
users/{uid}/favoritesFilmes e séries favoritos
users/{uid}/favorites_channelsCanais de TV favoritos
users/{uid}/playback_progressProgresso de reprodução
messagesNotificações in-app
userMeta/{uid}/pushTokensTokens de push (não usados no Android atual)
streaming_providersProvedores de player
ads/bannerHtmlHTML do banner

O Worker também usa /access/{uid}, /entitlements/…, /payments/{sessionId}, /otp/{uid} e /devices/… para licença, OTP e aparelhos.

Storage

Usado para avatares enviados pelo usuário. A foto é recortada antes do upload.

TMDb

  • Base: https://api.themoviedb.org/3, sempre por meio do Worker.
  • O app envia language (pt-BR/en-US) e region (BR/US).
  • O Worker faz cache de CDN: 10 minutos para listas e 24 horas para detalhes.
  • O Worker também aquece o cache das listas principais em pt-BR/BR.

Rotas disponíveis em API do Worker.

MangaDex

  • Base: https://api.mangadex.org.
  • O app consulta direto (não passa pelo Worker).
  • Filtros: contentRating[]=safe, includes[]=cover_art, includes[]=author, idioma de tradução.
  • 24 títulos por página.
  • O site usa um proxy Netlify (/api/mangadex/*) porque a MangaDex não envia CORS.

RAWG e Steam

  • Base RAWG: https://api.rawg.io/api.
  • O Worker aplica limite de requisições e cache em D1.
  • Ordenações: populares (-added), recentes (últimos 120 dias) e futuros (próximos 365 dias).
  • 30 jogos por página (padrão), com máximo configurável no Worker.
  • Quando ENABLE_STEAM_ENRICHMENT=1, o Worker busca descrição e trailers na loja da Steam.
  • O idioma do detalhe é pt ou en, conforme language/Accept-Language.

Notícias

  • Fonte: https://freenewsapi.ai/v1/search.
  • O Worker consulta 50 resultados por país, janela de 48 horas, e mantém apenas o dia local do país.
  • Resumos são gerados com Workers AI e limitados a 3.000 caracteres.
  • A mídia só é aceita com licença reconhecida (CC BY, CC BY-SA, CC0, domínio público).
  • Cron a cada 20 minutos faz o rodízio de países; limpeza de dias anteriores ocorre de hora em hora.
  • O app pede 20 artigos por página.

Futebol

  • Base: https://api.football-data.org/v4.
  • O Worker guarda tabela, resultados e próximos jogos em D1 por cerca de 5 minutos.
  • ?refresh=1 força atualização (sujeita ao limite do provedor).
  • Competições: br, it, de, es, gb, fr, pt, nl.

Rádio

  • Fonte: https://de1.api.radio-browser.info/json/stations/search.
  • O Worker limita a 100 estações, oculta estações quebradas e ordena por cliques.
  • A rota exige acesso pago.

IPTV

Dois modos:

  1. Padrão (app direto): listas iptv-org.github.io por país, HTTPS-only, blocklist pública, cache de 24 h e verificação de saúde de 12 h.
  2. Worker (opcional): EXPO_PUBLIC_USE_WORKER_IPTV=1 ativa /api/iptv/catalog, /access e /stream com URLs assinadas. Desligado por padrão.

Stripe

  • Checkout hospedado, preço de US$ 1 (100 centavos) e 30 dias.
  • POST /checkout/session cria a sessão; o app abre a URL em WebView.
  • POST /stripe/webhook valida a assinatura, confere valor/moeda e grava o entitlement.
  • Não há assinatura recorrente.

Sentry

  • Inicializado no app para capturar erros e crashes.
  • Não envia conteúdo de vídeo, senhas ou tokens.
  • O DSN é configuração de build e não deve ser tratado como segredo crítico, mas também não precisa ser divulgado na documentação do usuário.

Push

  • O Worker possui fan-out via Expo Push.
  • No Android atual, o app não registra token (registerForPushNotificationsAsync retorna null), e POST_NOTIFICATIONS está bloqueada.
  • As notificações visíveis são in-app, lidas do Realtime Database.

Limites e falhas

  • Todas as APIs de terceiros podem ficar indisponíveis; o app trata erro e cache quando possível.
  • O Worker aplica timeout e limite de tamanho nas respostas.
  • Chaves nunca são impressas em logs; erros de RAWG e futebol são registrados sem a URL com credencial.

↑ Voltar ao início

Referência

API do Worker

Base

https://ad-server-worker.gabrieldossantoselizeu3.workers.dev

O app usa EXPO_PUBLIC_WORKER_ORIGIN para apontar para outra origem. Todas as chamadas usam HTTPS.

Autenticação

Rotas públicas

Não exigem token:

  • GET / e GET /health
  • GET /ad/next, GET /video/:id, GET /imagem/:id
  • POST /track
  • POST /auth/otp/send, POST /auth/otp/verify, POST /auth/session/logout
  • POST /checkout/session, POST /stripe/webhook, GET /access/status
  • GET /checkout/success, GET /checkout/cancel
  • POST /api/devices/register
  • POST /api/notifications/clicks

Rotas de conteúdo pago

Exigem, em conjunto:

  1. Authorization: Bearer <Firebase ID token> válido;
  2. e-mail Gmail verificado;
  3. entitlement ativo (expiresAt no futuro);
  4. x-device-id com 8 a 128 caracteres (A-Z, a-z, 0-9, _, -) igual ao aparelho vinculado.

Falhas retornam:

StatuserrorSignificado
401unauthorizedToken ausente/inválido
403verified_gmail_requiredConta não é Gmail verificado
400device_requiredx-device-id ausente/inválido
403access_requiredSem entitlement ativo
403device_mismatchAparelho diferente do vinculado
503access_check_unavailableFalha ao consultar o Firebase

Rotas administrativas

Exigem x-admin-token (ou x-dashboard-token nas rotas de chaves):

  • POST /api/admin/access/revoke
  • POST /api/notifications/fanout/run
  • POST /api/activation-keys
  • GET /api/activation-keys/list
  • GET /api/activation-keys/export
  • POST /api/activation-keys/revoke

Ads e mídia

GET /ad/next

Retorna o próximo anúncio.

QueryEfeito
rn=1Retorna HTML pronto para WebView

Resposta JSON:

{
  "success": true,
  "ad": {
    "id": "…",
    "type": "video",
    "clickUrl": "https://…",
    "src": "/video/…",
    "allowSkipAfter": 5,
    "muteByDefault": true
  }
}

Sem anúncio: { "success": true, "ad": null }.

GET /video/:id

Serve ads/{id}/video.mp4 do R2, com suporte a Range (206).

GET /imagem/:id

Serve ads/{id}/image.{jpg,jpeg,png,webp} do R2, com cache de 1 dia.

POST /track

Registra eventos de anúncio. Limite: 60 requisições por minuto por IP.

Eventos aceitos: ad_impression, ad_click, ad_complete, banner_impression, banner_click, banner_close.

Campos comuns: event, adId, campaignId, placement, clickUrl, ts, installId, appVersion, watchedMs.

Autenticação e sessão

POST /auth/otp/send

Envia um código de 8 dígitos para o e-mail da conta. Limite de 10 requisições por minuto por IP.

Regras: validade de 5 minutos, reenvio após 60 segundos, máximo de 5 códigos por hora, 3 tentativas por código.

POST /auth/otp/verify

Valida o código e devolve um sessionToken de 64 caracteres hexadecimais. O token é guardado no SecureStore.

POST /auth/session/logout

Invalida o OTP e a sessão do usuário autenticado.

Checkout e acesso

POST /checkout/session

Cria uma sessão Stripe. Requer Firebase ID token e Gmail verificado.

Resposta:

{ "ok": true, "sessionId": "cs_…", "url": "https://checkout.stripe.com/…" }

POST /stripe/webhook

Recebe eventos do Stripe. Valida a assinatura, aceita checkout.session.completed e checkout.session.async_payment_succeeded, confere valor (100 centavos) e moeda (usd) e grava o entitlement por 30 dias. É idempotente por session.id.

GET /access/status

Requer Firebase ID token, Gmail verificado e deviceId (query ou header). Retorna status, expiração, dias restantes e chave de ativação quando houver.

Status: ACTIVE, EXPIRED, NONE, DEVICE_MISMATCH, OTP_REQUIRED.

GET /checkout/success e GET /checkout/cancel

Páginas HTML de retorno do Stripe.

Dispositivos

POST /api/devices/register

Limite: 20 por minuto por IP.

{
  "deviceId": "…",
  "deviceInfo": {
    "os": "android",
    "osVersion": "14",
    "brand": "samsung",
    "model": "SM-…",
    "appVersion": "4.4.13"
  }
}

Retorna isNew, firstSeenAt, lastSeenAt e accessCount.

Notificações

POST /api/notifications/clicks

Limite: 60 por minuto por IP.

Campos: source (push ou in_app), action (route, tmdb, action_url, dismissed), notificationId, campaignId, actionTarget, route, routeParams, tmdbId, mediaType.

POST /api/notifications/fanout/run

Executa o fan-out manualmente. Exige x-admin-token. O cron também executa o fan-out a cada minuto.

IPTV

Todas exigem acesso pago.

RotaDescrição
GET /api/iptv/catalog/:countryLista de canais do país
GET /api/iptv/access/:countryURLs de acesso/assinatura
GET /api/iptv/stream/:idRedireciona (302) para o stream autorizado

País com duas letras minúsculas (br, us, es, …).

Rádio

GET /api/radio/stations/:country

País com duas letras (br, us, …) ou all. Retorna até 100 estações, sem estações quebradas, ordenadas por cliques. Exige acesso pago.

Notícias

GET /api/news/:country

ParâmetroPadrãoLimite
page11–100
limit201–50
format—summary apenas no artigo

Países: br, us, gb, fr, de, es, it, pt, jp, cn.

Resposta inclui country, page, limit, total, hasMore, updatedAt, stale, refreshError e articles[].

GET /api/news/:country/:articleId?format=summary

Retorna o artigo completo (resumo de até 3.000 caracteres) com licenseName e licenseUrl.

Futebol

GET /api/football/:country

Países: br, it, de, es, gb, fr, pt, nl.

Query refresh=1 força atualização. Resposta inclui competição, temporada, classificação, resultados e próximos jogos, além de source e cached.

Jogos

RotaParâmetros
GET /api/games/popularpage, pageSize, sort (popular, recent, upcoming), genre, language
GET /api/games/searchq (obrigatório), page, pageSize, genre, language
GET /api/games/genres—
GET /api/games/:idlanguage

pageSize é limitado pelo Worker; o app usa 30. Erros: invalid_page, invalid_page_size, invalid_sort, invalid_genre, invalid_query, games_upstream_failed.

TMDb

Todas exigem acesso pago. page é normalizado; language padrão pt-BR; region padrão BR.

Busca

RotaQuery obrigatória
GET /api/search/moviequery (ou q)
GET /api/search/tvquery (ou q)
GET /api/search/multiquery (ou q)

Listas

RotaObservação
GET /api/movies/populartambém aceita /api/movie/popular
GET /api/movie/upcomingestreias
GET /api/tv/popularséries populares
GET /api/movies/trendingtrending semanal de filmes
GET /api/tv/trendingtrending semanal de séries
GET /api/trending/:mediaType/:timeWindowmovie/tv/all, day/week
GET /api/tv/airing_todayno ar hoje

Discover

GET /api/discover/movie:

page, region, with_genres, without_genres, primary_release_date.gte, primary_release_date.lte, sort_by, include_adult, language.

GET /api/discover/tv:

page, with_genres, with_original_language, sort_by, include_adult, language.

Detalhes

RotaDescrição
GET /api/movie/:idDetalhes do filme
GET /api/movie/:id/videosTrailers (fallback en-US)
GET /api/movie/:id/creditsElenco
GET /api/tv/:idDetalhes da série
GET /api/tv/:id/season/:nTemporada
GET /api/tv/:id/creditsElenco
GET /api/person/:idPessoa (fallback de biografia em en-US)
GET /api/person/:id/combined_creditsCréditos
GET /api/person/:id/external_idsIDs externos

Rotas descontinuadas

/api/license/* e as rotas públicas de chave de ativação retornam 410 Gone:

  • /api/activation-keys/claim
  • /api/activation-keys/validate-and-claim
  • /api/activation-keys/validate

O fluxo atual é Stripe + entitlement.

Erros e CORS

  • Erros seguem { "ok": false, "error": "código" } ou { "error": "mensagem" }.
  • ALLOWED_ORIGINS define as origens permitidas; vazio usa a política padrão do Worker.
  • OPTIONS retorna 204 com cabeçalhos CORS.
  • Limites por IP usam os bindings de rate limit do Cloudflare.

Cron

wrangler.toml agenda * * * * * (a cada minuto). A cada execução:

  • fan-out de notificações;
  • a cada 20 minutos: aquecimento de notícias, backfill de resumos, poda do cache de jogos e aquecimento do TMDb;
  • a cada hora: limpeza de notícias de dias anteriores.

↑ Voltar ao início

Referência

Histórico de versões

4.4.13 — 03/11/2026

versionCode 19

  • Corrigida a exibição de capas em PNG, WebP e GIF no catálogo de mangás; antes apenas arquivos .jpg eram aceitos.
  • A lista de capítulos passou a seguir o total do feed da MangaDex (com teto de 10.000), em vez de parar em 2.000. Séries longas não perdem mais capítulos.
  • O site passou a usar um proxy próprio para a API e para as capas, com User-Agent de servidor; a seção de mangás voltou a carregar.
  • Corrigido o estouro horizontal das descrições de mangá com URLs longas no site.
  • APK publicado: watchverse_4.4.13.apk, 120.693.331 bytes.
  • SHA-256: e0bf63a1495a551505e5c3071c4118f5e58d08a34a63b7ecf67e42e753465b12.
  • Nenhuma mudança em autenticação, licenciamento, pagamentos, mídia ou backend.

4.4.12 — 02/11/2026

versionCode 18

  • Central de Ajuda publicada também em inglês, em https://watchverse.fun/documentation.
  • O botão Ajuda passou a abrir a edição do idioma do app: /documentacao para pt-BR e /documentation para en-US.
  • As duas páginas têm seletor de idioma e hreflang recíproco para SEO.
  • Nenhuma mudança em autenticação, licenciamento, pagamentos, mídia ou backend.

4.4.11 — 02/11/2026

versionCode 17

  • O item Ajuda do Perfil passou a abrir esta Central de Ajuda em WebView interna (https://watchverse.fun/documentacao?embed=1), com fallback de erro, botão de tentar novamente e opção de abrir no navegador.
  • A documentação passou a ser gerada a partir de docs/ (npm run docs:build) e publicada no site.
  • Nenhuma mudança em autenticação, licenciamento, pagamentos, mídia ou backend.

4.4.10 — 01/11/2026

versionCode 16

  • Corrigido o player de rádio aberto pelos Favoritos: a rota RadioPlayer agora é empilhada sobre LiveHome com initial: false. O botão voltar e o toque repetido na aba Ao Vivo retornam ao hub.
  • APK publicado: watchverse_4.4.10.apk, 120.680.187 bytes.
  • SHA-256: c6875d1946d86d48d4ea7b08991dfcc426917c18dab7f6850e2160ec2b040b8c.
  • Assinatura v3 válida; certificado 19d85449…6f7f.

4.4.9 — 01/11/2026

versionCode 15

  • Assinatura alterada para v1 desligada, v2 e v3 habilitadas no DSL; o AGP gerou APK v3-only, aceito por minSdk 29.
  • Removidos componentes exportados sem uso:
    • com.google.android.gms.auth.api.signin.RevocationBoundService
    • androidx.profileinstaller.ProfileInstallReceiver
  • Mantido FirebaseInstanceIdReceiver (FCM).
  • Documento de supressões justificadas do MobSF criado.
  • SHA-256: 2bf8f9fbc1b3ab7ab6e63dbd6d7837ed8be40a1b42e97c25eaed01dcf2d5b55d.

4.4.8 — 01/11/2026

versionCode 14

  • NewsService passou a aceitar resumos de até 3.000 caracteres, alinhado ao contrato do Worker (MAX_ARTICLE_BODY_CHARS).
  • Teste de regressão adicionado; newsService.test.ts 17/17.
  • Notícias restauradas e validadas (GET /api/news/br 200, 15 artigos).

4.4.7 — 01/11/2026

  • @expo/dom-webview excluído do autolinking por ser código morto.
  • react-native-webview mantido com flags perigosas desativadas e validação de HTTPS/host.
  • Alertas medium do MobSF documentados.
  • MD5 e SHA-1 remanescentes mantidos por uso não criptográfico ou exigido por especificação.

4.4.6 — 30/10/2026

  • Cleartext HTTP eliminado do build de release; localhost e 10.0.2.2 movidos para a configuração de debug.
  • Canais IPTV sem HTTPS passaram a usar espelhos HTTPS ou foram descartados.
  • Permissões de armazenamento e mídia removidas do manifesto.
  • allowBackup=false e regras de backup restritas.
  • Whitelist do banner HTML restringida.
  • src do iframe do player escapado.
  • Dados locais do usuário limpos no logout.
  • Rate limit por IP no fluxo de OTP.

4.4.5 — 30/10/2026

  • Permissão CAMERA removida (não era usada).
  • AES-CBC com PKCS5/PKCS7 em androidx.biometric mantido: uso apenas de criptografia, sem decifração de entrada do atacante.
  • minSdk elevado para 29 (Android 10).

4.4.3 — 30/10/2026

  • minSdk 24 → 29.
  • WebView com depuração remota desativada em release.

Documentação — 02/11/2026

  • Criada a Central de Ajuda em Markdown como fonte única.
  • Publicação em https://watchverse.fun/documentacao, com edição em inglês em https://watchverse.fun/documentation.
  • Botão Ajuda do Perfil passou a abrir a documentação em WebView, com fallback de erro.
  • Adicionados capítulos de usuário, desenvolvedor, API, segurança e changelog.
  • Documento interno de recomendações de segurança separado e não publicado.

↑ Voltar ao início

Segurança

Modelo de segurança

Princípios

O WatchVerse adota quatro princípios:

  1. O servidor decide o acesso. O app não é a autoridade final sobre licença ou aparelho; o Worker valida token, e-mail, entitlement e deviceId.
  2. Privilégio mínimo. O manifesto declara apenas as permissões necessárias (internet, mídia em segundo plano, biometria, vibração).
  3. Transporte seguro. Todo tráfego é HTTPS; cleartext é bloqueado no release.
  4. Superfície pequena. Componentes exportados sem uso foram removidos; WebViews validam hosts; não há SDK de anúncio de terceiros.

Camadas

1. Integridade do aparelho e do app

Em build de produção (!__DEV__ e fora do Expo Go), AppSecurityService verifica:

VerificaçãoEfeito
Ambiente de desenvolvimento / Expo GoBloqueia
EmuladorBloqueia
Root (RootBeer + detecção própria)Bloqueia
Assinatura AndroidCompara com o SHA-256 esperado; bloqueia se divergir
Runtime de updatesVerifica consistência quando habilitado

O bloqueio mostra SecurityBlockedScreen com o motivo. As verificações são executadas no início e têm timeout para não travar o app.

Limite: nenhuma verificação local é invulnerável a um atacante com controle total do aparelho. Elas elevam o custo e cobrem o usuário comum, mas a decisão de acesso continua no servidor.

2. Autenticação

  • Login exclusivamente Google/Gmail.
  • O Worker valida o ID token do Firebase contra as chaves públicas do Google.
  • Exige email_verified e domínio Gmail.
  • A sessão do Worker usa um token de 32 bytes (64 hex) guardado no SecureStore.
  • O código OTP tem 8 dígitos, validade de 5 minutos, 3 tentativas, reenvio de 60 segundos e limite de 5 por hora.
  • OTP e token de sessão são armazenados como hash; a comparação é de tempo constante.

3. Autorização e licença

  • O entitlement é gravado no Firebase pelo webhook do Stripe, não pelo app.
  • O Worker confere valor (100 centavos), moeda (usd) e identidade da sessão.
  • O webhook valida a assinatura do Stripe e é idempotente por session.id.
  • A conta é vinculada a um aparelho via deviceId; outro aparelho recebe DEVICE_MISMATCH.
  • Rotas de conteúdo pago exigem entitlement ativo e o mesmo deviceId.

4. Transporte

  • network_security_config.xml de release: cleartextTrafficPermitted="false", sem exceções.
  • O arquivo de debug tem configuração separada para localhost/10.0.2.2 e não entra no release.
  • Canais IPTV que só existem em HTTP usam espelhos HTTPS ou são descartados.
  • Requisições do Worker têm timeout e limite de tamanho de resposta.

5. Armazenamento

DadoOndeProteção
Token de sessãoSecureStoreKeystore do Android
Preferência de biometriaSecureStoreKeystore do Android
Licença em cacheSecureStoreKeystore do Android
IdiomaSecureStoreKeystore do Android
Favoritos, progresso, cachesAsyncStorageSandbox do app
BackupDesativadoallowBackup=false

Em aparelho sem root, outros aplicativos não acessam o sandbox. O logout limpa os dados locais do usuário.

6. Biometria

  • Usa BiometricPrompt com CryptoObject.
  • Requer biometria forte cadastrada.
  • Protege a sessão já autenticada; não substitui o login Google.
  • A chave fica no Keystore e o app só a usa para montar o CryptoObject.

O uso de AES-CBC/PKCS7 nessa biblioteca do AndroidX é apenas para criptografar com a chave do Keystore. Não há decifração de dados controlados pelo atacante, portanto não há oráculo de padding.

7. WebViews

WebViewConteúdoControles
Playeriframe do provedorHTTPS, whitelist de hosts, sem bridge, src escapado
CheckoutStripeURL fixa, HTTPS
BannerHTML do backendorigens restritas (about:blank, data:, blob:, HTTPS)
DocumentaçãoSite oficialHTTPS, host fixo, sem bridge

Configurações perigosas ficam desligadas por padrão na versão usada da biblioteca:

  • allowFileAccess=false
  • allowContentAccess=false
  • allowFileAccessFromFileURLs=false
  • allowUniversalAccessFromFileURLs=false
  • mixedContentMode=NEVER_ALLOW
  • depuração remota desligada em release

Links externos passam por validação: apenas http(s) absolutos; intent:, javascript:, file: e URLs relativas a host são recusados.

8. Captura de tela

expo-screen-capture impede captura e gravação da tela enquanto o app está em uso. Isso reduz vazamento visual de conteúdo, mas não impede fotos com outro aparelho.

9. Backend

  • Consultas ao D1 são parametrizadas.
  • Segredos ficam em bindings do Worker, nunca no APK.
  • Rate limit por IP em OTP, tracking, registro de dispositivo e cliques de notificação.
  • CORS configurável por ALLOWED_ORIGINS.
  • Logs não imprimem chaves; erros de provedores são registrados sem a URL com credencial.
  • Rotas antigas de chave de ativação retornam 410.

O que o app não faz

  • Não contorna DRM, geobloqueio ou login de provedores.
  • Não baixa conteúdo protegido.
  • Não coleta senha do Google (o fluxo é delegado ao Google).
  • Não armazena dados de cartão (o Stripe hospeda o checkout).
  • Não garante que o conteúdo de terceiros seja seguro ou esteja disponível.

Riscos residuais aceitos

RiscoSituaçãoMitigação
Root/emulador sofisticadoDetectores locais podem ser burladosServidor continua validando acesso
Provedores de vídeo externosPodem coletar dados e exibir anúncios própriosWebView sem bridge e com whitelist
Conteúdo de notícias de terceirosResumos automáticos podem errarLink para a fonte e crédito
Streams IPTV instáveisDisponibilidade variaSaúde do stream, fallback e cache
Captura por câmera externaFora do controle do appAviso na política
expo-dev-client presente no bundleSem launcher activity, não utilizável pelo usuárioPendência de higiene de dependências
Push Android ausenteSem token registradoNotificações in-app

Recomendações internas

Orientações operacionais, de hardening e de resposta a incidentes ficam em um documento interno mantido pela equipe, não publicado no site.

Reportar uma vulnerabilidade

Envie um e-mail pelo formulário em https://watchverse.fun/contato.html, descrevendo o problema e os passos para reproduzir. Não inclua dados de outras pessoas, tokens ou conteúdo de contas. O recebimento é confirmado e a correção é priorizada conforme o impacto.

↑ Voltar ao início