dotfiles/scripts/playvid/src/main.zig

86 lines
2.7 KiB
Zig

const std = @import("std");
pub const std_options = std.Options{
.log_level = .debug,
.logFn = @import("common").logFn,
};
pub fn main() !u8 {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const alloc = gpa.allocator();
var file_buf: [std.os.PATH_MAX]u8 = undefined;
const file = try findVideoFile(alloc, &file_buf);
try std.io.getStdOut().writer().print("playing: `{s}`\n", .{file});
var child = std.process.Child.init(&.{ "mpv", file }, alloc);
const term = try child.spawnAndWait();
if (!std.meta.eql(term, .{ .Exited = 0 })) return 1;
if (try promtForDeletion(file)) {
try std.io.getStdOut().writer().print("deleting: `{s}`\n", .{file});
try std.fs.cwd().deleteFile(file);
}
return 0;
}
fn findVideoFile(alloc: std.mem.Allocator, out_buf: []u8) ![]const u8 {
var basedir: []const u8 = ".";
if (std.os.argv.len >= 2) {
const arg = std.mem.span(std.os.argv[1]);
if ((try std.fs.cwd().statFile(arg)).kind == .directory) {
basedir = arg;
} else {
if (arg.len > out_buf.len) return error.OutOfMemory;
@memcpy(out_buf[0..arg.len], arg);
return out_buf[0..arg.len];
}
}
var fname_arena = std.heap.ArenaAllocator.init(alloc);
defer fname_arena.deinit();
var cwd_iter = try std.fs.cwd().openDir(basedir, .{ .iterate = true });
defer cwd_iter.close();
var iter = cwd_iter.iterate();
var files = std.ArrayList([]const u8).init(alloc);
defer files.deinit();
while (try iter.next()) |entry| {
switch (entry.kind) {
.file => {
try files.append(try fname_arena.allocator().dupe(u8, entry.name));
},
else => {},
}
}
if (files.items.len == 0) return error.DirectoryEmpty;
const idx = std.crypto.random.uintLessThan(usize, files.items.len);
if (files.items[idx].len > out_buf.len) return error.OutOfMemory;
@memcpy(out_buf[0..files.items[idx].len], files.items[idx]);
return out_buf[0..files.items[idx].len];
}
fn promtForDeletion(file: []const u8) !bool {
try std.io.getStdOut().writer().print("delete file `{s}`? [Y/N] ", .{file});
const old_termios = try std.os.tcgetattr(std.os.STDIN_FILENO);
var new_termios = old_termios;
new_termios.lflag.ICANON = false; // No line buffering
try std.os.tcsetattr(std.os.STDIN_FILENO, .NOW, new_termios);
defer std.os.tcsetattr(std.os.STDIN_FILENO, .NOW, old_termios) catch {};
const answer = try std.io.getStdIn().reader().readByte();
const ret = switch (answer) {
'y', 'Y' => true,
else => false,
};
try std.io.getStdOut().writeAll("\n");
return ret;
}