mirror of
https://mzte.de/git/LordMZTE/dotfiles.git
synced 2024-05-17 06:23:50 +02:00
132 lines
4.1 KiB
Zig
132 lines
4.1 KiB
Zig
const std = @import("std");
|
|
const c = @import("ffi.zig").c;
|
|
const State = @import("State.zig");
|
|
const log = std.log.scoped(.launch);
|
|
|
|
pub fn launchChildren(state: *State, channel: []const u8) !void {
|
|
log.info(
|
|
"starting for channel {s} with quality {s} (chatty: {})",
|
|
.{ channel, std.mem.sliceTo(&state.quality_buf, 0), state.chatty },
|
|
);
|
|
|
|
// just to be safe...
|
|
state.freeStreamlinkMemfd();
|
|
|
|
if (state.chatty and !state.chatty_alive) {
|
|
var chatty_arena = std.heap.ArenaAllocator.init(std.heap.c_allocator);
|
|
const channel_d = try std.ascii.allocLowerString(chatty_arena.allocator(), channel);
|
|
const chatty_argv = try chatty_arena.allocator().dupe(
|
|
[]const u8,
|
|
&.{ "chatty", "-connect", "-channel", channel_d },
|
|
);
|
|
const chatty_child = std.ChildProcess.init(chatty_argv, std.heap.c_allocator);
|
|
|
|
const chatty_thread = try std.Thread.spawn(
|
|
.{},
|
|
chattyThread,
|
|
.{ state, chatty_child, chatty_arena },
|
|
);
|
|
chatty_thread.detach();
|
|
}
|
|
|
|
const channel_d = try std.heap.c_allocator.dupe(u8, channel);
|
|
const streamlink_thread = try std.Thread.spawn(
|
|
.{},
|
|
streamlinkThread,
|
|
.{ state, channel_d },
|
|
);
|
|
streamlink_thread.detach();
|
|
}
|
|
|
|
fn streamlinkThread(state: *State, channel: []const u8) !void {
|
|
defer std.heap.c_allocator.free(channel);
|
|
errdefer {
|
|
state.mutex.lock();
|
|
defer state.mutex.unlock();
|
|
|
|
c.glfwShowWindow(state.win);
|
|
}
|
|
|
|
const memfd = try std.os.memfd_create("streamlink_out", 0);
|
|
errdefer std.os.close(memfd);
|
|
const memfile = std.fs.File{ .handle = memfd };
|
|
|
|
var arg_arena = std.heap.ArenaAllocator.init(std.heap.c_allocator);
|
|
defer arg_arena.deinit();
|
|
const pid = spawn: {
|
|
state.mutex.lock();
|
|
defer state.mutex.unlock();
|
|
|
|
var ch_buf: [128]u8 = undefined;
|
|
const lower_channel = std.ascii.lowerString(&ch_buf, channel);
|
|
|
|
const url = try std.fmt.allocPrintZ(arg_arena.allocator(), "https://twitch.tv/{s}", .{lower_channel});
|
|
const quality = try arg_arena.allocator().dupeZ(u8, std.mem.sliceTo(&state.quality_buf, 0));
|
|
|
|
const streamlink_argv = try arg_arena.allocator().allocSentinel(
|
|
?[*:0]const u8,
|
|
3,
|
|
null,
|
|
);
|
|
|
|
streamlink_argv[0] = "streamlink";
|
|
streamlink_argv[1] = url;
|
|
streamlink_argv[2] = quality;
|
|
|
|
// Doing it the C way because zig's ChildProcess ain't got this
|
|
const pid = try std.os.fork();
|
|
if (pid == 0) {
|
|
try std.os.dup2(memfd, 1);
|
|
try std.os.dup2(memfd, 2);
|
|
return std.os.execvpeZ(streamlink_argv[0].?, streamlink_argv, std.c.environ);
|
|
}
|
|
|
|
break :spawn pid;
|
|
};
|
|
|
|
var success = std.os.waitpid(pid, 0).status == 0;
|
|
|
|
var size = (try memfile.stat()).size;
|
|
if (size == 0) {
|
|
try memfile.writeAll("<no output>");
|
|
size = (try memfile.stat()).size;
|
|
}
|
|
|
|
const mem = try std.os.mmap(
|
|
null,
|
|
size,
|
|
std.os.PROT.READ,
|
|
.{ .TYPE = .PRIVATE },
|
|
memfd,
|
|
0,
|
|
);
|
|
|
|
// If the stream ends, this silly program still exits with a non-zero status.
|
|
success = success or std.mem.containsAtLeast(u8, mem, 1, "Stream ended");
|
|
|
|
state.mutex.lock();
|
|
defer state.mutex.unlock();
|
|
|
|
if (success) {
|
|
std.os.munmap(mem);
|
|
log.info("streamlink exited successfully, closing.", .{});
|
|
c.glfwSetWindowShouldClose(state.win, 1);
|
|
} else {
|
|
state.streamlink_memfd = memfile;
|
|
state.streamlink_out = mem;
|
|
c.glfwShowWindow(state.win);
|
|
}
|
|
}
|
|
|
|
fn chattyThread(state: *State, child: std.ChildProcess, arena: std.heap.ArenaAllocator) !void {
|
|
// no need to get the mutex here, chatty_alive is atomic
|
|
@atomicStore(bool, &state.chatty_alive, true, .unordered);
|
|
defer @atomicStore(bool, &state.chatty_alive, false, .unordered);
|
|
|
|
var ch = child;
|
|
defer arena.deinit();
|
|
_ = ch.spawnAndWait() catch |e| {
|
|
std.log.err("Spawning Chatty: {!}", .{e});
|
|
};
|
|
}
|