playtwitch: add basic font support and improve http error handling

This commit is contained in:
LordMZTE 2022-11-23 22:43:45 +01:00
parent 4ecae122c5
commit 0fe952479d
Signed by: LordMZTE
GPG key ID: B64802DC33A64FF6
6 changed files with 80 additions and 6 deletions

View file

@ -20,6 +20,7 @@ pub const Live = enum {
live, live,
offline, offline,
loading, loading,
err,
}; };
mutex: std.Thread.Mutex, mutex: std.Thread.Mutex,

View file

@ -78,5 +78,5 @@ pub fn configLoaderThread(state: *State) !void {
state.channels = channels.toOwnedSlice(); state.channels = channels.toOwnedSlice();
} }
try @import("live.zig").fetchChannelsLive(state); @import("live.zig").tryFetchChannelsLive(state);
} }

View file

@ -190,11 +190,13 @@ pub fn winContent(state: *State) !void {
.loading => c.ImVec4{ .x = 1.0, .y = 1.0, .z = 0.0, .w = 1.0 }, .loading => c.ImVec4{ .x = 1.0, .y = 1.0, .z = 0.0, .w = 1.0 },
.live => c.ImVec4{ .x = 0.0, .y = 1.0, .z = 0.0, .w = 1.0 }, .live => c.ImVec4{ .x = 0.0, .y = 1.0, .z = 0.0, .w = 1.0 },
.offline => c.ImVec4{ .x = 1.0, .y = 0.0, .z = 0.0, .w = 1.0 }, .offline => c.ImVec4{ .x = 1.0, .y = 0.0, .z = 0.0, .w = 1.0 },
.err => c.ImVec4{ .x = 0.8, .y = 0.0, .z = 0.0, .w = 1.0 },
}; };
const live_label = switch (ch.live) { const live_label = switch (ch.live) {
.loading => "Loading...", .loading => "Loading...",
.live => "Live", .live => "Live",
.offline => "Offline", .offline => "Offline",
.err => "Error",
}; };
const prev_col = c.igGetStyle().*.Colors[c.ImGuiCol_Text]; const prev_col = c.igGetStyle().*.Colors[c.ImGuiCol_Text];

View file

@ -16,10 +16,26 @@ pub fn reloadLiveThread(s: *State) !void {
} }
} }
try fetchChannelsLive(s); tryFetchChannelsLive(s);
} }
pub fn fetchChannelsLive(s: *State) !void { pub fn tryFetchChannelsLive(s: *State) void {
fetchChannelsLive(s) catch |e| {
log.err("fetching status: {}", .{e});
s.mutex.lock();
defer s.mutex.unlock();
for (s.channels.?) |*chan| {
switch (chan.*) {
.channel => |*ch| ch.live = .err,
else => {},
}
}
};
}
fn fetchChannelsLive(s: *State) !void {
@atomicStore(bool, &s.live_status_loading, true, .Unordered); @atomicStore(bool, &s.live_status_loading, true, .Unordered);
defer @atomicStore(bool, &s.live_status_loading, false, .Unordered); defer @atomicStore(bool, &s.live_status_loading, false, .Unordered);
log.info("initiaizing cURL", .{}); log.info("initiaizing cURL", .{});
@ -51,8 +67,6 @@ pub fn fetchChannelsLive(s: *State) !void {
for (s.channels.?) |*entry| { for (s.channels.?) |*entry| {
const chan = if (entry.* == .channel) &entry.channel else continue; const chan = if (entry.* == .channel) &entry.channel else continue;
page_buf.clearRetainingCapacity();
log.info("requesting live state for channel {s}", .{chan.name}); log.info("requesting live state for channel {s}", .{chan.name});
const url = try std.fmt.bufPrintZ( const url = try std.fmt.bufPrintZ(
@ -61,8 +75,29 @@ pub fn fetchChannelsLive(s: *State) !void {
.{chan.name}, .{chan.name},
); );
try handleCurlErr(c.curl_easy_setopt(curl, c.CURLOPT_URL, url.ptr)); try handleCurlErr(c.curl_easy_setopt(curl, c.CURLOPT_URL, url.ptr));
try handleCurlErr(c.curl_easy_perform(curl));
var tries: u8 = 3;
while (tries > 0) : (tries -= 1) {
page_buf.clearRetainingCapacity();
try handleCurlErr(c.curl_easy_perform(curl));
var response: c_long = 0;
try handleCurlErr(c.curl_easy_getinfo(curl, c.CURLINFO_RESPONSE_CODE, &response));
if (response != 200) {
log.warn(
"got error response {}, retrying ({} tries left)",
.{ response, tries },
);
continue;
}
break;
}
if (tries == 0) {
@atomicStore(State.Live, &chan.live, .err, .Unordered);
}
if (std.mem.containsAtLeast(u8, page_buf.items, 1, "live_user")) { if (std.mem.containsAtLeast(u8, page_buf.items, 1, "live_user")) {
@atomicStore(State.Live, &chan.live, .live, .Unordered); @atomicStore(State.Live, &chan.live, .live, .Unordered);
} else { } else {

View file

@ -48,6 +48,7 @@ pub fn main() !void {
c.igStyleColorsDark(null); c.igStyleColorsDark(null);
@import("theme.zig").loadTheme(&c.igGetStyle().*.Colors); @import("theme.zig").loadTheme(&c.igGetStyle().*.Colors);
const font = try @import("theme.zig").loadFont();
const state = try State.init(win.?); const state = try State.init(win.?);
defer state.deinit(); defer state.deinit();
@ -65,6 +66,8 @@ pub fn main() !void {
c.ImGui_ImplOpenGL3_NewFrame(); c.ImGui_ImplOpenGL3_NewFrame();
c.ImGui_ImplGlfw_NewFrame(); c.ImGui_ImplGlfw_NewFrame();
c.igNewFrame(); c.igNewFrame();
if (font) |f|
c.igPushFont(f);
const win_visible = c.igBegin( const win_visible = c.igBegin(
"##main_win", "##main_win",
@ -89,6 +92,9 @@ pub fn main() !void {
try gui.winContent(state); try gui.winContent(state);
} }
if (font != null)
c.igPopFont();
c.igEnd(); c.igEnd();
c.igEndFrame(); c.igEndFrame();

View file

@ -15,3 +15,33 @@ pub fn loadTheme(colors: [*]c.ImVec4) void {
colors[c.ImGuiCol_TitleBgActive] = c.ImVec4{ .x = 0.33, .y = 0.14, .z = 0.51, .w = 1.0 }; colors[c.ImGuiCol_TitleBgActive] = c.ImVec4{ .x = 0.33, .y = 0.14, .z = 0.51, .w = 1.0 };
colors[c.ImGuiCol_WindowBg] = c.ImVec4{ .x = 0.12, .y = 0.0, .z = 0.23, .w = 0.8 }; colors[c.ImGuiCol_WindowBg] = c.ImVec4{ .x = 0.12, .y = 0.0, .z = 0.23, .w = 0.8 };
} }
pub fn loadFont() !?*c.ImFont {
log.info("loading fonts", .{});
const fonts = [_][:0]const u8{
"/usr/share/fonts/TTF/Iosevka Nerd Font Complete.ttf",
"/usr/share/fonts/noto/NotoSans-Regular.ttf",
};
for (fonts) |font| {
const found = if (std.fs.accessAbsolute(font, .{})) |_|
true
else |e| if (e == error.FileNotFound)
true
else
return e;
if (found) {
log.info("using font {s}", .{font});
return c.ImFontAtlas_AddFontFromFileTTF(
c.igGetIO().*.Fonts,
font.ptr,
16,
null,
null,
);
}
}
return null;
}