From 9a54cec127e4565f5fb07786078ba74ad6907c50 Mon Sep 17 00:00:00 2001
From: LordMZTE <lord@mzte.de>
Date: Fri, 19 Aug 2022 20:08:40 +0200
Subject: [PATCH] cleanup playtwitch

---
 scripts/playtwitch/src/ffi.zig |  4 --
 scripts/playtwitch/src/gui.zig | 82 ++++++++++++++++++++--------------
 2 files changed, 49 insertions(+), 37 deletions(-)

diff --git a/scripts/playtwitch/src/ffi.zig b/scripts/playtwitch/src/ffi.zig
index e5d38deb..8a4df197 100644
--- a/scripts/playtwitch/src/ffi.zig
+++ b/scripts/playtwitch/src/ffi.zig
@@ -16,10 +16,6 @@ pub fn connectSignal(
     _ = c.g_signal_connect_data(instance, detailed_signal, c_handler, data, null, flags.*);
 }
 
-pub fn getEntryBufferText(buf: *c.GtkEntryBuffer) []const u8 {
-    return c.gtk_entry_buffer_get_text(buf)[0..c.gtk_entry_buffer_get_length(buf)];
-}
-
 pub fn handleGError(err: *?*c.GError) !void {
     if (err.*) |e| {
         std.log.err("glib error: {s}", .{e.message});
diff --git a/scripts/playtwitch/src/gui.zig b/scripts/playtwitch/src/gui.zig
index 78d43ed8..d11a0546 100644
--- a/scripts/playtwitch/src/gui.zig
+++ b/scripts/playtwitch/src/gui.zig
@@ -166,14 +166,14 @@ fn onRowActivate(list: *c.GtkListBox, row: *c.GtkListBoxRow, data: *RowActivateD
     const quality = c.gtk_combo_box_text_get_active_text(data.quality_box);
     defer c.g_free(quality);
 
-    start(
-        if (c.gtk_switch_get_active(data.chatty_switch) == 0) false else true,
-        std.mem.span(channel_name),
-        std.mem.span(quality),
-        data.dialog,
-        data.text_buf,
-        data.win,
-    ) catch |err| std.log.err("Failed to start children: {}", .{err});
+    start(.{
+        .chatty = c.gtk_switch_get_active(data.chatty_switch) != 0,
+        .channel = std.mem.span(channel_name),
+        .quality = std.mem.span(quality),
+        .crash_dialog = data.dialog,
+        .error_text_buf = data.text_buf,
+        .window = data.win,
+    }) catch |err| std.log.err("Failed to start children: {}", .{err});
 
     c.gtk_widget_hide(@ptrCast(*c.GtkWidget, data.win));
 }
@@ -193,14 +193,16 @@ fn onOtherStreamActivate(entry: *c.GtkEntry, data: *OtherStreamActivateData) voi
     const quality = c.gtk_combo_box_text_get_active_text(data.quality_box);
     defer c.g_free(quality);
 
-    start(
-        if (c.gtk_switch_get_active(data.chatty_switch) == 0) false else true,
-        ffi.getEntryBufferText(data.buf),
-        std.mem.span(quality),
-        data.dialog,
-        data.text_buf,
-        data.win,
-    ) catch |err| std.log.err("Failed to start children: {}", .{err});
+    start(.{
+        .chatty = c.gtk_switch_get_active(data.chatty_switch) != 0,
+        .channel = c.gtk_entry_buffer_get_text(
+            data.buf,
+        )[0..c.gtk_entry_buffer_get_length(data.buf)],
+        .quality = std.mem.span(quality),
+        .crash_dialog = data.dialog,
+        .error_text_buf = data.text_buf,
+        .window = data.win,
+    }) catch |err| std.log.err("Failed to start children: {}", .{err});
 
     c.gtk_widget_hide(@ptrCast(*c.GtkWidget, data.win));
 }
@@ -256,15 +258,24 @@ fn onErrorDialogResponse(dialog: *c.GtkDialog, response_id: c_int, window: *c.Gt
     }
 }
 
-fn start(
+const StartOptions = struct {
+    /// if true, start chatty
     chatty: bool,
+    /// name of the channel to launch
     channel: []const u8,
+    /// quality parameter for streamlink
     quality: []const u8,
-    dialog: *c.GtkWidget,
-    text_buf: *c.GtkTextBuffer,
+    /// a pointer to a GTK widget that'll be shown if streamlink crashes
+    crash_dialog: *c.GtkWidget,
+    /// GtkTextBuffer to save streamlink's output in in the case of a crash
+    /// so it can be displayed
+    error_text_buf: *c.GtkTextBuffer,
+    /// the main GTK window
     window: *c.GtkWindow,
-) !void {
-    if (channel.len == 0) {
+};
+
+fn start(options: StartOptions) !void {
+    if (options.channel.len == 0) {
         std.log.warn("Exiting due to attempt to start empty channel", .{});
         return;
     }
@@ -273,11 +284,11 @@ fn start(
 
     std.log.info(
         "Starting for channel {s} with quality {s} (chatty: {})",
-        .{ channel, quality, chatty },
+        .{ options.channel, options.quality, options.chatty },
     );
-    const url = try std.fmt.allocPrintZ(c_allocator, "https://twitch.tv/{s}", .{channel});
+    const url = try std.fmt.allocPrintZ(c_allocator, "https://twitch.tv/{s}", .{options.channel});
     defer c_allocator.free(url);
-    const quality_z = try std.cstr.addNullByte(c_allocator, quality);
+    const quality_z = try std.cstr.addNullByte(c_allocator, options.quality);
     defer c_allocator.free(quality_z);
     const streamlink_argv = [_][*c]const u8{ "streamlink", url, quality_z, null };
     const streamlink_subproc = c.g_subprocess_newv(
@@ -289,9 +300,9 @@ fn start(
 
     const communicate_data = try c_allocator.create(StreamlinkCommunicateData);
     communicate_data.* = StreamlinkCommunicateData{
-        .dialog = dialog,
-        .text_buf = text_buf,
-        .window = window,
+        .dialog = options.crash_dialog,
+        .text_buf = options.error_text_buf,
+        .window = options.window,
     };
 
     c.g_subprocess_communicate_async(
@@ -302,14 +313,14 @@ fn start(
         communicate_data,
     );
 
-    if (chatty) {
+    if (options.chatty) {
         if (@atomicLoad(bool, &chatty_alive, .Unordered)) {
             std.log.warn("Chatty is already running, not starting again.", .{});
             return;
         }
 
         var chatty_arena = std.heap.ArenaAllocator.init(c_allocator);
-        const channel_d = try chatty_arena.allocator().dupe(u8, channel);
+        const channel_d = try chatty_arena.allocator().dupe(u8, options.channel);
         const chatty_argv = [_][]const u8{ "chatty", "-connect", "-channel", channel_d };
         const chatty_argv_dup = try chatty_arena.allocator().dupe([]const u8, &chatty_argv);
         var chatty_child = std.ChildProcess.init(
@@ -372,22 +383,27 @@ fn streamlinkCommunicateCb(
     }
 
     var len: usize = 0;
-    const stdout_data = @ptrCast([*c]const u8, c.g_bytes_get_data(stdout, &len));
+    const stdout_raw = @ptrCast([*c]const u8, c.g_bytes_get_data(stdout, &len));
+    const stdout_data = std.mem.trimRight(u8, stdout_raw[0..len], " \n\r\t");
 
     // Streamlink exits with a nonzero code if the stream ends, but we don't
     // want to count this as a crash.
-    if (std.mem.containsAtLeast(u8, stdout_data[0..len], 1, "Stream ended")) {
+    if (std.mem.containsAtLeast(u8, stdout_data, 1, "Stream ended")) {
         std.log.warn(
             \\Streamlink exited with code {d}, but output contained
             \\"Stream ended", not showing popup. Full output:
             \\{s}
         ,
-            .{ exit_code, stdout_data[0..len] },
+            .{ exit_code, stdout_data },
         );
         c.gtk_window_close(data.window);
         return;
     }
 
-    c.gtk_text_buffer_set_text(data.text_buf, stdout_data, @intCast(c_int, len));
+    c.gtk_text_buffer_set_text(
+        data.text_buf,
+        stdout_data.ptr,
+        @intCast(c_int, stdout_data.len),
+    );
     c.gtk_widget_show(data.dialog);
 }