cleanup playtwitch

This commit is contained in:
LordMZTE 2022-08-19 20:08:40 +02:00
parent 0d082554f6
commit 9a54cec127
Signed by: LordMZTE
GPG key ID: B64802DC33A64FF6
2 changed files with 49 additions and 37 deletions

View file

@ -16,10 +16,6 @@ pub fn connectSignal(
_ = c.g_signal_connect_data(instance, detailed_signal, c_handler, data, null, flags.*); _ = 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 { pub fn handleGError(err: *?*c.GError) !void {
if (err.*) |e| { if (err.*) |e| {
std.log.err("glib error: {s}", .{e.message}); std.log.err("glib error: {s}", .{e.message});

View file

@ -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); const quality = c.gtk_combo_box_text_get_active_text(data.quality_box);
defer c.g_free(quality); defer c.g_free(quality);
start( start(.{
if (c.gtk_switch_get_active(data.chatty_switch) == 0) false else true, .chatty = c.gtk_switch_get_active(data.chatty_switch) != 0,
std.mem.span(channel_name), .channel = std.mem.span(channel_name),
std.mem.span(quality), .quality = std.mem.span(quality),
data.dialog, .crash_dialog = data.dialog,
data.text_buf, .error_text_buf = data.text_buf,
data.win, .window = data.win,
) catch |err| std.log.err("Failed to start children: {}", .{err}); }) catch |err| std.log.err("Failed to start children: {}", .{err});
c.gtk_widget_hide(@ptrCast(*c.GtkWidget, data.win)); 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); const quality = c.gtk_combo_box_text_get_active_text(data.quality_box);
defer c.g_free(quality); defer c.g_free(quality);
start( start(.{
if (c.gtk_switch_get_active(data.chatty_switch) == 0) false else true, .chatty = c.gtk_switch_get_active(data.chatty_switch) != 0,
ffi.getEntryBufferText(data.buf), .channel = c.gtk_entry_buffer_get_text(
std.mem.span(quality), data.buf,
data.dialog, )[0..c.gtk_entry_buffer_get_length(data.buf)],
data.text_buf, .quality = std.mem.span(quality),
data.win, .crash_dialog = data.dialog,
) catch |err| std.log.err("Failed to start children: {}", .{err}); .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)); 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, chatty: bool,
/// name of the channel to launch
channel: []const u8, channel: []const u8,
/// quality parameter for streamlink
quality: []const u8, quality: []const u8,
dialog: *c.GtkWidget, /// a pointer to a GTK widget that'll be shown if streamlink crashes
text_buf: *c.GtkTextBuffer, 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, 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", .{}); std.log.warn("Exiting due to attempt to start empty channel", .{});
return; return;
} }
@ -273,11 +284,11 @@ fn start(
std.log.info( std.log.info(
"Starting for channel {s} with quality {s} (chatty: {})", "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); 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); defer c_allocator.free(quality_z);
const streamlink_argv = [_][*c]const u8{ "streamlink", url, quality_z, null }; const streamlink_argv = [_][*c]const u8{ "streamlink", url, quality_z, null };
const streamlink_subproc = c.g_subprocess_newv( const streamlink_subproc = c.g_subprocess_newv(
@ -289,9 +300,9 @@ fn start(
const communicate_data = try c_allocator.create(StreamlinkCommunicateData); const communicate_data = try c_allocator.create(StreamlinkCommunicateData);
communicate_data.* = StreamlinkCommunicateData{ communicate_data.* = StreamlinkCommunicateData{
.dialog = dialog, .dialog = options.crash_dialog,
.text_buf = text_buf, .text_buf = options.error_text_buf,
.window = window, .window = options.window,
}; };
c.g_subprocess_communicate_async( c.g_subprocess_communicate_async(
@ -302,14 +313,14 @@ fn start(
communicate_data, communicate_data,
); );
if (chatty) { if (options.chatty) {
if (@atomicLoad(bool, &chatty_alive, .Unordered)) { if (@atomicLoad(bool, &chatty_alive, .Unordered)) {
std.log.warn("Chatty is already running, not starting again.", .{}); std.log.warn("Chatty is already running, not starting again.", .{});
return; return;
} }
var chatty_arena = std.heap.ArenaAllocator.init(c_allocator); 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 = [_][]const u8{ "chatty", "-connect", "-channel", channel_d };
const chatty_argv_dup = try chatty_arena.allocator().dupe([]const u8, &chatty_argv); const chatty_argv_dup = try chatty_arena.allocator().dupe([]const u8, &chatty_argv);
var chatty_child = std.ChildProcess.init( var chatty_child = std.ChildProcess.init(
@ -372,22 +383,27 @@ fn streamlinkCommunicateCb(
} }
var len: usize = 0; 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 // Streamlink exits with a nonzero code if the stream ends, but we don't
// want to count this as a crash. // 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( std.log.warn(
\\Streamlink exited with code {d}, but output contained \\Streamlink exited with code {d}, but output contained
\\"Stream ended", not showing popup. Full output: \\"Stream ended", not showing popup. Full output:
\\{s} \\{s}
, ,
.{ exit_code, stdout_data[0..len] }, .{ exit_code, stdout_data },
); );
c.gtk_window_close(data.window); c.gtk_window_close(data.window);
return; 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); c.gtk_widget_show(data.dialog);
} }