Switch to using newtable partial for all tables
Will be renamed eventually, don't care right now. Also cleans up a lot of code I wasn't particularly happy about
This commit is contained in:
parent
153ea869e0
commit
365b9dbf11
10 changed files with 128 additions and 166 deletions
|
|
@ -17,8 +17,8 @@
|
||||||
// internet connectivity.
|
// internet connectivity.
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.jetzig = .{
|
.jetzig = .{
|
||||||
.url = "https://github.com/jetzig-framework/jetzig/archive/a298192bb0cddf9c45d7d0d976a9852804457de2.tar.gz",
|
.url = "https://github.com/jetzig-framework/jetzig/archive/7be1d137fcab5c422e05f12092f6e04a02900d6f.tar.gz",
|
||||||
.hash = "jetzig-0.0.0-IpAgLf5aDwB4UOKMhIjtK22zBsPfbWEwCYgHT0hayyT-",
|
.hash = "jetzig-0.0.0-IpAgLURbDwB1NlywUH7lnQ3zptNvSQWVosaA1k7l1cNz",
|
||||||
},
|
},
|
||||||
.zeit = .{
|
.zeit = .{
|
||||||
.url = "https://github.com/rockorager/zeit/archive/refs/tags/v0.6.0.tar.gz",
|
.url = "https://github.com/rockorager/zeit/archive/refs/tags/v0.6.0.tar.gz",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const jetzig = @import("jetzig");
|
const jetzig = @import("jetzig");
|
||||||
const jetquery = @import("jetzig").jetquery;
|
const jetquery = @import("jetzig").jetquery;
|
||||||
|
const TableRow = @import("../../types.zig").TableRows;
|
||||||
|
const HyperlinkData = @import("../../types.zig").HyperlinkData;
|
||||||
|
|
||||||
pub fn index(request: *jetzig.Request) !jetzig.View {
|
pub fn index(request: *jetzig.Request) !jetzig.View {
|
||||||
var root = try request.data(.object);
|
var root = try request.data(.object);
|
||||||
|
|
@ -22,28 +24,26 @@ pub fn index(request: *jetzig.Request) !jetzig.View {
|
||||||
const Album = struct { name: []const u8, id: i32, artist_name: []const u8, artist_id: i32, scrobbles: i64 };
|
const Album = struct { name: []const u8, id: i32, artist_name: []const u8, artist_id: i32, scrobbles: i64 };
|
||||||
|
|
||||||
var prev_album_id: ?i32 = null;
|
var prev_album_id: ?i32 = null;
|
||||||
var prev_artist_infos: ?*jetzig.zmpl.Data.Value = null;
|
|
||||||
|
var row: ?TableRow = null;
|
||||||
|
var artistlist = std.ArrayList(HyperlinkData).init(request.allocator);
|
||||||
|
|
||||||
blk: while (try albums_jq_result.postgresql.result.next()) |album_row| {
|
blk: while (try albums_jq_result.postgresql.result.next()) |album_row| {
|
||||||
const album = try album_row.to(Album, .{ .dupe = true, .allocator = request.allocator });
|
const album = try album_row.to(Album, .{ .dupe = true, .allocator = request.allocator });
|
||||||
if (album.id == prev_album_id) {
|
if (album.id == prev_album_id) {
|
||||||
var artist_info = try prev_artist_infos.?.append(.object);
|
try artistlist.append(.{ .name = album.artist_name, .id = album.artist_id });
|
||||||
try artist_info.put("name", album.artist_name);
|
|
||||||
try artist_info.put("id", album.artist_id);
|
|
||||||
continue :blk;
|
continue :blk;
|
||||||
|
} else {
|
||||||
|
try artistlist.append(.{ .name = album.artist_name, .id = album.artist_id });
|
||||||
|
|
||||||
|
row = TableRow{
|
||||||
|
.album = .{ .name = album.name, .id = album.id },
|
||||||
|
.artistlist = try artistlist.toOwnedSlice(),
|
||||||
|
.scrobbles = album.scrobbles,
|
||||||
|
};
|
||||||
|
|
||||||
|
try albums_view.append(row);
|
||||||
}
|
}
|
||||||
var album_view = try albums_view.append(.object);
|
|
||||||
|
|
||||||
try album_view.put("name", album.name);
|
|
||||||
try album_view.put("id", album.id);
|
|
||||||
try album_view.put("scrobbles", album.scrobbles);
|
|
||||||
|
|
||||||
var artist_infos = try album_view.put("artist_info", .array);
|
|
||||||
var artist_info = try artist_infos.append(.object);
|
|
||||||
try artist_info.put("name", album.artist_name);
|
|
||||||
try artist_info.put("id", album.artist_id);
|
|
||||||
|
|
||||||
prev_artist_infos = artist_infos;
|
|
||||||
prev_album_id = album.id;
|
prev_album_id = album.id;
|
||||||
}
|
}
|
||||||
return request.render(.ok);
|
return request.render(.ok);
|
||||||
|
|
@ -72,10 +72,12 @@ pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View {
|
||||||
|
|
||||||
while (try songs_js_result.postgresql.result.next()) |song_row| {
|
while (try songs_js_result.postgresql.result.next()) |song_row| {
|
||||||
const song = try song_row.to(Song, .{ .dupe = true, .allocator = request.allocator });
|
const song = try song_row.to(Song, .{ .dupe = true, .allocator = request.allocator });
|
||||||
var song_view = try songs_view.append(.object);
|
const row = TableRow{
|
||||||
try song_view.put("name", song.name);
|
.song = .{ .name = song.name, .id = song.id },
|
||||||
try song_view.put("id", song.id);
|
.scrobbles = song.scrobbles,
|
||||||
try song_view.put("scrobbles", song.scrobbles);
|
};
|
||||||
|
|
||||||
|
try songs_view.append(row);
|
||||||
}
|
}
|
||||||
return request.render(.ok);
|
return request.render(.ok);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const jetzig = @import("jetzig");
|
const jetzig = @import("jetzig");
|
||||||
const jetquery = @import("jetzig").jetquery;
|
const jetquery = @import("jetzig").jetquery;
|
||||||
|
const TableRow = @import("../../types.zig").TableRows;
|
||||||
const dateFmt = @import("../../date_fmt.zig").dateFmt;
|
const dateFmt = @import("../../date_fmt.zig").dateFmt;
|
||||||
const ordinalFmt = @import("../../ordinal_fmt.zig").ordinalFmt;
|
const ordinalFmt = @import("../../ordinal_fmt.zig").ordinalFmt;
|
||||||
|
|
||||||
|
|
@ -25,10 +26,12 @@ pub fn index(request: *jetzig.Request) !jetzig.View {
|
||||||
|
|
||||||
while (try artists_jq_result.postgresql.result.next()) |artist_row| {
|
while (try artists_jq_result.postgresql.result.next()) |artist_row| {
|
||||||
const artist = try artist_row.to(Artist, .{ .dupe = true, .allocator = request.allocator });
|
const artist = try artist_row.to(Artist, .{ .dupe = true, .allocator = request.allocator });
|
||||||
var artist_view = try artists_view.append(.object);
|
const row = TableRow{
|
||||||
try artist_view.put("name", artist.name);
|
.artist = .{ .name = artist.name, .id = artist.id },
|
||||||
try artist_view.put("url", artist.id);
|
.scrobbles = artist.scrobbles,
|
||||||
try artist_view.put("scrobbles", artist.scrobbles);
|
};
|
||||||
|
|
||||||
|
try artists_view.append(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
return request.render(.ok);
|
return request.render(.ok);
|
||||||
|
|
@ -84,7 +87,12 @@ pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View {
|
||||||
|
|
||||||
while (try albums_jq_result.postgresql.result.next()) |album_row| {
|
while (try albums_jq_result.postgresql.result.next()) |album_row| {
|
||||||
const album = try album_row.to(AlbumsResult, .{ .dupe = true, .allocator = request.allocator });
|
const album = try album_row.to(AlbumsResult, .{ .dupe = true, .allocator = request.allocator });
|
||||||
try albums_view.append(album);
|
const album_table_row = TableRow{
|
||||||
|
.album = .{ .name = album.name, .id = album.id },
|
||||||
|
.scrobbles = album.scrobbles,
|
||||||
|
};
|
||||||
|
|
||||||
|
try albums_view.append(album_table_row);
|
||||||
}
|
}
|
||||||
//albums_jq_result.drain();
|
//albums_jq_result.drain();
|
||||||
|
|
||||||
|
|
@ -107,7 +115,12 @@ pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View {
|
||||||
|
|
||||||
while (try appears_jq_result.postgresql.result.next()) |appears_row| {
|
while (try appears_jq_result.postgresql.result.next()) |appears_row| {
|
||||||
const appears = try appears_row.to(AlbumsResult, .{ .dupe = true, .allocator = request.allocator });
|
const appears = try appears_row.to(AlbumsResult, .{ .dupe = true, .allocator = request.allocator });
|
||||||
try appears_view.append(appears);
|
const appears_table_row = TableRow{
|
||||||
|
.album = .{ .name = appears.name, .id = appears.id },
|
||||||
|
.scrobbles = appears.scrobbles,
|
||||||
|
};
|
||||||
|
|
||||||
|
try appears_view.append(appears_table_row);
|
||||||
}
|
}
|
||||||
|
|
||||||
//appears_jq_result.drain();
|
//appears_jq_result.drain();
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,15 @@
|
||||||
|
@zig {
|
||||||
|
const ColumnChoices = []const enum{song, album, artist, artistlist, scrobbles, date};
|
||||||
|
const columns: ColumnChoices = &.{.artist, .scrobbles};
|
||||||
|
}
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
|
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@partial partials/header
|
@partial partials/header
|
||||||
<h1>Artists</h1>
|
<h1>Artists</h1>
|
||||||
<table id="myTable" class='table'>
|
@partial partials/newtable(T: ColumnChoices, table_data: .artists, columns: columns)
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Scrobbles</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@for (.artists) |artist| {
|
|
||||||
<tr>
|
|
||||||
<td class=cell><a href="/artists/{{artist.url}}">{{artist.name}}</a></td>
|
|
||||||
<td class=cell>{{artist.scrobbles}}</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest" type="text/javascript"></script>
|
|
||||||
<script>
|
|
||||||
const dataTable = new simpleDatatables.DataTable("#myTable", {
|
|
||||||
searchable: true,
|
|
||||||
perPage: 50,
|
|
||||||
perPageSelect: [25,50,100],
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -32,33 +32,37 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
@zig {
|
@zig {
|
||||||
const array = table_data.items(.array);
|
const array = table_data.items(.array);
|
||||||
for (array) |ent| {
|
for (array) |row| {
|
||||||
<tr>
|
<tr>
|
||||||
for (columns) |header| {
|
for (columns) |header| {
|
||||||
switch (header) {
|
switch (header) {
|
||||||
.song, .album, .artist => {
|
.song => {
|
||||||
const path = switch (header) {
|
|
||||||
.song => "songs",
|
|
||||||
.album => "albums",
|
|
||||||
.artist => "artists",
|
|
||||||
else => unreachable
|
|
||||||
};
|
|
||||||
<td class=cell>
|
<td class=cell>
|
||||||
<a href="/{{path}}/{{ent.id}}">{{ent.name}}</a>
|
<a href="/songs/{{row.song.id}}">{{row.song.name}}</a>
|
||||||
|
</td>
|
||||||
|
},
|
||||||
|
.album => {
|
||||||
|
<td class=cell>
|
||||||
|
<a href="/albums/{{row.album.id}}">{{row.album.name}}</a>
|
||||||
|
</td>
|
||||||
|
},
|
||||||
|
.artist => {
|
||||||
|
<td class=cell>
|
||||||
|
<a href="/artists/{{row.artist.id}}">{{row.artist.name}}</a>
|
||||||
</td>
|
</td>
|
||||||
},
|
},
|
||||||
.artistlist => {
|
.artistlist => {
|
||||||
<td class=cell>
|
<td class=cell>
|
||||||
@for (ent.get("artist_info").?) |artist| {
|
@for (row.get("artistlist").?) |artist| {
|
||||||
<a href="/artists/{{artist.id}}">{{artist.name}}</a>
|
<a href="/artists/{{artist.id}}">{{artist.name}}</a>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
},
|
},
|
||||||
.scrobbles => {
|
.scrobbles => {
|
||||||
<td class=cell>{{ent.scrobbles}}</td>
|
<td class=cell>{{row.scrobbles}}</td>
|
||||||
},
|
},
|
||||||
.date =>{
|
.date =>{
|
||||||
<td class=cell>{{ent.date}}</td>
|
<td class=cell>{{row.date}}</td>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const jetzig = @import("jetzig");
|
const jetzig = @import("jetzig");
|
||||||
const zeit = @import("zeit");
|
const zeit = @import("zeit");
|
||||||
|
const TableRow = @import("../../types.zig").TableRows;
|
||||||
|
const HyperlinkData = @import("../../types.zig").HyperlinkData;
|
||||||
|
|
||||||
pub fn index(request: *jetzig.Request) !jetzig.View {
|
pub fn index(request: *jetzig.Request) !jetzig.View {
|
||||||
var root = try request.data(.object);
|
var root = try request.data(.object);
|
||||||
|
|
@ -23,33 +25,30 @@ pub fn index(request: *jetzig.Request) !jetzig.View {
|
||||||
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 };
|
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 prev_s_id: ?i32 = null;
|
||||||
var prev_artist_infos: ?*jetzig.zmpl.Data.Value = null;
|
|
||||||
|
var row: ?TableRow = null;
|
||||||
|
var artistlist = std.ArrayList(HyperlinkData).init(request.allocator);
|
||||||
|
|
||||||
blk: while (try scrobbles_jq_result.postgresql.result.next()) |scrobble_row| {
|
blk: while (try scrobbles_jq_result.postgresql.result.next()) |scrobble_row| {
|
||||||
const scrobble = try scrobble_row.to(Scrobble, .{ .dupe = true, .allocator = request.allocator });
|
const scrobble = try scrobble_row.to(Scrobble, .{ .dupe = true, .allocator = request.allocator });
|
||||||
if (scrobble.s_id == prev_s_id) {
|
if (scrobble.s_id == prev_s_id) {
|
||||||
var artist_info = try prev_artist_infos.?.append(.object);
|
try artistlist.append(.{ .name = scrobble.artist_name, .id = scrobble.artist_id });
|
||||||
try artist_info.put("name", scrobble.artist_name);
|
|
||||||
try artist_info.put("url", scrobble.artist_id);
|
|
||||||
continue :blk;
|
continue :blk;
|
||||||
}
|
} else {
|
||||||
// Not appending the scrobble directly because we don't want the unix timestamp or scrobble id
|
|
||||||
var scrobble_view = try scrobbles_view.append(.object);
|
|
||||||
|
|
||||||
var artist_infos = try scrobble_view.put("artist_info", .array);
|
|
||||||
var artist_info = try artist_infos.append(.object);
|
|
||||||
try artist_info.put("name", scrobble.artist_name);
|
|
||||||
try artist_info.put("url", scrobble.artist_id);
|
|
||||||
|
|
||||||
try scrobble_view.put("song_name", scrobble.song_name);
|
|
||||||
try scrobble_view.put("song_id", scrobble.song_id);
|
|
||||||
try scrobble_view.put("album_name", scrobble.album_name);
|
|
||||||
try scrobble_view.put("album_id", scrobble.album_id);
|
|
||||||
var date = std.ArrayList(u8).init(request.allocator);
|
var date = std.ArrayList(u8).init(request.allocator);
|
||||||
try (try zeit.instant(.{ .source = .{ .unix_timestamp = @divFloor(scrobble.date, 1_000) } })).time().strftime(date.writer(), "%d %b %Y, %H:%M");
|
try (try zeit.instant(.{ .source = .{ .unix_timestamp = @divFloor(scrobble.date, 1_000) } })).time().strftime(date.writer(), "%d %b %Y, %H:%M");
|
||||||
try scrobble_view.put("date", date.items);
|
|
||||||
|
|
||||||
prev_artist_infos = artist_infos;
|
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.items,
|
||||||
|
};
|
||||||
|
|
||||||
|
try scrobbles_view.append(row);
|
||||||
|
}
|
||||||
prev_s_id = scrobble.s_id;
|
prev_s_id = scrobble.s_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,15 @@
|
||||||
|
@zig {
|
||||||
|
const ColumnChoices = []const enum{song, album, artist, artistlist, scrobbles, date};
|
||||||
|
const columns: ColumnChoices = &.{.song, .artistlist, .album, .date};
|
||||||
|
}
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
|
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@partial partials/header
|
@partial partials/header
|
||||||
<h1>Scrobbles</h1>
|
<h1>Scrobbles</h1>
|
||||||
<table id="myTable">
|
@partial partials/newtable(T: ColumnChoices, table_data: .scrobbles, columns: columns)
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Song</th>
|
|
||||||
<th>Artist(s)</th>
|
|
||||||
<th>Album</th>
|
|
||||||
<th data-type="date" data-format="DD MMM YYYY, HH:mm">Date</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@for (.scrobbles) |scrobble| {
|
|
||||||
<tr>
|
|
||||||
<td class=cell><a href="/songs/{{scrobble.song_id}}">{{scrobble.song_name}}</a></td>
|
|
||||||
<td class=cell>
|
|
||||||
@for (scrobble.get("artist_info").?) |ai| {
|
|
||||||
<a href="/artists/{{ai.url}}">{{ai.name}}</a>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
<td class=cell><a href="/albums/{{scrobble.album_id}}">{{scrobble.album_name}}</a></td>
|
|
||||||
<td class=cell>{{scrobble.date}}</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest" type="text/javascript"></script>
|
|
||||||
<script>
|
|
||||||
const dataTable = new simpleDatatables.DataTable("#myTable", {
|
|
||||||
searchable: true,
|
|
||||||
perPage: 50,
|
|
||||||
perPageSelect: [25,50,100],
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const jetzig = @import("jetzig");
|
const jetzig = @import("jetzig");
|
||||||
|
const TableRow = @import("../../types.zig").TableRows;
|
||||||
|
const HyperlinkData = @import("../../types.zig").HyperlinkData;
|
||||||
|
|
||||||
pub fn index(request: *jetzig.Request) !jetzig.View {
|
pub fn index(request: *jetzig.Request) !jetzig.View {
|
||||||
var root = try request.data(.object);
|
var root = try request.data(.object);
|
||||||
|
|
@ -22,28 +24,26 @@ pub fn index(request: *jetzig.Request) !jetzig.View {
|
||||||
const Song = struct { name: []const u8, id: i32, artist_name: []const u8, artist_id: i32, scrobbles: i64 };
|
const Song = struct { name: []const u8, id: i32, artist_name: []const u8, artist_id: i32, scrobbles: i64 };
|
||||||
|
|
||||||
var prev_song_id: ?i32 = null;
|
var prev_song_id: ?i32 = null;
|
||||||
var prev_artist_infos: ?*jetzig.zmpl.Data.Value = null;
|
|
||||||
|
var row: ?TableRow = null;
|
||||||
|
var artistlist = std.ArrayList(HyperlinkData).init(request.allocator);
|
||||||
|
|
||||||
blk: while (try songs_js_result.postgresql.result.next()) |song_row| {
|
blk: while (try songs_js_result.postgresql.result.next()) |song_row| {
|
||||||
const song = try song_row.to(Song, .{ .dupe = true, .allocator = request.allocator });
|
const song = try song_row.to(Song, .{ .dupe = true, .allocator = request.allocator });
|
||||||
if (song.id == prev_song_id) {
|
if (song.id == prev_song_id) {
|
||||||
var artist_info = try prev_artist_infos.?.append(.object);
|
try artistlist.append(.{ .name = song.artist_name, .id = song.artist_id });
|
||||||
try artist_info.put("name", song.artist_name);
|
|
||||||
try artist_info.put("url", song.artist_id);
|
|
||||||
continue :blk;
|
continue :blk;
|
||||||
|
} else {
|
||||||
|
try artistlist.append(.{ .name = song.artist_name, .id = song.artist_id });
|
||||||
|
|
||||||
|
row = TableRow{
|
||||||
|
.song = .{ .name = song.name, .id = song.id },
|
||||||
|
.artistlist = try artistlist.toOwnedSlice(),
|
||||||
|
.scrobbles = song.scrobbles,
|
||||||
|
};
|
||||||
|
|
||||||
|
try songs_view.append(row);
|
||||||
}
|
}
|
||||||
var song_view = try songs_view.append(.object);
|
|
||||||
|
|
||||||
var artist_infos = try song_view.put("artist_info", .array);
|
|
||||||
var artist_info = try artist_infos.append(.object);
|
|
||||||
try artist_info.put("name", song.artist_name);
|
|
||||||
try artist_info.put("url", song.artist_id);
|
|
||||||
|
|
||||||
try song_view.put("name", song.name);
|
|
||||||
try song_view.put("url", song.id);
|
|
||||||
try song_view.put("scrobbles", song.scrobbles);
|
|
||||||
|
|
||||||
prev_artist_infos = artist_infos;
|
|
||||||
prev_song_id = song.id;
|
prev_song_id = song.id;
|
||||||
}
|
}
|
||||||
return request.render(.ok);
|
return request.render(.ok);
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,15 @@
|
||||||
|
@zig {
|
||||||
|
const ColumnChoices = []const enum{song, album, artist, artistlist, scrobbles, date};
|
||||||
|
const columns: ColumnChoices = &.{.song, .artistlist, .scrobbles};
|
||||||
|
}
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
|
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@partial partials/header
|
@partial partials/header
|
||||||
<h1>Songs</h1>
|
<h1>Songs</h1>
|
||||||
<table id="myTable">
|
@partial partials/newtable(T: ColumnChoices, table_data: .songs, columns: columns)
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Artist(s)</th>
|
|
||||||
<th>Scrobbles</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@for (.songs) |song| {
|
|
||||||
<tr>
|
|
||||||
<td class=cell><a href="/songs/{{song.url}}">{{song.name}}</a></td>
|
|
||||||
<td class=cell>
|
|
||||||
@for (song.get("artist_info").?) |ai| {
|
|
||||||
<a href="/artists/{{ai.url}}">{{ai.name}}</a>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
<td class=cell>{{song.scrobbles}}</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest" type="text/javascript"></script>
|
|
||||||
<script>
|
|
||||||
const dataTable = new simpleDatatables.DataTable("#myTable", {
|
|
||||||
searchable: true,
|
|
||||||
perPage: 50,
|
|
||||||
perPageSelect: [25,50,100],
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -72,3 +72,18 @@ pub const Rules = struct {
|
||||||
// scrobbles,
|
// scrobbles,
|
||||||
// date,
|
// date,
|
||||||
//};
|
//};
|
||||||
|
//
|
||||||
|
|
||||||
|
pub const TableRows = struct {
|
||||||
|
song: ?HyperlinkData = null,
|
||||||
|
album: ?HyperlinkData = null,
|
||||||
|
artist: ?HyperlinkData = null,
|
||||||
|
artistlist: ?[]HyperlinkData = null,
|
||||||
|
scrobbles: ?i64 = null,
|
||||||
|
date: ?[]const u8 = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const HyperlinkData = struct {
|
||||||
|
name: []const u8,
|
||||||
|
id: i32,
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue