Scanner

Como o InkShelf descobre o que existe numa pasta raiz e mantém a biblioteca em Room sincronizada com o que está no armazenamento, sem perder o estado que o usuário já acumulou (favoritos, progresso, capas escolhidas).

O trabalho é dividido em duas etapas com responsabilidades bem separadas: LibraryScanner só lê o sistema de arquivos; SyncEngine decide o que fazer com o resultado. Este documento cobre a varredura local (SAF). Para bibliotecas remotas (Komga/Kavita) — que têm seu próprio scanner por provedor, mas seguem a mesma filosofia de preservar estado do usuário no merge — ver Fontes Remotas.

LibraryScanner — travessia

Percorre uma pasta raiz (URI do SAF) recursivamente, subdiretório por subdiretório, usando o ContentResolver do Android. Cada diretório é uma consulta independente ao provedor de documentos; para não serializar milhares dessas consultas uma atrás da outra, a travessia roda em corrotinas paralelas, limitadas a 4 diretórios sendo consultados ao mesmo tempo — limite escolhido porque o DocumentsProvider do SAF já serializa internamente e degrada com concorrência maior que isso.

Extensões reconhecidas: cbz, cbr, pdf, zip, rar, epub. Qualquer outro arquivo é ignorado silenciosamente.

Depois de coletar toda a árvore, pastas que não têm nenhum arquivo suportado em nenhum nível abaixo delas são descartadas do resultado — uma pasta cheia de arquivos de formato não suportado, ou vazia, não vira uma entrada vazia na biblioteca.

O resultado de um scan é apenas uma lista de pastas e arquivos em memória; nada é gravado no banco nesta etapa.

SyncEngine — sincronização

Recebe o resultado do scanner e decide, comparando com o que já existe no Room, o que precisa mudar:

  • Itens novos (na varredura, ausentes no banco) são inseridos.
  • Itens que desapareceram (no banco, ausentes na varredura — porque o usuário apagou ou moveu o arquivo/pasta fora do app) são removidos.
  • Itens que já existiam têm os campos vindos do sistema de arquivos atualizados (nome, pasta pai), mas os campos que representam estado do usuário são preservados explicitamente: favorito, oculto, capa customizada, progresso de leitura (página atual, página total, posição de rolagem e zoom no caso de EPUB) e todos os campos de metadado ComicInfo.xml já lidos anteriormente. Um rescan nunca zera o progresso de leitura de um arquivo que já vinha sendo lido.
  • A contagem de itens de cada pasta (itemCount, usada na exibição) é recalculada de forma incremental a partir da árvore inteira, não pasta por pasta.
  • Ao final, caches em disco (capas, páginas extraídas, arquivos de leitura reaproveitáveis, EPUBs extraídos) que pertenciam a arquivos removidos da biblioteca são apagados — remover uma pasta raiz de fato libera o espaço em disco que ela ocupava.

Quando existem múltiplas pastas raiz (ver Biblioteca), um rescan varre todas elas e sincroniza o conjunto combinado numa única passada.

Quando o scanner roda

  • Ao adicionar uma pasta raiz pela primeira vez, dispara uma varredura inicial daquela pasta.
  • Rescan manual, acionado pelo usuário na Biblioteca ou nas configurações de Biblioteca — reprocessa todas as pastas raiz atuais.

Bibliotecas remotas grandes rodam em 1º plano

Uma sincronização de fonte remota (adicionar, anexar biblioteca nova, ou mudar opções de uma biblioteca já existente) roda num serviço em 1º plano (KomgaSyncService/KavitaSyncService), com notificação de progresso — necessário porque uma biblioteca remota grande pode levar minutos, tempo demais pra confiar só numa corrotina presa à tela. Ver Fontes Remotas para os detalhes de scanner/merge por provedor.