Enquanto trabalho e caminhando, ouço música de fundo. Eu costumava usar um rádio na Internet chamado Jango , que era adequado a quase todos, exceto pelas seguintes coisas:
- inacessibilidade durante caminhadas quase diárias na floresta (ou seja, sem conexão à Internet).
- A necessidade de alternar entre diferentes canais para mudar o gênero da música. Em outras palavras, o ouvinte de Jango tem poucas chances de descobrir novos gêneros musicais.
Um dia, a ideia surgiu com um aplicativo móvel para ouvir música, que funcionava a maior parte do tempo sem a Internet (ou seja, cache de músicas) com detecção automática dos vícios musicais dos usuários. Como não vi nada parecido (talvez apenas parecesse mal?), Decidi implementá-lo pessoalmente. Agora, após vários meses de codificação em meu tempo livre do trabalho principal, publiquei a primeira versão ainda muito crua, mas já em funcionamento, do aplicativo Android .

Eu queria implementar um aplicativo com uma interface muito simples e intuitiva (de fato, com apenas dois botões: "pausar" e "pular"), mas com lógica interna suficientemente avançada para analisar as preferências musicais (com base na coleta de estatísticas sobre a duração da escuta das faixas antes de pular) e faixas de armazenamento em cache. Como eu não queria duplicar a lógica para diferentes plataformas, foi decidido implementá-la em C ++ (que é o "denominador comum" para iOS e Android).
Para armazenar os metadados sobre as faixas, bem como as preferências do usuário, escolhi o SQLite. Os arquivos de capa de álbum e música são armazenados em uma árvore de diretórios baseada em hash de três níveis (semelhante à maneira como funciona no Git).
512 MiB escolheram o tamanho do cache (esses e quaisquer outros dígitos, é claro, podem ser configurados). A lógica da rotação das faixas é a seguinte: 20 faixas são baixadas por iteração de atualização. Depois que o usuário escuta cada faixa pelo menos duas vezes, uma nova atualização é iniciada. As faixas são excluídas, para as quais o tempo médio de audição é inferior ao limite especificado e os metadados das novas faixas são baixados do servidor, após o qual o download é iniciado.
A lógica de reprodução é a seguinte. Quanto maior o tempo médio de audição de uma faixa, mais frequentemente ela é reproduzida.
Sendo um desenvolvedor experiente de C ++, não tive dificuldades especiais na implementação da lógica descrita acima (embora, na realidade, seja um pouco mais complicada). No entanto, não tendo experiência em escrever aplicativos para Android, tive que gastar muito tempo e esforço na implementação da camada de software apropriada (especialmente a interface do usuário). Estou certo de que agora muitas coisas foram implementadas não da melhor maneira.
Decidi escrever um wrapper Android no Kotlin. De fato, o Java não prometeu nenhuma vantagem, porque você ainda teria que mexer com o JNI (no iOS, a situação seria diferente, o Objective-C é muito mais conveniente que o Swift em termos de integração com o código lógico do núcleo nativo).
Usei o Fuel para baixar metadados JSON e o Fetch para baixar arquivos (fiquei surpreso que o Fuel não consiga baixar arquivos com eficiência). A propósito, para a segunda biblioteca, tenho queixas sobre a estabilidade do trabalho.
O código do servidor foi escrito em Golang e usa o PostgreSQL durante a reforma . O banco de dados de metadados atual foi criado pela indexação do Free Music Archive e, no futuro, planejo indexar outros fontes abertas também. As faixas no servidor ainda não estão armazenadas para economizar espaço (eu economizo na hospedagem), mas consulte diretamente o repositório de origem.
O servidor coleta estatísticas de escuta de faixas para cada um dos usuários. Assim, a cada gênero musical é atribuída uma pontuação preferencial que afeta a probabilidade de escolher as composições apropriadas durante a rotação.
Ficarei feliz se você tentar meu aplicativo. De repente você vai gostar. Certamente, durante o uso, você encontrará bugs (o programa ainda está sendo processado). A velocidade de sua correção dependerá diretamente da demanda pelo meu trabalho.