diff --git a/src/app/views/songs.zig b/src/app/views/songs.zig
index d5a7944..3143f01 100644
--- a/src/app/views/songs.zig
+++ b/src/app/views/songs.zig
@@ -12,6 +12,21 @@ pub fn index(request: *jetzig.Request) !jetzig.View {
}
pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View {
- _ = id;
+ 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);
return request.render(.ok);
}
diff --git a/src/app/views/songs/get.zmpl b/src/app/views/songs/get.zmpl
index 76457d0..0a051a4 100644
--- a/src/app/views/songs/get.zmpl
+++ b/src/app/views/songs/get.zmpl
@@ -1,3 +1,19 @@
-
- Content goes here
-
+@zig {
+ const ColumnChoices = []const enum{song, album, artist, artistlist, scrobbles, date};
+ const columns: ColumnChoices = &.{.song, .artistlist, .album, .date};
+}
+
+
+
+
+
+
+@partial partials/header
+{{.song}}
+@partial partials/firstlast_listens(scrobbles: .song.scrobbles, rank: .song.rank, firstlast: .firstlast)
+Yearly Performance
+@partial partials/timescale(range: .yearly)
+Scrobbles
+@partial partials/newtable(T: ColumnChoices, table_data: .scrobbles, columns: columns)
+
+
\ No newline at end of file
diff --git a/src/queries.zig b/src/queries.zig
index faba14d..061b5b3 100644
--- a/src/queries.zig
+++ b/src/queries.zig
@@ -20,7 +20,7 @@ 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 => |T| {
+ FirstlastResult, TimescaleResult, EntitiesScrobbleResult, EntitiesSongResult, EntitiesAlbumResult, EntitiesArtistResult, EntityItemsResult, AppearsResult, EntityInfoResult, EntityItemsSongResult => |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) {
@@ -39,7 +39,8 @@ pub fn entityQueryResult(request: *jetzig.Request, query: GeneratedQuery, args:
};
},
},
- EntityItemsResult => switch (query.entity) {
+ 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 },
.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,
@@ -92,6 +93,17 @@ const EntitiesScrobbleResult = struct { song_name: []const u8, song_id: i32, alb
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{
@@ -106,7 +118,11 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
.album => EntitiesAlbumResult,
.artist => EntitiesArtistResult,
},
- .entity_items => EntityItemsResult,
+ .entity_items => switch (entity) {
+ .scrobble => unreachable,
+ .song => EntityItemsSongResult,
+ else => EntityItemsResult,
+ },
.appears => AppearsResult,
.entity_info => EntityInfoResult,
},
@@ -116,23 +132,21 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
switch (entity) {
.scrobble => unreachable,
.song =>
- \\(SELECT songs.name AS name, songs.id AS id, scrobbles.datetime AS date
+ \\(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 albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
- \\WHERE albumsongsartists.artist_id = $1
+ \\WHERE albumsongs.song_id = $1
\\ORDER BY scrobbles.datetime ASC
\\LIMIT 1)
\\
\\UNION ALL
\\
- \\(SELECT songs.name AS name, songs.id AS id, scrobbles.datetime AS date
+ \\(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 albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
- \\WHERE albumsongsartists.artist_id = $1
+ \\WHERE albumsongs.song_id = $1
\\ORDER BY scrobbles.datetime DESC
\\LIMIT 1)
,
@@ -190,9 +204,8 @@ 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 albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
- \\INNER JOIN artists ON artists.id = albumsongsartists.artist_id
- \\WHERE artists.id = $1
+ \\INNER JOIN songs ON songs.id = albumsongs.song_id
+ \\WHERE songs.id = $1
\\GROUP BY year
\\ORDER BY year ASC;
,
@@ -268,13 +281,21 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
switch (entity) {
.scrobble => unreachable,
.song =>
- \\ NOTHING YET
+ \\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;
,
.album =>
\\nope
,
.artist =>
- \\SELECT albums.name AS name, albums.id AS id, COUNT(scrobbles) AS scrobbles
+ \\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
@@ -291,7 +312,13 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
switch (entity) {
.scrobble => unreachable,
.song =>
- \\get all scrobbles
+ \\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
,
.album =>
\\SELECT songs.name, songs.id, COUNT(scrobbles) AS scrobbles
@@ -317,12 +344,19 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
.entity_info => switch (entity) {
.scrobble => unreachable,
.song =>
- \\lol idk
+ \\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
,
.album =>
\\SELECT * FROM
\\(SELECT *, TO_CHAR(ROW_NUMBER() OVER (ORDER BY scrobbles DESC),'FM9999th') AS rank FROM
- \\(SELECT albums.name, albums.id, COUNT(scrobbles) AS scrobbles
+ \\(SELECT albums.name AS name, albums.id AS id, COUNT(scrobbles) AS scrobbles
\\FROM albumsongs
\\INNER JOIN albums ON albumsongs.album_id = albums.id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
@@ -341,6 +375,26 @@ 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,
+ },
},
};
}