continue fixing up sync

This commit is contained in:
Daniel Bulant 2026-04-20 17:58:50 +02:00
parent d4f9a8c2dd
commit 332ddd76cf
No known key found for this signature in database
2 changed files with 222 additions and 171 deletions

View file

@ -43,22 +43,30 @@ type DbTransaction = Parameters<typeof db.transaction>[0] extends (
type DbLike = DbClient | DbTransaction; type DbLike = DbClient | DbTransaction;
export async function upsertImages(images: Image[], dbClient: DbLike = db) { export async function upsertImages(images: Image[], dbClient: DbLike = db) {
await dbClient.insert(platformImage).values( await dbClient
.insert(platformImage)
.values(
images.map(({ url, height, width }) => ({ images.map(({ url, height, width }) => ({
platform: PLATFORM_SPOTIFY, platform: PLATFORM_SPOTIFY,
url, url,
height, height,
width, width,
})), })),
); )
.onConflictDoNothing();
} }
export async function upsertGenres(genres: string[], dbClient: DbLike = db) { export async function upsertGenres(genres: string[], dbClient: DbLike = db) {
await dbClient.insert(genre).values(genres.map((name) => ({ name }))); await dbClient
.insert(genre)
.values(genres.map((name) => ({ name })))
.onConflictDoNothing();
} }
export async function upsertArtists(artists: Artist[], dbClient: DbLike = db) { export async function upsertArtists(artists: Artist[], dbClient: DbLike = db) {
await dbClient.insert(artist).values( await dbClient
.insert(artist)
.values(
artists.map(({ id, name, images, genres, popularity, type }) => ({ artists.map(({ id, name, images, genres, popularity, type }) => ({
platform: PLATFORM_SPOTIFY, platform: PLATFORM_SPOTIFY,
platform_id: id, platform_id: id,
@ -66,7 +74,8 @@ export async function upsertArtists(artists: Artist[], dbClient: DbLike = db) {
popularity, popularity,
type, type,
})), })),
); )
.onConflictDoNothing();
await upsertImages( await upsertImages(
artists.flatMap((a) => a.images), artists.flatMap((a) => a.images),
dbClient, dbClient,
@ -76,7 +85,9 @@ export async function upsertArtists(artists: Artist[], dbClient: DbLike = db) {
dbClient, dbClient,
); );
for (const spotifyArtist of artists) { for (const spotifyArtist of artists) {
await dbClient.insert(artistImage).select( await dbClient
.insert(artistImage)
.select(
dbClient dbClient
.select({ .select({
artistId: artist.id, artistId: artist.id,
@ -93,8 +104,11 @@ export async function upsertArtists(artists: Artist[], dbClient: DbLike = db) {
), ),
) )
.innerJoin(artist, eq(artist.platform_id, spotifyArtist.id)), .innerJoin(artist, eq(artist.platform_id, spotifyArtist.id)),
); )
await dbClient.insert(artistGenre).select( .onConflictDoNothing();
await dbClient
.insert(artistGenre)
.select(
dbClient dbClient
.select({ .select({
artistId: artist.id, artistId: artist.id,
@ -103,7 +117,8 @@ export async function upsertArtists(artists: Artist[], dbClient: DbLike = db) {
.from(genre) .from(genre)
.where(inArray(genre.name, spotifyArtist.genres)) .where(inArray(genre.name, spotifyArtist.genres))
.innerJoin(artist, eq(artist.platform_id, spotifyArtist.id)), .innerJoin(artist, eq(artist.platform_id, spotifyArtist.id)),
); )
.onConflictDoNothing();
} }
} }
@ -191,7 +206,9 @@ export async function upsertAlbums(
albums.flatMap((a) => a.artists), albums.flatMap((a) => a.artists),
dbClient, dbClient,
); );
await dbClient.insert(album).values( await dbClient
.insert(album)
.values(
albums.map(({ id, name, type, popularity, release_date, label }) => ({ albums.map(({ id, name, type, popularity, release_date, label }) => ({
platform: PLATFORM_SPOTIFY, platform: PLATFORM_SPOTIFY,
platform_id: id, platform_id: id,
@ -201,7 +218,8 @@ export async function upsertAlbums(
release_date: new Date(release_date), release_date: new Date(release_date),
label, label,
})), })),
); )
.onConflictDoNothing();
await upsertImages( await upsertImages(
albums.flatMap((a) => a.images), albums.flatMap((a) => a.images),
dbClient, dbClient,
@ -211,7 +229,9 @@ export async function upsertAlbums(
dbClient, dbClient,
); );
for (const spotifyAlbum of albums) { for (const spotifyAlbum of albums) {
await dbClient.insert(albumImage).select( await dbClient
.insert(albumImage)
.select(
dbClient dbClient
.select({ .select({
albumId: album.id, albumId: album.id,
@ -228,8 +248,11 @@ export async function upsertAlbums(
), ),
) )
.innerJoin(album, eq(album.platform_id, spotifyAlbum.id)), .innerJoin(album, eq(album.platform_id, spotifyAlbum.id)),
); )
await dbClient.insert(albumArtist).select( .onConflictDoNothing();
await dbClient
.insert(albumArtist)
.select(
dbClient dbClient
.select({ .select({
albumId: album.id, albumId: album.id,
@ -243,8 +266,11 @@ export async function upsertAlbums(
), ),
) )
.innerJoin(album, eq(album.platform_id, spotifyAlbum.id)), .innerJoin(album, eq(album.platform_id, spotifyAlbum.id)),
); )
await dbClient.insert(albumGenre).select( .onConflictDoNothing();
await dbClient
.insert(albumGenre)
.select(
dbClient dbClient
.select({ .select({
albumId: album.id, albumId: album.id,
@ -253,7 +279,8 @@ export async function upsertAlbums(
.from(genre) .from(genre)
.where(inArray(genre.name, spotifyAlbum.genres)) .where(inArray(genre.name, spotifyAlbum.genres))
.innerJoin(album, eq(album.platform_id, spotifyAlbum.id)), .innerJoin(album, eq(album.platform_id, spotifyAlbum.id)),
); )
.onConflictDoNothing();
} }
} }
@ -271,7 +298,9 @@ export async function upsertTracks(tracks: Track[], dbClient: DbLike = db) {
tracks.map((t) => t.album.id), tracks.map((t) => t.album.id),
dbClient, dbClient,
); );
await dbClient.insert(track).values( await dbClient
.insert(track)
.values(
tracks.map((spotifyTrack) => ({ tracks.map((spotifyTrack) => ({
albumId: albumIdMap.get(spotifyTrack.album.id)!, albumId: albumIdMap.get(spotifyTrack.album.id)!,
name: spotifyTrack.name, name: spotifyTrack.name,
@ -283,9 +312,12 @@ export async function upsertTracks(tracks: Track[], dbClient: DbLike = db) {
disc_number: spotifyTrack.disc_number, disc_number: spotifyTrack.disc_number,
track_number: spotifyTrack.track_number, track_number: spotifyTrack.track_number,
})), })),
); )
.onConflictDoNothing();
for (const spotifyTrack of tracks) { for (const spotifyTrack of tracks) {
await dbClient.insert(trackArtist).select( await dbClient
.insert(trackArtist)
.select(
dbClient dbClient
.select({ .select({
trackId: track.id, trackId: track.id,
@ -299,7 +331,8 @@ export async function upsertTracks(tracks: Track[], dbClient: DbLike = db) {
), ),
) )
.innerJoin(track, eq(track.platform_id, spotifyTrack.id)), .innerJoin(track, eq(track.platform_id, spotifyTrack.id)),
); )
.onConflictDoNothing();
} }
} }
@ -315,14 +348,17 @@ export async function upsertTopArtists(
artists.map((t) => t.id), artists.map((t) => t.id),
dbClient, dbClient,
); );
await dbClient.insert(topArtist).values( await dbClient
.insert(topArtist)
.values(
artists.map((spotifyArtist, index) => ({ artists.map((spotifyArtist, index) => ({
artistId: artistIdMap.get(spotifyArtist.id)!, artistId: artistIdMap.get(spotifyArtist.id)!,
position: index + 1, position: index + 1,
userId, userId,
timeline, timeline,
})), })),
); )
.onConflictDoNothing();
} }
export async function upsertTopTracks( export async function upsertTopTracks(
@ -337,14 +373,17 @@ export async function upsertTopTracks(
tracks.map((t) => t.id), tracks.map((t) => t.id),
dbClient, dbClient,
); );
await dbClient.insert(topTrack).values( await dbClient
.insert(topTrack)
.values(
tracks.map((spotifyTrack, index) => ({ tracks.map((spotifyTrack, index) => ({
trackId: trackIdMap.get(spotifyTrack.id)!, trackId: trackIdMap.get(spotifyTrack.id)!,
position: index + 1, position: index + 1,
userId, userId,
timeline, timeline,
})), })),
); )
.onConflictDoNothing();
} }
export async function upsertSavedAlbums( export async function upsertSavedAlbums(
@ -359,13 +398,16 @@ export async function upsertSavedAlbums(
albums.map((t) => t.id), albums.map((t) => t.id),
dbClient, dbClient,
); );
await dbClient.insert(savedAlbum).values( await dbClient
.insert(savedAlbum)
.values(
saved.map((item) => ({ saved.map((item) => ({
albumId: albumIdMap.get(item.album.id)!, albumId: albumIdMap.get(item.album.id)!,
userId, userId,
saved_at: new Date(item.added_at), saved_at: new Date(item.added_at),
})), })),
); )
.onConflictDoNothing();
} }
export async function upsertSavedTracks( export async function upsertSavedTracks(
@ -380,13 +422,16 @@ export async function upsertSavedTracks(
tracks.map((t) => t.id), tracks.map((t) => t.id),
dbClient, dbClient,
); );
await dbClient.insert(savedTrack).values( await dbClient
.insert(savedTrack)
.values(
saved.map((item) => ({ saved.map((item) => ({
trackId: trackIdMap.get(item.track.id)!, trackId: trackIdMap.get(item.track.id)!,
userId, userId,
saved_at: new Date(item.added_at), saved_at: new Date(item.added_at),
})), })),
); )
.onConflictDoNothing();
} }
export async function upsertFollowedArtists( export async function upsertFollowedArtists(
@ -400,12 +445,15 @@ export async function upsertFollowedArtists(
artists.map((t) => t.id), artists.map((t) => t.id),
dbClient, dbClient,
); );
await dbClient.insert(followedArtist).values( await dbClient
.insert(followedArtist)
.values(
artists.map((spotifyArtist) => ({ artists.map((spotifyArtist) => ({
artistId: artistIdMap.get(spotifyArtist.id)!, artistId: artistIdMap.get(spotifyArtist.id)!,
userId, userId,
})), })),
); )
.onConflictDoNothing();
} }
export async function upsertPlaybackHistory( export async function upsertPlaybackHistory(
@ -420,11 +468,14 @@ export async function upsertPlaybackHistory(
tracks.map((t) => t.id), tracks.map((t) => t.id),
dbClient, dbClient,
); );
await dbClient.insert(playbackHistory).values( await dbClient
.insert(playbackHistory)
.values(
items.map((item) => ({ items.map((item) => ({
trackId: trackIdMap.get(item.track.id)!, trackId: trackIdMap.get(item.track.id)!,
userId, userId,
played_at: new Date(item.played_at), played_at: new Date(item.played_at),
})), })),
); )
.onConflictDoNothing();
} }

View file

@ -140,8 +140,8 @@ export class SpotifySyncWorkflow extends ConfiguredInstance {
const page = await sdk.currentUser.followedArtists(after, 50); const page = await sdk.currentUser.followedArtists(after, 50);
const artists = page.artists; const artists = page.artists;
followed.push(...artists.items); followed.push(...artists.items);
if (!artists.next) break; if (!artists.next || artists.items.length === 0) break;
after = artists.next; after = artists.items[artists.items.length - 1]!.id;
} }
return followed; return followed;
} }