Compare commits
10 commits
199dc0ca49
...
fa4c3a6eff
| Author | SHA1 | Date | |
|---|---|---|---|
| fa4c3a6eff | |||
| 8f34815904 | |||
| 75a63a19fc | |||
| 2b22cbe6c1 | |||
| 62ec4dc3ab | |||
| 894e562400 | |||
| ee855dde18 | |||
| dc959607f9 | |||
| f1f1072a18 | |||
| 46f0b5038c |
20 changed files with 184 additions and 70 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -3,4 +3,4 @@ zig-cache/
|
|||
*.core
|
||||
static/
|
||||
.jetzig
|
||||
src/app/database/
|
||||
src/app/database/data.db-journal
|
||||
|
|
@ -28,7 +28,7 @@ pub fn build(b: *std.Build) !void {
|
|||
|
||||
// All dependencies **must** be added to imports above this line.
|
||||
|
||||
try jetzig.jetzigInit(b, exe, .{.zmpl_version = .v2});
|
||||
try jetzig.jetzigInit(b, exe, .{ .zmpl_version = .v2 });
|
||||
|
||||
b.installArtifact(exe);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,20 +14,16 @@
|
|||
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
|
||||
// Once all dependencies are fetched, `zig build` no longer requires
|
||||
// internet connectivity.
|
||||
.dependencies = .{
|
||||
.jetzig = .{
|
||||
.url = "https://github.com/jetzig-framework/jetzig/archive/68ca4d3bbad05880e6e38fc6d10e7a24e772081e.tar.gz",
|
||||
.hash = "122047ebabab1dfe1bb7f96ffdac98410ffb4850b06dc6b1670ce74aaeaa49bdc08e",
|
||||
},
|
||||
.iguanas = .{
|
||||
.url = "https://github.com/jetzig-framework/iguanas/archive/89c2abf29de0bc31054a9a6feac5a6a83bab0459.tar.gz",
|
||||
.hash = "12202fd319a5ab4e124b00e8ddea474d07c19c4e005d77b6c29fc44860904ea01a5c",
|
||||
},
|
||||
.sqlite = .{
|
||||
.url = "https://github.com/vrischmann/zig-sqlite/archive/6af21bb.tar.gz",
|
||||
.hash = "12202799861d92c7880d1a74f95be099752d7f0420a0c9628dc923ca2b1a22b7bda8",
|
||||
}
|
||||
},
|
||||
.dependencies = .{ .jetzig = .{
|
||||
.url = "https://github.com/jetzig-framework/jetzig/archive/88abe2243d87b28ad110c5fe9fe90b716a6c6583.tar.gz",
|
||||
.hash = "12200d15cef72d4c37a01c930db53c3ffafdc05142462afddeab818701a0291327d1",
|
||||
}, .iguanas = .{
|
||||
.url = "https://github.com/jetzig-framework/iguanas/archive/89c2abf29de0bc31054a9a6feac5a6a83bab0459.tar.gz",
|
||||
.hash = "12202fd319a5ab4e124b00e8ddea474d07c19c4e005d77b6c29fc44860904ea01a5c",
|
||||
}, .sqlite = .{
|
||||
.url = "https://github.com/vrischmann/zig-sqlite/archive/6af21bb.tar.gz",
|
||||
.hash = "12202799861d92c7880d1a74f95be099752d7f0420a0c9628dc923ca2b1a22b7bda8",
|
||||
} },
|
||||
.paths = .{
|
||||
// This makes *all* files, recursively, included in this package. It is generally
|
||||
// better to explicitly list the files and directories instead, to insure that
|
||||
|
|
|
|||
|
|
@ -3,8 +3,23 @@
|
|||
* <link rel="stylesheet" href="/styles.css" />
|
||||
*
|
||||
*/
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');
|
||||
|
||||
.message {
|
||||
font-weight: bold;
|
||||
.title {
|
||||
font-family: 'Roboto';
|
||||
font-size: 3rem;
|
||||
font-weight: 500;
|
||||
margin-left: 20px;
|
||||
margin-right: 40px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.header-link{
|
||||
font-family: 'Roboto';
|
||||
font-size: 1.5rem;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
#replaceMe{
|
||||
font-family:'Courier New';
|
||||
}
|
||||
|
|
|
|||
BIN
src/app/database/data.db
Normal file
BIN
src/app/database/data.db
Normal file
Binary file not shown.
22
src/app/lib/db.zig
Normal file
22
src/app/lib/db.zig
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
pub const addArtist = \\INSERT INTO artists ('artist', 'plays', 'url') VALUES (?,?)
|
||||
;
|
||||
|
||||
pub const addTrack = \\INSERT INTO tracks ('artist', 'track', 'album', 'plays', 'url') VALUES (?,?,?,?)
|
||||
;
|
||||
|
||||
pub const getArtist = \\SELECT artist, plays FROM artists WHERE artist == ?
|
||||
;
|
||||
|
||||
pub const getTrack = \\SELECT artist, track, album, plays FROM tracks WHERE track == ?
|
||||
;
|
||||
|
||||
pub const getTrackSearch = \\SELECT track, url, form FROM tracks WHERE track LIKE '%' || ? || '%'
|
||||
;
|
||||
|
||||
pub const getArtistSearch = \\SELECT artist, url, form FROM artists WHERE artist LIKE '%' || ? || '%'
|
||||
;
|
||||
|
||||
pub const getAlbumSearch = \\SELECT album, url, form FROM albums WHERE album LIKE '%' || ? || '%'
|
||||
;
|
||||
|
||||
pub const total_search = getArtistSearch ++ " UNION " ++ getAlbumSearch ++ " UNION " ++ getTrackSearch;
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
const std = @import("std");
|
||||
const jetzig = @import("jetzig");
|
||||
|
||||
/// `src/app/views/root.zig` represents the root URL `/`
|
||||
|
|
@ -18,7 +19,7 @@ pub fn index(request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
|||
var root = try data.object();
|
||||
|
||||
// Add a string to the root object.
|
||||
try root.put("message", data.string("Welcome to Jetzig!"));
|
||||
try root.put("welcome_message", data.string("Welcome to Jetzig!"));
|
||||
|
||||
// Request params have the same type as a `data.object()` so they can be inserted them
|
||||
// directly into the response data. Fetch `http://localhost:8080/?message=hello` to set the
|
||||
|
|
@ -26,9 +27,7 @@ pub fn index(request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
|||
// present.
|
||||
const params = try request.params();
|
||||
|
||||
if (params.get("message")) |value| {
|
||||
try root.put("message_param", value);
|
||||
}
|
||||
try root.put("message_param", params.get("message"));
|
||||
|
||||
// Set arbitrary response headers as required. `content-type` is automatically assigned for
|
||||
// HTML, JSON responses.
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
<!--// Renders the `message` response data value.-->
|
||||
<h3 class="message text-[#39b54a]">{.message}</h3>
|
||||
|
||||
<div><img class="p-3 mx-auto" src="/jetzig.png" /></div>
|
||||
|
||||
<div>
|
||||
<a href="https://github.com/jetzig-framework/zmpl">
|
||||
<img class="p-3 m-3 mx-auto" src="/zmpl.png" />
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<div>Visit <a class="font-bold text-[#39b54a]" href="https://jetzig.dev/">jetzig.dev</a> to get started.
|
||||
<div>Join our Discord server and introduce yourself:</div>
|
||||
<div>
|
||||
<a class="font-bold text-[#39b54a]">Search for an artist, album, or song:</a>
|
||||
<input type="text" name="search" hx-include="[name='search']" hx-get="/test" hx-trigger="keyup[keyCode==13]">
|
||||
<button type="button" hx-include="[name='search']" hx-get="/test">You whattup</button>
|
||||
</div>
|
||||
</div>
|
||||
6
src/app/views/root/_header.zmpl
Normal file
6
src/app/views/root/_header.zmpl
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<b class="title text-[#123456]">Zuletzt</b>
|
||||
<a class="header-link" href="/artists">Artists</a>
|
||||
<a class="header-link" href="/albums">Albums</a>
|
||||
<a class="header-link" href="/tracks">Tracks</a>
|
||||
<a class="header-link" href="/stats">Stats</a>
|
||||
<hr>
|
||||
0
src/app/views/root/_history.zmpl
Normal file
0
src/app/views/root/_history.zmpl
Normal file
0
src/app/views/root/_random.zmpl
Normal file
0
src/app/views/root/_random.zmpl
Normal file
0
src/app/views/root/_recent.zmpl
Normal file
0
src/app/views/root/_recent.zmpl
Normal file
26
src/app/views/root/_top.zmpl
Normal file
26
src/app/views/root/_top.zmpl
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<div>
|
||||
<fieldset>
|
||||
Top:
|
||||
<input type="radio" label="Artist" name="q" value="artist" hx-get="/stats" hx-target="#update" hx-include="[name='t']" hx-swap="outerHTML" hx-trigger="click" checked>Artist</input>
|
||||
<input type="radio" label="Album" name="q" value="album" hx-get="/stats" hx-target="#update" hx-include="[name='t']" hx-swap="outerHTML" hx-trigger="click">Album</input>
|
||||
<input type="radio" label="Track" name="q" value="track" hx-get="/stats" hx-target="#update" hx-include="[name='t']" hx-swap="outerHTML" hx-trigger="click">Track</input>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
of:
|
||||
<input type="radio" label="Day" name="t" value="day" hx-get="/stats" hx-target="#update" hx-include="[name='q']" hx-swap="outerHTML" hx-trigger="click" checked>Day</input>
|
||||
<input type="radio" label="Week" name="t" value="week" hx-get="/stats" hx-target="#update" hx-include="[name='q']" hx-swap="outerHTML" hx-trigger="click">Week</input>
|
||||
<input type="radio" label="Month" name="t" value="month" hx-get="/stats" hx-target="#update" hx-include="[name='q']" hx-swap="outerHTML" hx-trigger="click">Month</input>
|
||||
<input type="radio" label="3 Months" name="t" value="quarter" hx-get="/stats" hx-target="#update" hx-include="[name='q']" hx-swap="outerHTML" hx-trigger="click">3 Months</input>
|
||||
<input type="radio" label="6 Months" name="t" value="half" hx-get="/stats" hx-target="#update" hx-include="[name='q']" hx-swap="outerHTML" hx-trigger="click">6 Months</input>
|
||||
<input type="radio" label="Current Year" name="t" value="begin" hx-get="/stats" hx-target="#update" hx-include="[name='q']" hx-swap="outerHTML" hx-trigger="click">Current Year</input>
|
||||
<input type="radio" label="365 Days" name="t" value="year" hx-get="/stats" hx-target="#update" hx-include="[name='q']" hx-swap="outerHTML" hx-trigger="click">365 days</input>
|
||||
<input type="radio" label="All Time" name="t" value="all" hx-get="/stats" hx-target="#update" hx-include="[name='q']" hx-swap="outerHTML" hx-trigger="click">All Time</input>
|
||||
</fieldset>
|
||||
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<b id="update">hyello</b>
|
||||
</td>
|
||||
</tr>
|
||||
</div>
|
||||
|
|
@ -8,15 +8,7 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<div class="text-center pt-10 m-auto">
|
||||
<!-- If present, renders the `message_param` response data value, add `?message=hello` to the
|
||||
// URL to see the output: -->
|
||||
<h2 class="param text-3xl text-[#f7931e]">{.message_param}</h2>
|
||||
|
||||
<!--// Renders `src/app/views/root/_content.zmpl` with the same template data available:-->
|
||||
<div>
|
||||
@partial root/content
|
||||
</div>
|
||||
</div>
|
||||
@partial root/header
|
||||
@partial root/top
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
52
src/app/views/search.zig
Normal file
52
src/app/views/search.zig
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
const std = @import("std");
|
||||
const jetzig = @import("jetzig");
|
||||
const queries = @import("../lib/db.zig");
|
||||
const sqlite = @import("sqlite");
|
||||
|
||||
pub fn index(request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
||||
var root = try data.array();
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||
defer arena.deinit();
|
||||
var db = try sqlite.Db.init(.{
|
||||
.mode = sqlite.Db.Mode{ .File = "/home/swebb/Source/zuletzt/src/app/database/data.db" },
|
||||
.open_flags = .{
|
||||
.write = true,
|
||||
.create = true,
|
||||
},
|
||||
.threading_mode = .MultiThread,
|
||||
});
|
||||
const params = try request.params();
|
||||
const queryOrNull: ?[]const u8 = if (params.get("q")) |param| param.string.value else null;
|
||||
if (queryOrNull) |query| {
|
||||
// sql.search(query, db);
|
||||
var artistSearch = try db.prepare(queries.total_search);
|
||||
defer artistSearch.deinit();
|
||||
|
||||
const artistResults = try artistSearch.all(
|
||||
struct {
|
||||
artist: []u8,
|
||||
url: []u8,
|
||||
form: []u8,
|
||||
},
|
||||
arena.allocator(),
|
||||
.{},
|
||||
.{ .artist = query, .album = query, .track = query },
|
||||
);
|
||||
|
||||
for (artistResults) |r| {
|
||||
std.log.debug("artist: {s}, url: {s}", .{ r.artist, r.url });
|
||||
try root.append(data.string(r.artist));
|
||||
try root.append(data.string(r.url));
|
||||
try root.append(data.string(r.form));
|
||||
//std.log.debug("{s}", .{r});
|
||||
}
|
||||
} else {
|
||||
return request.render(.bad_request);
|
||||
}
|
||||
//const query = params.get("q");
|
||||
//try root.put("q",query);
|
||||
//try root.put("q", data.string("Welcome"));
|
||||
return request.render(.ok);
|
||||
}
|
||||
16
src/app/views/search/index.zmpl
Normal file
16
src/app/views/search/index.zmpl
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<table>
|
||||
<tr>
|
||||
<th>Artist</th>
|
||||
<th>Album</th>
|
||||
<th>Track</th>
|
||||
</tr>
|
||||
@zig {
|
||||
for (zmpl.items(.array), 0..) |u,i| {
|
||||
if(@mod(i,3)==0){
|
||||
<tr>
|
||||
<td id={{zmpl.items(.array)[i+2].string.value}}><a href={{zmpl.items(.array)[i+1].string.value}}>{{u}}</a></td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
}
|
||||
</table>
|
||||
7
src/app/views/stats.zig
Normal file
7
src/app/views/stats.zig
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
const std = @import("std");
|
||||
const jetzig = @import("jetzig");
|
||||
|
||||
pub fn index(request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
||||
_ = data;
|
||||
return request.render(.ok);
|
||||
}
|
||||
3
src/app/views/stats/index.zmpl
Normal file
3
src/app/views/stats/index.zmpl
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<div>
|
||||
<span>Content goes here</span>
|
||||
</div>
|
||||
34
src/main.zig
34
src/main.zig
|
|
@ -87,35 +87,35 @@ pub const jetzig_options = struct {
|
|||
};
|
||||
|
||||
pub fn main() !void {
|
||||
var db = try sqlite.Db.init(.{
|
||||
.mode = sqlite.Db.Mode{ .File = "/home/swebb/Source/zuletzt/src/app/database/data.db" },
|
||||
.open_flags = .{
|
||||
.write = true,
|
||||
.create = true,
|
||||
},
|
||||
.threading_mode = .MultiThread,
|
||||
});
|
||||
//var db = try sqlite.Db.init(.{
|
||||
// .mode = sqlite.Db.Mode{ .File = "/home/swebb/Source/zuletzt/src/app/database/data.db" },
|
||||
// .open_flags = .{
|
||||
// .write = true,
|
||||
// .create = true,
|
||||
// },
|
||||
// .threading_mode = .MultiThread,
|
||||
//});
|
||||
|
||||
//const create =
|
||||
// \\CREATE TABLE artists ('artist', 'plays')
|
||||
//;
|
||||
|
||||
const query =
|
||||
\\INSERT INTO artists ('artist', 'plays') VALUES (?,?)
|
||||
;
|
||||
//const query =
|
||||
// \\INSERT INTO artists ('artist', 'plays') VALUES (?,?)
|
||||
//;
|
||||
|
||||
//var build = try db.prepare(create);
|
||||
//defer build.deinit();
|
||||
|
||||
//try build.exec(.{},.{});
|
||||
|
||||
var stmt = try db.prepare(query);
|
||||
defer stmt.deinit();
|
||||
//var stmt = try db.prepare(query);
|
||||
//defer stmt.deinit();
|
||||
|
||||
try stmt.exec(.{}, .{
|
||||
.artist = "Wilco",
|
||||
.plays = 2500,
|
||||
});
|
||||
//try stmt.exec(.{}, .{
|
||||
// .artist = "Wilco",
|
||||
// .plays = 2500,
|
||||
//});
|
||||
|
||||
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue