diff --git a/build.zig.zon b/build.zig.zon index 823b42c..0839430 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -17,8 +17,8 @@ // internet connectivity. .dependencies = .{ .jetzig = .{ - .url = "https://github.com/jetzig-framework/jetzig/archive/2c52792217b9441ed5e91d67e7ec5a8959285307.tar.gz", - .hash = "jetzig-0.0.0-IpAgLbMeDwDYRqWu0OJixGbcDUoUbfAN0xGe1xsYRHTj", + .url = "https://github.com/jetzig-framework/jetzig/archive/86d82026ab574d4e5c3c6cc3817dda84b510001a.tar.gz", + .hash = "jetzig-0.0.0-IpAgLTkzDwDKmsY9MqM41EHDXWGkViiECa0lzV8xl17x", }, .zeit = .{ .url = "https://github.com/rockorager/zeit/archive/refs/heads/main.tar.gz", diff --git a/src/app/jobs/process_rule.zig b/src/app/jobs/process_rule.zig index 7cb1a71..f211dbe 100644 --- a/src/app/jobs/process_rule.zig +++ b/src/app/jobs/process_rule.zig @@ -1,29 +1,14 @@ const std = @import("std"); const jetzig = @import("jetzig"); +const Data = @import("../../types.zig"); pub fn run(allocator: std.mem.Allocator, params: *jetzig.data.Value, env: jetzig.jobs.JobEnv) !void { _ = env; //_ = params; - const Rule = struct { - name: []const u8, - conditionals: []struct { - match_on: []const u8, - match_cond: []const u8, - match_txt: []const u8, - }, - actions: []struct { - action: []const u8, - action_on: []const u8, - action_txt: []const u8, - }, - }; + std.log.debug("{s}", .{try params.toJson()}); - const Rules = struct { - rules: []const Rule, - }; - - const rule = try std.json.parseFromSliceLeaky(Rule, allocator, try params.toJson(), .{ .ignore_unknown_fields = true }); + const rule = try std.json.parseFromSliceLeaky(Data.Rule, allocator, try params.toJson(), .{ .ignore_unknown_fields = true }); const file_read: std.fs.File = std.fs.cwd().openFile("rules.json", .{}) catch |read_err| switch (read_err) { error.FileNotFound => { @@ -34,7 +19,7 @@ pub fn run(allocator: std.mem.Allocator, params: *jetzig.data.Value, env: jetzig return; }, }; - const out_rules = Rules{ .rules = &[_]Rule{rule} }; + const out_rules = Data.Rules{ .rules = &[_]Data.Rule{rule} }; const out = try std.json.stringifyAlloc(allocator, out_rules, .{}); try file.writeAll(out); file.close(); @@ -46,17 +31,17 @@ pub fn run(allocator: std.mem.Allocator, params: *jetzig.data.Value, env: jetzig }, }; - var rules = std.ArrayList(Rule).init(allocator); + var rules = std.ArrayList(Data.Rule).init(allocator); defer rules.deinit(); const file_content = try file_read.readToEndAlloc(allocator, 16_000_000); - const content: Rules = try std.json.parseFromSliceLeaky(Rules, allocator, file_content, .{}); + const content: Data.Rules = try std.json.parseFromSliceLeaky(Data.Rules, allocator, file_content, .{}); try rules.appendSlice(content.rules); try rules.append(rule); file_read.close(); const file_write: std.fs.File = try std.fs.cwd().openFile("rules.json", .{ .mode = .write_only }); - const out_rules = Rules{ .rules = rules.items }; + const out_rules = Data.Rules{ .rules = rules.items }; const out = try std.json.stringifyAlloc(allocator, out_rules, .{}); try file_write.writeAll(out); diff --git a/src/app/views/rules.zig b/src/app/views/rules.zig index bb8ea4b..957f5d2 100644 --- a/src/app/views/rules.zig +++ b/src/app/views/rules.zig @@ -25,12 +25,17 @@ pub fn post(request: *jetzig.Request) !jetzig.View { var job = try request.job("process_rule"); _ = try job.params.put("name", params.get("rule-title")); + _ = try job.params.put("cond_req", params.get("cond-req")); var conditionals = try job.params.put("conditionals", .array); - var cond0 = try conditionals.append(.object); - try cond0.put("match_on", params.get("match-on")); - try cond0.put("match_cond", params.get("match-cond")); - try cond0.put("match_txt", params.get("match-txt")); + inline for (0..5) |i| { + if (!std.mem.eql(u8, "", params.getT(.string, comptime std.fmt.comptimePrint("match-txt{}", .{i})).?)) { + var cond = try conditionals.append(.object); + try cond.put("match_on", params.get(comptime std.fmt.comptimePrint("match-on{}", .{i}))); + try cond.put("match_cond", params.get(comptime std.fmt.comptimePrint("match-cond{}", .{i}))); + try cond.put("match_txt", params.get(comptime std.fmt.comptimePrint("match-txt{}", .{i}))); + } + } var actions = try job.params.put("actions", .array); var act0 = try actions.append(.object); diff --git a/src/app/views/rules/index.zmpl b/src/app/views/rules/index.zmpl index ab55c96..038ce71 100644 --- a/src/app/views/rules/index.zmpl +++ b/src/app/views/rules/index.zmpl @@ -12,74 +12,37 @@ Add a rule below.
+Match + +conditonals. +
If - - - - - - - +@for (0..5) |i| { + + + + + + + +
+}
diff --git a/src/apply_rule.zig b/src/apply_rule.zig index 92d7598..db6eb42 100644 --- a/src/apply_rule.zig +++ b/src/apply_rule.zig @@ -2,17 +2,33 @@ const std = @import("std"); const Scrobble = @import("./types.zig").LastFMScrobble; const Rules = @import("./types.zig").Rules; +// Wrapper for containsAtLeast to make the switch below to work +fn containsAtLeastOne(haystack: []const u8, needle: []const u8) bool { + return std.mem.containsAtLeast(u8, haystack, 1, needle); +} + +fn eqlDecomped(haystack: []const u8, needle: []const u8) bool { + return std.mem.eql(u8, haystack, needle); +} + pub fn applyScrobbleRule(scrobble: Scrobble, rules: Rules) Scrobble { - var match_found: bool = true; var output_scrobble: Scrobble = scrobble; for (rules.rules) |rule| { + var match_found: bool = switch (rule.cond_req) { + .any => false, + .all => true, + }; for (rule.conditionals) |cond| { - switch (cond.match_cond) { - .is => switch (cond.match_on) { - inline else => |on| match_found = match_found and std.mem.eql(u8, @field(scrobble, @tagName(on)), cond.match_txt), + const match_fn: *const fn ([]const u8, []const u8) bool = switch (cond.match_cond) { + .is => eqlDecomped, + .contains => containsAtLeastOne, + }; + switch (rule.cond_req) { + .any => switch (cond.match_on) { + inline else => |on| match_found = match_found or match_fn(@field(scrobble, @tagName(on)), cond.match_txt), }, - .contains => switch (cond.match_on) { - inline else => |on| match_found = match_found and std.mem.containsAtLeast(u8, @field(scrobble, @tagName(on)), 1, cond.match_txt), + .all => switch (cond.match_on) { + inline else => |on| match_found = match_found and match_fn(@field(scrobble, @tagName(on)), cond.match_txt), }, } } diff --git a/src/types.zig b/src/types.zig index 61b0e88..0e385a5 100644 --- a/src/types.zig +++ b/src/types.zig @@ -35,8 +35,9 @@ pub const SpotifyScrobble = struct { incognito_mode: ?bool, }; -const Rule = struct { +pub const Rule = struct { name: []const u8, + cond_req: enum { any, all }, conditionals: []struct { match_on: ScrobbleFields, match_cond: enum { is, contains },