Skip to content

feat: Handlers dinâmicos, unificação de busca, metadados estendidos e otimizações do MeiliSearch - #81

Open
GuickerZ wants to merge 4 commits into
felipemarinho97:mainfrom
GuickerZ:main
Open

feat: Handlers dinâmicos, unificação de busca, metadados estendidos e otimizações do MeiliSearch#81
GuickerZ wants to merge 4 commits into
felipemarinho97:mainfrom
GuickerZ:main

Conversation

@GuickerZ

Copy link
Copy Markdown

Pull Request: Modernização de Arquitetura, Busca Paralela e Melhorias no MeiliSearch

Título: feat: Handlers dinâmicos, unificação de busca, metadados estendidos e otimizações do MeiliSearch

Descrição

Este PR traz uma série de melhorias arquiteturais e correções no motor do torrent-indexer. O foco principal é tornar o projeto mais independente de configurações manuais (hardcoded), melhorar o tempo de resposta em consultas múltiplas, e otimizar o uso de disco do banco de dados, mantendo 100% de compatibilidade reversa com clientes existentes (Jackett, Addons, etc).

Além das mudanças de infraestrutura, este PR também integra o bugfix do bludv discutido na comunidade e corrige a descoberta de metadados via UDP.


Mudanças e Justificativas

1. Registro Dinâmico de Indexadores

O que foi feito?
A lista de indexadores no endpoint raiz (/) e o mapeamento de rotas (/indexers/bludv, etc.) no main.go agora são gerados dinamicamente a partir de um mapa (GetAllHandlersMap).
Por que isso é necessário?
Antes, cada vez que um novo site (arquivo .go) era adicionado, era preciso modificar manualmente o main.go e a documentação na raiz. Agora a arquitetura é "plug-and-play": adicionou o arquivo, a rota sobe e a documentação atualiza sozinha.

2. Unificação da Rota de Busca (/search)

O que foi feito?
A rota separada POST /search/multi foi removida. O endpoint GET /search foi atualizado para suportar múltiplas buscas simultâneas tanto via GET ?q=a&q=b quanto via payload POST {"queries": ["a", "b"]}.
Por que isso é necessário?
A existência de duas rotas separadas gerava fragmentação na hora de integrar o MeiliSearch em clientes externos. Com a unificação, o comportamento do /search se equipara ao /indexers/all, devolvendo um Array unificado de resultados de forma padronizada.

3. Paralelismo com WaitGroups (/indexers/all)

O que foi feito?
A lógica que consulta múltiplos indexadores ao mesmo tempo (HandlerMultiIndexers) foi refatorada para utilizar goroutines com sync.WaitGroup. O endpoint também passou a tolerar falhas (se um site cair, ele retorna 200 OK com os resultados dos sites que funcionaram).
Por que isso é necessário?
Se o usuário consulta 5 indexadores e um deles sofre um "timeout" ou erro 500, a requisição inteira falhava. Além disso, a execução paralela reduz o tempo total de resposta de (Tempo A + Tempo B + Tempo C) para apenas o tempo do site mais lento da fila.

4. Otimização de Relevância e Armazenamento (MeiliSearch)

O que foi feito?
Adicionada a diretiva omitempty em campos opcionais (como imdb, size, quality) no schema.IndexedTorrent. Também foi criado um mapeamento automático de Sinônimos no startup (the = o, of = do) e inserido a rota /search/stats na documentação raiz.
Por que isso é necessário?
O MeiliSearch estava salvando strings vazias (""), o que inflava o uso de disco/RAM e quebrava as estatísticas do painel (ex: acusava milhares de torrents com imdb, sendo que estavam vazios). Já o mapeamento de sinônimos impede que o motor ignore artigos como stop-words, consertando buscas de títulos curtos como "The 100" ou "The Batman", que agora são correspondidos corretamente independente da linguagem do crawler.

5. Contexto Inteligente e Parser de Títulos

O que foi feito?
Foi criada a extração nativa do atributo Context. O scraper agora varre o HTML em torno do magnet link e extrai textos valiosos (como temporada, episódio, qualidade, e legendas) que costumam ficar grudados aos botões de download. Além disso, foi incluído um novo Post Processor (ParseTitleMetadata) que intercepta o título do post e via RegEx extrai qualidades nativas como 1080p, WEB-DL ou 4K caso o site não forneça essa tag de forma clara.
Por que isso é necessário?
O campo Context se torna uma mina de ouro de meta-dados ultraleves, garantindo que o usuário da API identifique de imediato se aquele Magnet pertence ao Episódio 01 ou 02, o que antigamente exigia regras complicadas para descobrir.

6. Extração Estendida (Opcional via ENV)

O que foi feito?
Agora os scrapers conseguem puxar dados profundos (como Resolução, Qualidade de Áudio/Vídeo, Gêneros, Duração e os Arquivos vindos do Magnet).
Por que isso é necessário?
Isso permite que UIs ricas consumam dados completos sem depender estritamente de APIs de terceiros. Porém, para proteger usuários de consumo excessivo de disco (Redis/MeiliSearch), isso foi desativado por padrão. Caso a pessoa não coloque ENABLE_EXTENDED_METADATA=true no .env, um processador passará a foice e limpará esses dados extras (mas mantendo o campo ultraleve Context), garantindo que o Torrent-Indexer original continue consumindo o mínimo de espaço possível.

7. Bugfixes da Comunidade

O que foi feito?

  • Incorporada a correção no parser do bludv reportada pelo membro .bazante.
  • Corrigida a porta 42069/udp no docker-compose.yml para a imagem do magnet-metadata-api.
    Por que isso é necessário?
    O tracker de DHT necessita do protocolo UDP para descobrir peers corretamente e recuperar os arquivos dos metadados. A falta dessa porta causava falhas silenciosas na resolução de magnet links.

Testes Realizados

  • Compatibilidade reversa mantida intacta com chamadas do Jackett.
  • Indexadores originais não apresentam quebra de estrutura HTML.
  • Verificado o comportamento do omitempty diretamente na engine local do MeiliSearch.

@GuickerZ

Copy link
Copy Markdown
Author

Opa Felipe! Só para constar, eu já coloquei esse PR em produção em um ambiente pesado e ele está rodando perfeitamente. Pode testar a resposta do JSON (ela esta hospedada em NY), a velocidade dos WaitGroups em /indexers/all e a unificação do /search diretamente na minha instância pública, usando exatamente o mesmo código deste PR:

Instância de Teste (API): http://guindex.duckdns.org:8090/ Teste do Multi-Search Unificado: http://guindex.duckdns.org:8090/search?q=Shutter%20Island&q=Ilha%20do%20Medo

(Nota: Essa instância de teste foi buildada com a ENV ENABLE_EXTENDED_METADATA=true para você ver os recursos novos como Quality, Genres e Context, e o parser inteligente de título extraindo o S00E00 ou resoluções).

Qualquer coisa, estou à disposição para ajustes!

…rch methods

- Default search limit set to 100 per query with hard cap
- Results sorted by Jaccard similarity (highest first)
- Implemented UpdateSearchableAttributes and UpdateSynonyms methods
  that were called in main.go but never defined
- Sort precision increased to 1000000x to avoid float truncation ties
- Support multiple ?q=a&q=b params (was only reading first query)
- Each query limited to 100 results independently
- Deduplicate results by info_hash across queries
- Keep highest similarity score when same torrent from multiple queries
- Sort merged results by similarity descending
@felipemarinho97

felipemarinho97 commented May 3, 2026

Copy link
Copy Markdown
Owner

@GuickerZ Consegue dividir o MR em pedaços menores? não sei se vou conseguir aceitar todas as mudanças e talvez algumas precisem de ajuste.

Por exemplo, isso aqui é um bugfix, e deveria ser mergeado:

Adicionada a diretiva omitempty em campos opcionais (como imdb, size, quality) no schema.IndexedTorrent.

Já isso aqui, considero fora do escopo do projeto:

mapeamento automático de Sinônimos no startup (the = o, of = do)

E o motivo é simples, se começarmos a mapear artigos do inglês, também deveríamos mapear do português, espanhol, mandarim, árabe, etc. E a coisa toda vai se tornando muito complexa.

Tem umas coisas extranhas também, ex:

A rota separada POST /search/multi foi removida.

essa rota nunca existiu

A feature do extended metadata por mim é ok de entrar também por ser algo opcional ativado via ENV, porém a implementação está confusa. Eu acho que deveria ser tudo feito em um post-processor olhando unicamente pro título, sem afetar os scrapers.

O /indexers/all também é ok, só colocaria ele em um arquivo dedicado.

Sobre as mudanças arquiteturais que você fez, no momento não posso aceitá-las pois existe outro MR aberto #78 que também está fazendo mudanças arquiteturais, e pode gerar conflitos. Então o ideal seria esperar esse MR ser mergeado, para depois revisar o que for necessário.

O MR também tem um fix pro bludv, que deveria estar em um MR a parte também.

Mas no geral, cada feature/mudança seria melhor que estivesse em seu próprio MR, e essas mais simples que não necessitam de muita discussão, que consiguiria mergeá-las mais rápido.

@maikyhot

maikyhot commented May 10, 2026

Copy link
Copy Markdown

I'm testing torrent-indexer on ZimaOS and currently only vaca_torrent works reliably. rede_torrent and torrent-dos-filmes fail through FlareSolverr with ERR_CONNECTION_REFUSED, even though FlareSolverr itself works fine with other sites.

Current instance info:

torrent-indexer root returns version: 0.15.2, revision: 0ba84b1

available indexers: comando_torrents, bludv, torrent-dos-filmes, filme_torrent, rede_torrent, vaca_torrent, starck-filmes

Working test:

GET /indexers/vaca_torrent?filter_results=true&limit=10&q=matrix returns 200 with valid JSON results.

Failing tests:

rede_torrent -> 500 / FlareSolverr ERR_CONNECTION_REFUSED

torrent-dos-filmes -> 500 / FlareSolverr ERR_CONNECTION_REFUSED

GET /search?q=matrix&q=batman -> Failed to search torrents

POST /search -> Method not allowed

GET /indexers/all?... falls back to root docs instead of aggregating results.

About Jackett:

custom definition is being loaded, because log changed from Loaded 548 Cardigann indexers to Loaded 549 Cardigann indexers after adding vaca_torrent_indexer.yml

but the indexer does not show up in the UI as expected.

Question:

Is vaca_torrent expected to work only through a single custom torrent-indexer.yml selector-based definition instead of a standalone Cardigann definition?

Are the /search and /indexers/all improvements from PR #81 not included in 0.15.2 / current latest image?

Has anyone made vaca_torrent appear and work correctly in Jackett UI?

If needed, I can provide the exact custom YAML and logs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants