Pular para o conteúdo
Development

O Apple Music dá dois IDs diferentes para o mesmo álbum

Por Victor Da Luz
iosswiftmusickitdev-logdeep-cut-atlas

Esse app foi renomeado depois para Deep Cut Atlas. Ele é chamado de “Discoverer” ao longo do texto abaixo, porque era assim que se chamava no dia em que isso aconteceu.

A funcionalidade dessa semana no meu app de descoberta é o caminho do “gostei”: você está olhando um álbum que salvou para conferir depois, toca em Add to Library, e o app imediatamente oferece mais lançamentos do mesmo artista para você colocar na fila em seguida. Adiciona, e mantém o embalo. Construir isso me ensinou algo sobre o MusicKit que eu não esperava, e é o tipo de coisa que quebraria silenciosamente uma implementação ingênua.

O fluxo

Toque em “Add to Library” num card de álbum e três coisas acontecem: as faixas do álbum entram na sua biblioteca, essas mesmas faixas saem da playlist “To Check Out” (você já resolveu aquilo, não devia continuar lá), e uma sheet desliza para cima: “More from Khruangbin.” Essa sheet é uma lista de outros lançamentos do artista, mais recentes primeiro, filtrada pelos tipos álbum/EP/single/coletânea que interessam, e principalmente, sem mostrar nada que você já tem. Toque em um, ele vai para a playlist, a sheet fecha. Não quer nenhum? Arraste para descartar.

Os dois primeiros passos reaproveitaram métodos de serviço que eu já tinha. A sheet foi onde a coisa ficou interessante.

“Não me mostre o que eu já tenho”

Esse filtro parece trivial. Tenho os lançamentos do catálogo do artista, tenho a biblioteca do usuário, é só subtrair um do outro. Meu instinto foi comparar por id, do jeito que você removeria duplicatas de qualquer coisa.

Isso não funciona. O MusicKit dá identificadores diferentes para a cópia de catálogo de um álbum e a cópia de biblioteca do mesmo álbum. O álbum parado na sua biblioteca e o álbum que você acabou de puxar de uma busca no catálogo são, no que diz respeito ao MusicItemID deles, dois objetos sem relação nenhuma. Então uma checagem de pertencimento a um conjunto usando ids encontra zero sobreposição e mostra alegremente álbuns que você já tem.

Uma vez que você percebe, faz sentido: seu item de biblioteca é uma cópia pessoal com ciclo de vida próprio, o item de catálogo é a listagem pública da loja, mas isso não é óbvio até te morder. A correção é comparar por algo estável nos dois lados: uma chave normalizada de título mais artista.

let libraryKeys = Set(libraryAlbums.items.map {
    albumKey(title: $0.title, artist: $0.artistName)   // lowercased, trimmed
})
return catalogAlbums
    .map(LibraryAlbum.init)
    .filter { !libraryKeys.contains(albumKey(title: $0.title, artist: $0.artistName)) }

É uma heurística, e anotei como algo para validar num dispositivo real. Uma edição deluxe e uma edição padrão compartilham o título; um remaster talvez não. Mas está bem mais perto de certo do que uma comparação por id que está estruturalmente garantida a falhar.

Até achar o artista é complicado

Tem uma complicação relacionada. Meus grupos de playlist identificam o álbum deles por uma chave sintetizada, não um id real de catálogo, porque, como escrevi em o post sobre agrupamento de álbuns, uma faixa de playlist não carrega a identidade completa do seu álbum. Então, para achar “mais desse artista,” também não consigo buscar o artista por id. Busco no catálogo por nome, pego o primeiro resultado, e peço os álbuns dele. Mesma imprecisão (dois artistas podem compartilhar um nome), mesma anotação para mim mesmo de verificar num dispositivo real.

Estou percebendo um padrão nesse projeto: o MusicKit funciona melhor quando você tem identificadores reais de catálogo em mãos, e boa parte do trabalho é reconstruí-los a partir dos dados mais soltos que você de fato tem disponíveis.

Construindo às cegas, ainda

Como em toda funcionalidade até agora, nada disso rodou contra minha biblioteca real enquanto eu construía, o MusicKit não funciona no simulador, e eu ainda estou numa conta de desenvolvedor gratuita. O serviço simulado devolve um conjunto fixo de lançamentos do Khruangbin, incluindo de propósito o álbum que você “adicionou” e cobrindo alguns tipos e anos, para que a lógica de excluir / filtrar / ordenar tenha algo real para mastigar. Vinte e dois testes unitários, todos verdes, todos contra dados falsos. A verificação honesta, se minha biblioteca real de fato é filtrada corretamente, se a busca de artista encontra o Khruangbin certo, está na fila para o dia em que eu conectar um telefone com uma conta paga por trás.

A lição

Se você levar uma coisa disso: no MusicKit, “esse álbum já está na biblioteca do usuário?” não é uma pergunta de id. Identidade num catálogo de música é mais bagunçada do que identidade no seu próprio banco de dados, porque o mesmo registro existe em dois lugares que não sabem um do outro. Compare pelo que é estável para humanos, título e artista, não pelo que é estável para um sistema.

Leitura relacionada

Development

A playlist que já tinha o nome certo

Um artefato de renomeação, uma API sem campo de autor pra atualizar, e um teste em dispositivo real provando que o bug já tinha se corrigido sozinho, fechado como aceitar como está.

Ler

Você também pode achar útil

Proton

Proton Mail

E-mail criptografado de ponta a ponta, com arquitetura de acesso zero.

Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).

Saiba mais
AdGuard

AdGuard para iOS

Bloqueio de anúncios e rastreadores em todo o sistema no iOS, sem necessidade de um servidor DNS separado.

Como afiliado da AdGuard, ganho com compras qualificadas.

Saiba mais
Proton

Proton Pass

Gerenciador de senhas focado em privacidade, da equipe por trás do Proton Mail.

Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).

Saiba mais