diff --git a/scripts/playtwitch/src/State.zig b/scripts/playtwitch/src/State.zig index 3206d4e..d9c42fc 100644 --- a/scripts/playtwitch/src/State.zig +++ b/scripts/playtwitch/src/State.zig @@ -20,6 +20,7 @@ pub const Live = enum { live, offline, loading, + err, }; mutex: std.Thread.Mutex, diff --git a/scripts/playtwitch/src/config.zig b/scripts/playtwitch/src/config.zig index a6f2cd4..17e36e7 100644 --- a/scripts/playtwitch/src/config.zig +++ b/scripts/playtwitch/src/config.zig @@ -78,5 +78,5 @@ pub fn configLoaderThread(state: *State) !void { state.channels = channels.toOwnedSlice(); } - try @import("live.zig").fetchChannelsLive(state); + @import("live.zig").tryFetchChannelsLive(state); } diff --git a/scripts/playtwitch/src/gui.zig b/scripts/playtwitch/src/gui.zig index 3872ea0..6ae998e 100644 --- a/scripts/playtwitch/src/gui.zig +++ b/scripts/playtwitch/src/gui.zig @@ -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 }, .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 }, + .err => c.ImVec4{ .x = 0.8, .y = 0.0, .z = 0.0, .w = 1.0 }, }; const live_label = switch (ch.live) { .loading => "Loading...", .live => "Live", .offline => "Offline", + .err => "Error", }; const prev_col = c.igGetStyle().*.Colors[c.ImGuiCol_Text]; diff --git a/scripts/playtwitch/src/live.zig b/scripts/playtwitch/src/live.zig index ecac552..f3ad201 100644 --- a/scripts/playtwitch/src/live.zig +++ b/scripts/playtwitch/src/live.zig @@ -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); defer @atomicStore(bool, &s.live_status_loading, false, .Unordered); log.info("initiaizing cURL", .{}); @@ -51,8 +67,6 @@ pub fn fetchChannelsLive(s: *State) !void { for (s.channels.?) |*entry| { const chan = if (entry.* == .channel) &entry.channel else continue; - page_buf.clearRetainingCapacity(); - log.info("requesting live state for channel {s}", .{chan.name}); const url = try std.fmt.bufPrintZ( @@ -61,8 +75,29 @@ pub fn fetchChannelsLive(s: *State) !void { .{chan.name}, ); 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")) { @atomicStore(State.Live, &chan.live, .live, .Unordered); } else { diff --git a/scripts/playtwitch/src/main.zig b/scripts/playtwitch/src/main.zig index 2166fff..02e6d85 100644 --- a/scripts/playtwitch/src/main.zig +++ b/scripts/playtwitch/src/main.zig @@ -48,6 +48,7 @@ pub fn main() !void { c.igStyleColorsDark(null); @import("theme.zig").loadTheme(&c.igGetStyle().*.Colors); + const font = try @import("theme.zig").loadFont(); const state = try State.init(win.?); defer state.deinit(); @@ -65,6 +66,8 @@ pub fn main() !void { c.ImGui_ImplOpenGL3_NewFrame(); c.ImGui_ImplGlfw_NewFrame(); c.igNewFrame(); + if (font) |f| + c.igPushFont(f); const win_visible = c.igBegin( "##main_win", @@ -89,6 +92,9 @@ pub fn main() !void { try gui.winContent(state); } + if (font != null) + c.igPopFont(); + c.igEnd(); c.igEndFrame(); diff --git a/scripts/playtwitch/src/theme.zig b/scripts/playtwitch/src/theme.zig index eb5622a..d6a4dc5 100644 --- a/scripts/playtwitch/src/theme.zig +++ b/scripts/playtwitch/src/theme.zig @@ -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_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; +}