eink-feed/src/eink_feed_render/main/departures.zig
2025-06-19 16:55:59 +02:00

101 lines
3.4 KiB
Zig

const std = @import("std");
const builtin = @import("builtin");
const clap = @import("clap");
const zdt = @import("zdt");
const render = @import("eink_feed_render");
pub const std_options: std.Options = .{
.log_level = if (builtin.mode == .Debug) .debug else .info,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.thread_safe = true,
}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
{
const params = comptime clap.parseParamsComptime(
\\-h, --help Display this help and exit.
\\--url <str> URL of eink-feed server.
\\--channel <u32> Channel ID.
\\--efa <str> URL of EFA server.
\\--stop <str> Stop ID.
\\--tz <str> Time zone.
\\--max <usize> Max number of departures listed.
\\--show-operator Show operator.
\\--stopfinder <str> Search for stops on the EFA server with the given search query.
);
var diag = clap.Diagnostic{};
var res = clap.parse(clap.Help, &params, clap.parsers.default, .{
.diagnostic = &diag,
.allocator = allocator,
}) catch |err| {
diag.report(std.io.getStdErr().writer(), err) catch {};
return err;
};
defer res.deinit();
if (res.args.help != 0 or
res.args.efa == null or
((res.args.stop == null or
res.args.tz == null or
res.args.url == null or
res.args.channel == null) and
res.args.stopfinder == null))
{
const writer = std.io.getStdErr().writer();
try writer.writeAll("eink-feed-render-departures\n");
return clap.help(writer, clap.Help, &params, .{});
}
const efa = try render.apps.Departures.efa.Client.init(allocator, res.args.efa.?);
defer efa.deinit();
if (res.args.stopfinder) |query| {
try efa.findStops(query);
return;
}
var tz = try zdt.Timezone.fromTzdata(res.args.tz.?, allocator);
defer tz.deinit();
render.renderer.init();
defer render.renderer.deinit();
const feed_client = try render.FeedClient.init(allocator, res.args.url.?);
defer feed_client.deinit();
const channel = try feed_client.getChannel(res.args.channel.?);
defer channel.deinit();
const dim = render.Dimensions{
.width = channel.value.display.width,
.height = channel.value.display.height,
};
const orientation = channel.value.display.orientation.toInternal();
const departures = render.apps.Departures.init(allocator, dim);
const stop_id: []const u8 = res.args.stop.?;
const now = try zdt.Datetime.now(.{ .tz = &tz });
const efa_departures = try efa.getDepartures(stop_id);
defer efa_departures.deinit();
const png = try departures.render(&efa_departures.value, .{
.now = &now,
.tz = &tz,
.max_items = res.args.max orelse 15,
.show_operator = res.args.@"show-operator" != 0,
});
defer allocator.free(png);
try feed_client.uploadFrame(
channel.value.id,
orientation,
png,
"image/png",
);
}
}