const std = @import("std"); const jetzig = @import("jetzig"); const jetquery = @import("jetzig").jetquery; const Scrobble = @import("../../types.zig").LastFMScrobble; const lastfm = @import("../../types.zig").LastFM; // The `run` function for a job is invoked every time the job is processed by a queue worker // (or by the Jetzig server if the job is processed in-line). // // Arguments: // * allocator: Arena allocator for use during the job execution process. // * params: Params assigned to a job (from a request, values added to response data). // * env: Provides the following fields: // - logger: Logger attached to the same stream as the Jetzig server. // - environment: Enum of `{ production, development }`. pub fn run(allocator: std.mem.Allocator, params: *jetzig.data.Value, env: jetzig.jobs.JobEnv) !void { _ = allocator; if (params.getT(.array, "scrobbles")) |scrobbles| { for (scrobbles.items()) |item| { const scrobble: Scrobble = .{ .track = item.track.?, .artist = item.artist.?, .album = item.album.?, .date = item.date.? }; // Make hashes const album_hash = std.hash.Fnv1a_64.hash(scrobble.album); const artist_hash = std.hash.Fnv1a_64.hash(scrobble.artist); const song_hash = std.hash.Fnv1a_64.hash(scrobble.track); // Make IDs // Song: Song hash XOR artist hash XOR album hash // This way, if two songs share a name, then // the IDs also depend on the hash of the album // they're on, as well as the artist name. As far // as I can tell, this is only as issue for Sufjan // Steven's `Songs for Christmas`. // Album: If the album is not self-titled, then // album hash XOR artist hash. This way, if two // artists have an album of the same name, then // the IDs also depend on the hash of the artist // name. As far as I can tell, this is only an // issue for Weezer. // Artist Artist hash. If two artists have the same name, // then a descriptive string can be provided to // differentiate after the fact, or in a rule. var album_id: u64 = 0; const song_id = (song_hash ^ artist_hash ^ album_hash); if (artist_hash == album_hash) { album_id = album_hash; } else { album_id = (artist_hash ^ album_hash); } const artist_id = artist_hash; const artistalbum_offset = try jetzig.database.Query(.ArtistAlbum).select(.{}).count().execute(env.repo) orelse unreachable; const albumsong_offset = try jetzig.database.Query(.AlbumSong).select(.{}).count().execute(env.repo) orelse unreachable; const artistsong_offset = try jetzig.database.Query(.ArtistSong).select(.{}).count().execute(env.repo) orelse unreachable; // Inserts const artistalbum_insert = jetzig.database.Query(.ArtistAlbum).insert(.{ .id = 1 + artistalbum_offset, .artist_id = artist_id, .album_id = album_id }); const albumsong_insert = jetzig.database.Query(.AlbumSong).insert(.{ .id = 1 + albumsong_offset, .song_id = song_id, .album_id = album_id }); const artistsong_insert = jetzig.database.Query(.ArtistSong).insert(.{ .id = 1 + artistsong_offset, .artist_id = artist_id, .song_id = song_id }); const album_insert = jetzig.database.Query(.Album).insert(.{ .id = album_id, .title = scrobble.album, .song_num = 0, .length = 0.0, .play_count = 0, .holiday = false, .compilation = false, .deluxe = false, .live = false }); const artist_insert = jetzig.database.Query(.Artist).insert(.{ .id = artist_id, .name = scrobble.artist, .album_num = 0, .song_num = 0, .play_count = 0 }); const song_insert = jetzig.database.Query(.Song).insert(.{ .id = song_id, .title = scrobble.track, .length = 0.0, .hidden = false, .holiday = false, .play_count = 0 }); // Checks const artistalbum_check = try jetzig.database.Query(.ArtistAlbum).where(.{ .{ .artist_id = artist_id }, .AND, .{ .album_id = album_id } }).count().execute(env.repo); const albumsong_check = try jetzig.database.Query(.AlbumSong).where(.{ .{ .album_id = album_id }, .AND, .{ .song_id = song_id } }).count().execute(env.repo); const artistsong_check = try jetzig.database.Query(.ArtistSong).where(.{ .{ .artist_id = artist_id }, .AND, .{ .song_id = song_id } }).count().execute(env.repo); const album_check = try jetzig.database.Query(.Album).where(.{.{ .id = album_id }}).count().execute(env.repo); const artist_check = try jetzig.database.Query(.Artist).where(.{.{ .id = artist_id }}).count().execute(env.repo); const song_check = try jetzig.database.Query(.Song).where(.{.{ .id = song_id }}).count().execute(env.repo); // Insert into Intermediate Tables if (artistalbum_check == 0) try env.repo.execute(artistalbum_insert); if (albumsong_check == 0) try env.repo.execute(albumsong_insert); if (artistsong_check == 0) try env.repo.execute(artistsong_insert); if (album_check == 0) try env.repo.execute(album_insert); if (artist_check == 0) try env.repo.execute(artist_insert); if (song_check == 0) try env.repo.execute(song_insert); const scrobble_offset = try jetzig.database.Query(.Scrobble).select(.{}).count().execute(env.repo) orelse unreachable; try jetzig.database.Query(.Scrobble).insert(.{ .id = scrobble_offset + 1, .song_id = song_id, .album_id = album_id, .artist_id = artist_id, .date = scrobble.date }).execute(env.repo); } } }