mirror of
https://mzte.de/git/LordMZTE/dotfiles.git
synced 2024-06-09 06:50:08 +02:00
playtwitch now pops up error if streamlink crashes
This commit is contained in:
parent
c479629e25
commit
e82c115878
|
@ -202,21 +202,76 @@ fn start(
|
|||
return;
|
||||
}
|
||||
|
||||
const channel_d = try state.udata_arena.dupe(u8, channel);
|
||||
const quality_d = try state.udata_arena.dupe(u8, quality);
|
||||
|
||||
std.log.info(
|
||||
"Starting for channel {s} with quality {s} (chatty: {})",
|
||||
.{ channel, quality, chatty },
|
||||
.{ channel_d, quality_d, chatty },
|
||||
);
|
||||
const url = try std.fmt.allocPrint(state.udata_arena, "https://twitch.tv/{s}", .{channel_d});
|
||||
const streamlink_argv = [_][]const u8{ "streamlink", url, quality_d };
|
||||
state.streamlink_child = std.ChildProcess.init(
|
||||
try state.udata_arena.dupe([]const u8, &streamlink_argv),
|
||||
state.alloc,
|
||||
);
|
||||
const url = try std.fmt.allocPrint(state.alloc, "https://twitch.tv/{s}", .{channel});
|
||||
defer state.alloc.free(url);
|
||||
const streamlink_argv = [_][]const u8{ "streamlink", url, quality };
|
||||
var streamlink_child = std.ChildProcess.init(&streamlink_argv, state.alloc);
|
||||
try streamlink_child.spawn();
|
||||
state.streamlink_child = streamlink_child;
|
||||
|
||||
if (chatty) {
|
||||
const chatty_argv = [_][]const u8{ "chatty", "-connect", "-channel", channel };
|
||||
var chatty_child = std.ChildProcess.init(&chatty_argv, state.alloc);
|
||||
try chatty_child.spawn();
|
||||
state.chatty_child = chatty_child;
|
||||
const chatty_argv = [_][]const u8{ "chatty", "-connect", "-channel", channel_d };
|
||||
state.chatty_child = std.ChildProcess.init(
|
||||
try state.udata_arena.dupe([]const u8, &chatty_argv),
|
||||
state.alloc,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn showStreamlinkErrorDialog(output: []const u8) void {
|
||||
// TODO: instead of creating a new main loop, reuse the one used for the rest of the GUI
|
||||
const main_loop = c.g_main_loop_new(null, 0);
|
||||
defer c.g_main_loop_unref(main_loop);
|
||||
|
||||
const dialog = c.gtk_dialog_new_with_buttons(
|
||||
"Streamlink Crashed!",
|
||||
null,
|
||||
c.GTK_DIALOG_MODAL,
|
||||
"_Close",
|
||||
c.GTK_RESPONSE_CLOSE,
|
||||
@as(?*anyopaque, null),
|
||||
);
|
||||
|
||||
ffi.connectSignal(
|
||||
dialog,
|
||||
"response",
|
||||
@ptrCast(c.GCallback, onErrorDialogResponse),
|
||||
main_loop,
|
||||
);
|
||||
|
||||
const content = c.gtk_dialog_get_content_area(@ptrCast(*c.GtkDialog, dialog));
|
||||
c.gtk_box_set_spacing(@ptrCast(*c.GtkBox, content), 5);
|
||||
c.gtk_widget_set_margin_top(content, 5);
|
||||
c.gtk_widget_set_margin_bottom(content, 5);
|
||||
c.gtk_widget_set_margin_start(content, 5);
|
||||
c.gtk_widget_set_margin_end(content, 5);
|
||||
c.gtk_box_append(
|
||||
@ptrCast(*c.GtkBox, content),
|
||||
c.gtk_label_new("Streamlink Crashed! This is the output."),
|
||||
);
|
||||
|
||||
const output_buf = c.gtk_text_buffer_new(null);
|
||||
var start_iter: c.GtkTextIter = undefined;
|
||||
c.gtk_text_buffer_get_start_iter(output_buf, &start_iter);
|
||||
c.gtk_text_buffer_insert(output_buf, &start_iter, output.ptr, @intCast(c_int, output.len));
|
||||
|
||||
const output_view = c.gtk_text_view_new_with_buffer(output_buf);
|
||||
c.gtk_widget_set_hexpand(output_view, 1);
|
||||
c.gtk_text_view_set_editable(@ptrCast(*c.GtkTextView, output_view), 0);
|
||||
c.gtk_box_append(@ptrCast(*c.GtkBox, content), output_view);
|
||||
|
||||
c.gtk_widget_show(dialog);
|
||||
|
||||
c.g_main_loop_run(main_loop);
|
||||
}
|
||||
|
||||
fn onErrorDialogResponse(_: *c.GtkDialog, _: c_int, loop: *c.GMainLoop) void {
|
||||
c.g_main_loop_quit(loop);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ pub fn main() !u8 {
|
|||
var udata_arena = std.heap.ArenaAllocator.init(std.heap.c_allocator);
|
||||
defer udata_arena.deinit();
|
||||
|
||||
var state = gui.GuiState {
|
||||
var state = gui.GuiState{
|
||||
.alloc = std.heap.c_allocator,
|
||||
.udata_arena = udata_arena.allocator(),
|
||||
};
|
||||
|
@ -27,13 +27,51 @@ pub fn main() !u8 {
|
|||
@ptrCast([*c][*c]u8, std.os.argv.ptr),
|
||||
);
|
||||
|
||||
if (state.streamlink_child) |*ch| {
|
||||
_ = try ch.wait();
|
||||
}
|
||||
|
||||
if (state.chatty_child) |*ch| {
|
||||
_ = try ch.wait();
|
||||
if (state.streamlink_child) |*sl_child| {
|
||||
try runChildren(sl_child, if (state.chatty_child) |*ch| ch else null);
|
||||
}
|
||||
|
||||
return @intCast(u8, status);
|
||||
}
|
||||
|
||||
fn runChildren(sl_child: *std.ChildProcess, chatty_child: ?*std.ChildProcess) !void {
|
||||
var sl_alive = true;
|
||||
var thread: ?std.Thread = null;
|
||||
if (chatty_child) |chatty| {
|
||||
thread = try std.Thread.spawn(
|
||||
.{},
|
||||
waitAndRunChatty,
|
||||
.{ chatty, &sl_alive },
|
||||
);
|
||||
}
|
||||
|
||||
sl_child.stdout_behavior = .Pipe;
|
||||
try sl_child.spawn();
|
||||
const output = try sl_child.stdout.?.readToEndAlloc(
|
||||
std.heap.c_allocator,
|
||||
std.math.maxInt(usize),
|
||||
);
|
||||
defer std.heap.c_allocator.free(output);
|
||||
const term = try sl_child.wait();
|
||||
if (term == .Exited and term.Exited != 0) {
|
||||
@atomicStore(bool, &sl_alive, false, .Unordered);
|
||||
std.log.err("Streamlink died:\n{s}", .{output});
|
||||
gui.showStreamlinkErrorDialog(std.mem.trimRight(u8, output, "\n\t "));
|
||||
if (thread) |*t| {
|
||||
t.detach();
|
||||
}
|
||||
} else {
|
||||
if (thread) |*t| {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function first waits a while, then checks if streamlink is still alive
|
||||
// and then runs chatty.
|
||||
fn waitAndRunChatty(chatty: *std.ChildProcess, sl_alive: *bool) !void {
|
||||
std.time.sleep(5 * std.time.ns_per_s);
|
||||
if (@atomicLoad(bool, sl_alive, .Unordered)) {
|
||||
_ = try chatty.spawnAndWait();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue