Saltar al contenido
Development

Apple Music le da dos IDs distintos al mismo álbum

Por Victor Da Luz
iosswiftmusickitdev-logdeep-cut-atlas

Esta app luego se renombró a Deep Cut Atlas. Se la llama “Discoverer” a lo largo de este texto, porque así se llamaba el día en que ocurrió esto.

La función de esta semana en esta app de descubrimiento es el camino de “me gustó”: se está viendo un álbum guardado para revisar más tarde, se toca “Agregar a la biblioteca,” y la app ofrece de inmediato más lanzamientos de ese mismo artista para poner en cola a continuación. Agregar, y luego mantener el impulso. Construirla enseñó algo sobre MusicKit que no se esperaba, y es el tipo de cosa que rompería en silencio una implementación ingenua.

El flujo

Al tocar “Agregar a la biblioteca” en la tarjeta de un álbum ocurren tres cosas: las canciones del álbum entran a la biblioteca, esas mismas canciones salen de la lista “Por revisar” (ya se atendió, no debería quedarse ahí dando vueltas), y aparece una hoja deslizante: “Más de Khruangbin.” Esa hoja es una lista de otros lanzamientos del artista, los más nuevos primero, filtrados a los tipos de álbum/EP/sencillo/compilado que interesan, y, crucialmente, sin mostrar nada que ya se tenga. Se toca uno, entra a la lista de reproducción, la hoja se cierra. ¿No se quiere ninguno? Se desliza para descartarlo.

Los primeros dos pasos reutilizaron métodos de servicio que ya existían. La hoja es donde se puso interesante.

”No me muestres lo que ya tengo”

Ese filtro suena trivial. Están los lanzamientos del catálogo del artista, está la biblioteca del usuario: se resta una de la otra. El instinto inicial fue comparar por id, tal como se deduplicaría cualquier otra cosa.

Eso no funciona. MusicKit le da identificadores distintos a la copia de catálogo de un álbum y a la copia de biblioteca de ese mismo álbum. El álbum que está en la biblioteca y el álbum que se acaba de obtener de una búsqueda en el catálogo son, en lo que respecta a su MusicItemID, dos objetos sin relación. Entonces una verificación de pertenencia a un conjunto basada en ids no encuentra ninguna coincidencia y termina mostrando álbumes que ya se tienen.

Una vez que se ve, tiene sentido: el elemento de biblioteca es una copia personal con su propio ciclo de vida, el elemento de catálogo es el listado público de la tienda, pero no es obvio hasta que sale mal. La solución es hacer coincidir algo estable entre ambos: una clave normalizada de título más 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)) }

Es una heurística, y quedó anotada como algo para validar en un dispositivo real. Una edición de lujo y una edición estándar comparten título; una remasterización tal vez no. Pero está mucho más cerca de ser correcta que una comparación de ids que está estructuralmente condenada a fallar.

Encontrar al artista, para empezar

Hay una complicación relacionada. Los grupos de la lista de reproducción identifican su álbum mediante una clave sintetizada, no un id de catálogo real, porque, como se explicó en la publicación sobre agrupación de álbumes, una canción de lista de reproducción no lleva consigo la identidad completa de su álbum. Así que para encontrar “más de este artista” tampoco se puede buscar al artista por id. Se busca en el catálogo por nombre, se toma el primer resultado, y se piden sus álbumes. La misma imprecisión (dos artistas pueden compartir nombre), la misma nota pendiente de verificar en un dispositivo real.

Se nota un patrón a lo largo de este proyecto: MusicKit funciona mejor cuando se cuenta con identificadores de catálogo reales, y buena parte del trabajo consiste en reconstruirlos a partir de los datos más sueltos que realmente se tienen a mano.

Construyendo a ciegas, todavía

Como con cada función hasta ahora, nada de esto corrió contra la biblioteca real mientras se construía, MusicKit no funciona en el simulador, y todavía se usa una cuenta de desarrollador gratuita. El servicio simulado devuelve un conjunto fijo de lanzamientos de Khruangbin, incluyendo deliberadamente el álbum que se “agregó” y abarcando algunos tipos y años, para que la lógica de excluir/filtrar/ordenar tenga algo real con qué trabajar. Veintidós pruebas unitarias, todas en verde, todas contra datos falsos. La verificación honesta (¿de verdad se filtra la biblioteca real?, ¿la búsqueda de artista encuentra al Khruangbin correcto?) queda pendiente para el día en que se conecte un teléfono con una cuenta paga detrás.

La conclusión

Si hay que quedarse con una sola cosa de todo esto: en MusicKit, “¿este álbum ya está en la biblioteca del usuario?” no es una pregunta de id. La identidad en un catálogo musical es más desordenada que la identidad en una base de datos propia, porque el mismo registro existe en dos lugares que no se conocen entre sí. Hay que hacer coincidir lo que es estable para los humanos (título y artista), no lo que es estable para un solo sistema.

Lecturas relacionadas