Compare commits

..

No commits in common. "d638fa66c550e79ccd04101e093b06b5d56970a2" and "7f3778e82f74627bfe992fd03193acec06adf9ce" have entirely different histories.

6 changed files with 183 additions and 224 deletions

View file

@ -17,8 +17,8 @@
// internet connectivity.
.dependencies = .{
.jetzig = .{
.url = "https://github.com/jetzig-framework/jetzig/archive/695664bc10e6e73389ee2fe7fbcaedc27fa8adc9.tar.gz",
.hash = "jetzig-0.0.0-IpAgLSFeDwBEhfEaDBo0JqhRbvQA3ScbWjssBqhJHFmb",
.url = "https://github.com/jetzig-framework/jetzig/archive/7be1d137fcab5c422e05f12092f6e04a02900d6f.tar.gz",
.hash = "jetzig-0.0.0-IpAgLURbDwB1NlywUH7lnQ3zptNvSQWVosaA1k7l1cNz",
},
.zeit = .{
.url = "https://github.com/rockorager/zeit/archive/refs/tags/v0.6.0.tar.gz",

View file

@ -1,12 +1,56 @@
const std = @import("std");
const jetzig = @import("jetzig");
const queries = @import("../../queries.zig");
const zeit = @import("zeit");
const TableRow = @import("../../types.zig").TableRow;
const HyperlinkData = @import("../../types.zig").HyperlinkData;
const Utils = @import("../../date_fmt.zig");
pub fn index(request: *jetzig.Request) !jetzig.View {
var root = try request.data(.object);
var scrobbles_view = try root.put("scrobbles", .array);
const scrobbles = try queries.entityQueryResult(request, queries.generateQuery(.scrobble, .entities), .{}, .array);
try root.put("scrobbles", scrobbles);
const query =
\\SELECT songs.name, songs.id, albums.name, albums.id, artists.name, artists.id, scrobbles.id, scrobbles.datetime
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
\\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
\\INNER JOIN artists ON artists.id = albumsongsartists.artist_id
\\ORDER BY scrobbles.datetime ASC
;
var scrobbles_jq_result = try request.repo.executeSql(query, .{});
defer scrobbles_jq_result.deinit();
const Scrobble = struct { song_name: []const u8, song_id: i32, album_name: []const u8, album_id: i32, artist_name: []const u8, artist_id: i32, s_id: i32, date: i64 };
var prev_s_id: ?i32 = null;
var row: ?TableRow = null;
var artistlist = std.ArrayList(HyperlinkData).init(request.allocator);
blk: while (try scrobbles_jq_result.postgresql.result.next()) |scrobble_row| {
const scrobble = try scrobble_row.to(Scrobble, .{ .dupe = true, .allocator = request.allocator });
if (scrobble.s_id == prev_s_id) {
try artistlist.append(.{ .name = scrobble.artist_name, .id = scrobble.artist_id });
continue :blk;
} else {
const date = try Utils.dateFmt(request.allocator, scrobble.date);
try artistlist.append(.{ .name = scrobble.artist_name, .id = scrobble.artist_id });
row = TableRow{
.song = .{ .name = scrobble.song_name, .id = scrobble.song_id },
.album = .{ .name = scrobble.album_name, .id = scrobble.album_id },
.artistlist = try artistlist.toOwnedSlice(),
.date = date,
};
try scrobbles_view.append(row);
}
prev_s_id = scrobble.s_id;
}
return request.render(.ok);
}

View file

@ -12,21 +12,6 @@ pub fn index(request: *jetzig.Request) !jetzig.View {
}
pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View {
var root = try request.data(.object);
const song = try queries.entityQueryResult(request, queries.generateQuery(.song, .entity_info), .{id}, .object);
try root.put("song", song.get("entity_info"));
const scrobbles = try queries.entityQueryResult(request, queries.generateQuery(.song, .entity_items), .{id}, .array);
try root.put("scrobbles", scrobbles);
const appears = try queries.entityQueryResult(request, queries.generateQuery(.song, .appears), .{id}, .array);
try root.put("appears", appears);
const firstlast = try queries.entityQueryResult(request, queries.generateQuery(.song, .firstlast), .{id}, .array);
try root.put("firstlast", firstlast);
const timescale = try queries.entityQueryResult(request, queries.generateQuery(.song, .timescale), .{id}, .array);
try root.put("yearly", timescale);
_ = id;
return request.render(.ok);
}

View file

@ -1,19 +1,3 @@
@zig {
const ColumnChoices = []const enum{song, album, artist, artistlist, scrobbles, date};
const columns: ColumnChoices = &.{.song, .artistlist, .album, .date};
}
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
@partial partials/header
<h1>{{.song}}</h1>
@partial partials/firstlast_listens(scrobbles: .song.scrobbles, rank: .song.rank, firstlast: .firstlast)
<h3>Yearly Performance</h3>
@partial partials/timescale(range: .yearly)
<h2>Scrobbles</h2>
@partial partials/newtable(T: ColumnChoices, table_data: .scrobbles, columns: columns)
</body>
</html>
<div>
<span>Content goes here</span>
</div>

View file

@ -81,46 +81,23 @@ pub fn post(request: *jetzig.Request) !jetzig.View {
// Not sure if I should be proud or feel sick
switch (imported_scrobbles) {
.LastFMStats => |scrobbles| {
inline else => |scrobbles| {
appends: for (scrobbles) |scrobble| {
const filtered_scrobble: Data.Scrobble = blk: switch (@TypeOf(scrobble)) {
Data.IgnorantScrobble => {
if (scrobble.date > latest_timestamp * 1_000 or scrobble.date < earliest_timestamp * 1_000) {
limited_tracks += 1;
continue :appends;
}
const filtered_scrobble = Data.Scrobble{
break :blk Data.Scrobble{
.album = scrobble.album,
.artists_album = &[_][]const u8{scrobble.artist},
.track = scrobble.track,
.artists_track = &[_][]const u8{scrobble.artist},
.date = scrobble.date * 1_000,
};
const complete_scrobble = if (rule_list) |rl| try rules.applyScrobbleRule(request.allocator, filtered_scrobble, rl) else filtered_scrobble;
const row = try Utils.scrobbleToRow(request.allocator, complete_scrobble);
try view_params.append(row);
try job_params.append(complete_scrobble);
}
},
.LastFMWeb => |scrobbles| {
for (scrobbles) |scrobble| {
const filtered_scrobble = Data.Scrobble{
.album = if (scrobble.album) |album| album.@"#text" else "Not Provided",
.artists_album = &[_][]const u8{scrobble.artist.@"#text"},
.track = scrobble.name,
.artists_track = &[_][]const u8{scrobble.artist.@"#text"},
.date = try std.fmt.parseInt(i64, scrobble.date.?.uts, 10) * 1_000_000,
};
const complete_scrobble = if (rule_list) |rl| try rules.applyScrobbleRule(request.allocator, filtered_scrobble, rl) else filtered_scrobble;
const row = try Utils.scrobbleToRow(request.allocator, complete_scrobble);
try view_params.append(row);
try job_params.append(complete_scrobble);
}
},
.Spotify => |scrobbles| {
appends: for (scrobbles) |scrobble| {
Data.SpotifyScrobble => {
if (scrobble.ms_played < 30_000 and (scrobble.reason_end == null or !std.mem.eql(u8, scrobble.reason_end.?, "trackdone"))) {
skipped_tracks += 1;
continue :appends;
@ -136,19 +113,45 @@ pub fn post(request: *jetzig.Request) !jetzig.View {
continue :appends;
}
const filtered_scrobble = Data.Scrobble{
break :blk Data.Scrobble{
.album = scrobble.master_metadata_album_album_name.?,
.artists_album = &[_][]const u8{scrobble.master_metadata_album_artist_name.?},
.track = scrobble.master_metadata_track_name.?,
.artists_track = &[_][]const u8{scrobble.master_metadata_album_artist_name.?},
.date = (try zeit.instant(.{ .source = .{ .iso8601 = scrobble.ts } })).unixTimestamp() * 1_000_000,
};
},
Data.LastFMWebScrobble => {
break :blk Data.Scrobble{
.album = if (scrobble.album) |album| album.@"#text" else "Not Provided",
.artists_album = &[_][]const u8{scrobble.artist.@"#text"},
.track = scrobble.name,
.artists_track = &[_][]const u8{scrobble.artist.@"#text"},
.date = try std.fmt.parseInt(i64, scrobble.date.?.uts, 10) * 1_000_000,
};
},
else => unreachable,
};
const complete_scrobble = if (rule_list) |rl| try rules.applyScrobbleRule(request.allocator, filtered_scrobble, rl) else filtered_scrobble;
const row = try Utils.scrobbleToRow(request.allocator, complete_scrobble);
try view_params.append(row);
try job_params.append(complete_scrobble);
var job_param = try job_params.append(.object);
try job_param.put("album", complete_scrobble.album);
try job_param.put("track", complete_scrobble.track);
try job_param.put("date", complete_scrobble.date);
var track_artists_array = try job_param.put("artists_track", .array);
for (complete_scrobble.artists_track) |a| {
try track_artists_array.append(a);
}
var album_artists_array = try job_param.put("artists_album", .array);
for (complete_scrobble.artists_album) |a| {
try album_artists_array.append(a);
}
}
},
}

View file

@ -20,27 +20,30 @@ pub fn entityQueryResult(request: *jetzig.Request, query: GeneratedQuery, args:
blk: while (try result.postgresql.result.next()) |entity_row| {
switch (query.ResultType) {
FirstlastResult, TimescaleResult, EntitiesScrobbleResult, EntitiesSongResult, EntitiesAlbumResult, EntitiesArtistResult, EntityItemsResult, AppearsResult, EntityInfoResult, EntityItemsSongResult => |T| {
FirstlastResult, TimescaleResult, EntitiesScrobbleResult, EntitiesSongResult, EntitiesAlbumResult, EntitiesArtistResult, EntityItemsResult, AppearsResult, EntityInfoResult => |T| {
const entity = try entity_row.to(T, .{ .dupe = true, .allocator = request.allocator });
const item: ?TableRow = switch (query.ResultType) {
EntitiesScrobbleResult, EntitiesSongResult, EntitiesAlbumResult, EntitiesArtistResult => switch (query.entity) {
.artist => TableRow{ .artist = .{ .name = entity.name, .id = entity.id }, .scrobbles = entity.scrobbles },
.scrobble, .song, .album => album_entities: {
.album => album_entities: {
const last_artist = artist_list.getLastOrNull();
try artist_list.append(.{ .name = entity.artist_name, .id = entity.artist_id });
if (last_artist) |la| {
if (la.id == entity.artist_id) continue :blk;
}
break :album_entities switch (query.entity) {
.scrobble => TableRow{ .song = .{ .name = entity.song_name, .id = entity.song_id }, .album = .{ .name = entity.album_name, .id = entity.album_id }, .artistlist = try artist_list.toOwnedSlice(), .date = entity.date },
.song => TableRow{ .song = .{ .name = entity.name, .id = entity.id }, .artistlist = try artist_list.toOwnedSlice(), .scrobbles = entity.scrobbles },
.album => TableRow{ .album = .{ .name = entity.name, .id = entity.id }, .artistlist = try artist_list.toOwnedSlice(), .scrobbles = entity.scrobbles },
break :album_entities TableRow{ .album = .{ .name = entity.name, .id = entity.id }, .artistlist = try artist_list.toOwnedSlice(), .scrobbles = entity.scrobbles };
},
.song => song_entities: {
const last_artist = artist_list.getLastOrNull();
try artist_list.append(.{ .name = entity.artist_name, .id = entity.artist_id });
if (last_artist) |la| {
if (la.id == entity.artist_id) continue :blk;
}
break :song_entities TableRow{ .song = .{ .name = entity.name, .id = entity.id }, .artistlist = try artist_list.toOwnedSlice(), .scrobbles = entity.scrobbles };
},
else => unreachable,
};
},
},
EntityItemsResult, EntityItemsSongResult => switch (query.entity) {
.song => TableRow{ .song = .{ .name = entity.song_name, .id = entity.song_id }, .album = .{ .name = entity.album_name, .id = entity.album_id }, .date = entity.date },
EntityItemsResult => switch (query.entity) {
.artist => TableRow{ .album = .{ .name = entity.name, .id = entity.id }, .scrobbles = entity.scrobbles },
.album => TableRow{ .song = .{ .name = entity.name, .id = entity.id }, .scrobbles = entity.scrobbles },
else => unreachable,
@ -89,21 +92,10 @@ const TimescaleResult = struct { year: []const u8, scrobbles: i64 };
const EntitiesArtistResult = struct { name: []const u8, id: i32, scrobbles: i64 };
const EntitiesAlbumResult = struct { name: []const u8, id: i32, artist_name: []const u8, artist_id: i32, scrobbles: i64 };
const EntitiesSongResult = struct { name: []const u8, id: i32, artist_name: []const u8, artist_id: i32, scrobbles: i64 };
const EntitiesScrobbleResult = struct { song_name: []const u8, song_id: i32, album_name: []const u8, album_id: i32, artist_name: []const u8, artist_id: i32, date: []const u8 };
const EntitiesScrobbleResult = struct { song_name: []const u8, song_id: i32, album_name: []const u8, album_id: i32, artist_name: []const u8, artist_id: i32, s_id: i32, date: i64 };
const EntityItemsResult = struct { name: []const u8, id: i32, scrobbles: i64 };
const AppearsResult = struct { name: []const u8, id: i32, scrobbles: i64 };
const EntityInfoResult = struct { name: []const u8, id: i32, scrobbles: i64, rank: []const u8 };
const EntityItemsSongResult = struct { song_name: []const u8, song_id: i32, album_name: []const u8, album_id: i32, date: []const u8 };
const UnifiedResult = struct {
album_name: ?[]const u8 = null,
album_id: ?i32 = null,
song_name: ?[]const u8 = null,
song_id: ?i32 = null,
artist_names: ?[]const []const u8 = null,
artist_ids: ?[]i32 = null,
scrobbles: ?i64 = null,
date: ?[]const u8 = null,
};
pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQuery {
return GeneratedQuery{
@ -118,11 +110,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
.album => EntitiesAlbumResult,
.artist => EntitiesArtistResult,
},
.entity_items => switch (entity) {
.scrobble => unreachable,
.song => EntityItemsSongResult,
else => EntityItemsResult,
},
.entity_items => EntityItemsResult,
.appears => AppearsResult,
.entity_info => EntityInfoResult,
},
@ -132,49 +120,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
switch (entity) {
.scrobble => unreachable,
.song =>
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime,'YYYY-MM-DD HH24:MI:SS') AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\WHERE albumsongs.song_id = $1
\\ORDER BY scrobbles.datetime ASC
\\LIMIT 1)
\\
\\UNION ALL
\\
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\WHERE albumsongs.song_id = $1
\\ORDER BY scrobbles.datetime DESC
\\LIMIT 1)
,
.album =>
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\WHERE albums.id = $1
\\ORDER BY scrobbles.datetime ASC
\\LIMIT 1)
\\
\\UNION ALL
\\
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\WHERE albums.id = $1
\\ORDER BY scrobbles.datetime DESC
\\LIMIT 1)
,
.artist =>
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date
\\(SELECT songs.name AS name, songs.id AS id, scrobbles.datetime AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
@ -185,7 +131,51 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
\\
\\UNION ALL
\\
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date
\\(SELECT songs.name AS name, songs.id AS id, scrobbles.datetime AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
\\WHERE albumsongsartists.artist_id = $1
\\ORDER BY scrobbles.datetime DESC
\\LIMIT 1)
,
.album =>
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MM:SS') AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\WHERE albums.id = $1
\\ORDER BY scrobbles.datetime ASC
\\LIMIT 1)
\\
\\UNION ALL
\\
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MM:SS') AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\WHERE albums.id = $1
\\ORDER BY scrobbles.datetime DESC
\\LIMIT 1)
,
.artist =>
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MM:SS') AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
\\WHERE albumsongsartists.artist_id = $1
\\ORDER BY scrobbles.datetime ASC
\\LIMIT 1)
\\
\\UNION ALL
\\
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MM:SS') AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
@ -204,8 +194,9 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
\\SELECT TO_CHAR(date_trunc('year', datetime), 'YYYY') AS year, COUNT(*) as scrobbles
\\FROM scrobbles
\\INNER JOIN albumsongs ON albumsongs.id = scrobbles.albumsong
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\WHERE songs.id = $1
\\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
\\INNER JOIN artists ON artists.id = albumsongsartists.artist_id
\\WHERE artists.id = $1
\\GROUP BY year
\\ORDER BY year ASC;
,
@ -236,14 +227,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
//.ResultType = EntitiesResult,
switch (entity) {
.scrobble =>
\\SELECT songs.name AS song_name, songs.id AS song_id, albums.name AS album_name, albums.id AS album_id, artists.name AS artist_name, artists.id AS artist_id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
\\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
\\INNER JOIN artists ON artists.id = albumsongsartists.artist_id
\\ORDER BY scrobbles.datetime ASC
\\none
,
.song =>
\\SELECT songs.name, songs.id, artists.name, artists.id, COUNT(scrobbles) AS scrobbles
@ -281,21 +265,13 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
switch (entity) {
.scrobble => unreachable,
.song =>
\\SELECT albums.name AS album_name, albums.id AS album_id, COUNT(scrobbles) AS scrobbles
\\FROM artistalbums
\\INNER JOIN albums ON albums.id = artistalbums.album_id
\\INNER JOIN albumsongs ON albumsongs.album_id = albums.id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
\\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
\\WHERE albumsongs.song_id = $1
\\GROUP BY albums.id
\\ORDER BY scrobbles DESC;
\\ NOTHING YET
,
.album =>
\\nope
,
.artist =>
\\SELECT albums.name AS album_name, albums.id AS album_id, COUNT(scrobbles) AS scrobbles
\\SELECT albums.name AS name, albums.id AS id, COUNT(scrobbles) AS scrobbles
\\FROM artistalbums
\\INNER JOIN albums ON albums.id = artistalbums.album_id
\\INNER JOIN albumsongs ON albumsongs.album_id = albums.id
@ -312,13 +288,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
switch (entity) {
.scrobble => unreachable,
.song =>
\\SELECT songs.name, songs.id, albums.name, albums.id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date
\\FROM albumsongs
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
\\WHERE songs.id = $1
\\ORDER BY date ASC
\\get all scrobbles
,
.album =>
\\SELECT songs.name, songs.id, COUNT(scrobbles) AS scrobbles
@ -344,19 +314,12 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
.entity_info => switch (entity) {
.scrobble => unreachable,
.song =>
\\SELECT * FROM
\\(SELECT *, TO_CHAR(ROW_NUMBER() OVER (ORDER BY scrobbles DESC),'FM99999th') AS rank FROM
\\(SELECT songs.name AS name, songs.id AS id, COUNT(scrobbles) AS scrobbles
\\FROM albumsongs
\\INNER JOIN songs ON albumsongs.song_id = songs.id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
\\GROUP BY songs.id))
\\WHERE id = $1
\\lol idk
,
.album =>
\\SELECT * FROM
\\(SELECT *, TO_CHAR(ROW_NUMBER() OVER (ORDER BY scrobbles DESC),'FM9999th') AS rank FROM
\\(SELECT albums.name AS name, albums.id AS id, COUNT(scrobbles) AS scrobbles
\\(SELECT albums.name, albums.id, COUNT(scrobbles) AS scrobbles
\\FROM albumsongs
\\INNER JOIN albums ON albumsongs.album_id = albums.id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
@ -375,26 +338,6 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
\\WHERE id = $1
,
},
.datestreak => switch (entity) {
.song =>
\\SELECT songs.name, albums.name, streak.maxseq, streak.ds, streak.de FROM (SELECT albumsong, MAX(numdays) AS maxseq, ds, de
\\FROM (SELECT albumsong, grp, MIN(datetime::date) AS ds, MAX(datetime::date) AS de,
\\COUNT(DISTINCT datetime::date) AS numdays
\\FROM (SELECT scrobbles.*,
\\((datetime::date - '1970-01-01'::date) - DENSE_RANK() OVER (PARTITION BY albumsong ORDER BY datetime::date)) AS grp
\\FROM scrobbles
\\) scrobbles
\\GROUP BY albumsong, grp
\\) scrobbles
\\GROUP BY albumsong, ds, de) AS streak
\\INNER JOIN albumsongs ON albumsongs.id = streak.albumsong
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\ORDER BY streak.maxseq DESC;
,
else => unreachable,
},
},
};
}