feat: add description checkbox

This commit is contained in:
LordMZTE 2023-03-22 18:52:19 +01:00
parent b1a847cf2c
commit ff6aa2f93a
Signed by: LordMZTE
GPG key ID: B64802DC33A64FF6
5 changed files with 82 additions and 37 deletions

View file

@ -5,12 +5,14 @@ class EnqueueTask {
var url:String; var url:String;
var outname:Null<String>; var outname:Null<String>;
var prepend:Bool; var prepend:Bool;
var description:Bool;
var audio_only:Bool; var audio_only:Bool;
public function new(url:String, outname:Null<String>, prepend:Bool, audio_only:Bool) { public function new(url:String, outname:Null<String>, prepend:Bool, description:Bool, audio_only:Bool) {
this.url = url; this.url = url;
this.outname = outname; this.outname = outname;
this.prepend = prepend; this.prepend = prepend;
this.description = description;
this.audio_only = audio_only; this.audio_only = audio_only;
} }

View file

@ -38,6 +38,7 @@ function onEnqSubmit(e:Dynamic):Void {
url_inp.value, url_inp.value,
outname.length == 0 ? null : outname, outname.length == 0 ? null : outname,
cast(Browser.document.getElementById("prepend_switch"), InputElement).checked, cast(Browser.document.getElementById("prepend_switch"), InputElement).checked,
cast(Browser.document.getElementById("description_switch"), InputElement).checked,
cast(Browser.document.getElementById("audio_only_switch"), InputElement).checked cast(Browser.document.getElementById("audio_only_switch"), InputElement).checked
).send(); ).send();

View file

@ -3,9 +3,28 @@ const std = @import("std");
const State = @import("State.zig"); const State = @import("State.zig");
pub const Task = struct { pub const Task = struct {
/// URL of the video
url: []const u8, url: []const u8,
/// Optional output file name or yt-dlp format string
outname: ?[]const u8, outname: ?[]const u8,
/// Extract audio
audio_only: bool, audio_only: bool,
/// Write description
description: bool,
pub fn copy(self: *const Task) !Task {
return .{
.url = try std.heap.c_allocator.dupe(u8, self.url),
.outname = blk: {
break :blk try std.heap.c_allocator.dupe(u8, self.outname orelse break :blk null);
},
.description = self.description,
.audio_only = self.audio_only,
};
}
}; };
state: *State, state: *State,
@ -36,13 +55,7 @@ pub fn spawn(state: *State) !*DownloadQueue {
/// Adds a task to the queue. The task given is copied. /// Adds a task to the queue. The task given is copied.
pub fn pushTask(self: *DownloadQueue, task: Task, prepend: bool) !void { pub fn pushTask(self: *DownloadQueue, task: Task, prepend: bool) !void {
const node = try std.heap.c_allocator.create(std.TailQueue(Task).Node); const node = try std.heap.c_allocator.create(std.TailQueue(Task).Node);
node.* = .{ .data = .{ node.* = .{ .data = try task.copy() };
.url = try std.heap.c_allocator.dupe(u8, task.url),
.outname = blk: {
break :blk try std.heap.c_allocator.dupe(u8, task.outname orelse break :blk null);
},
.audio_only = task.audio_only,
} };
self.m.lock(); self.m.lock();
defer self.m.unlock(); defer self.m.unlock();
@ -100,7 +113,7 @@ fn next(self: *DownloadQueue) !void {
std.log.info("downlading URL `{s}`", .{task.url}); std.log.info("downlading URL `{s}`", .{task.url});
var argv = try std.BoundedArray([]const u8, 8).init(0); var argv = try std.BoundedArray([]const u8, 16).init(0);
try argv.append("yt-dlp"); try argv.append("yt-dlp");
try argv.append("--quiet"); try argv.append("--quiet");
@ -111,10 +124,22 @@ fn next(self: *DownloadQueue) !void {
try argv.append("--extract-audio"); try argv.append("--extract-audio");
} }
if (task.description) {
try argv.append("--write-description");
}
try argv.append("--output");
var outfile_buf: [512]u8 = undefined; var outfile_buf: [512]u8 = undefined;
if (task.outname) |outname| { if (task.outname) |outname| {
try argv.append("--output"); // If outname contains format specifiers, don't append file ext stuff
try argv.append(try std.fmt.bufPrint(&outfile_buf, "{s}.%(ext)s", .{outname})); if (std.mem.containsAtLeast(u8, outname, 1, "%")) {
try argv.append(outname);
} else {
try argv.append(try std.fmt.bufPrint(&outfile_buf, "{s}.%(ext)s", .{outname}));
}
} else {
try argv.append("%(uploader)s - %(title)s.%(ext)s");
} }
try argv.append(task.url); try argv.append(task.url);

View file

@ -1,70 +1,74 @@
body { body {
border-radius: 0; border-radius: 0;
font-family: monospace; font-family: monospace;
color: #f8f8f2; color: #f8f8f2;
background-color: #282a36; background-color: #282a36;
} }
a { a {
color: #bd93f9; color: #bd93f9;
} }
a:visited { a:visited {
color: #ff79c6; color: #ff79c6;
} }
#enqueue_form { #enqueue_form {
width: 100%; width: 100%;
} }
#enqueue_form *:not([type="checkbox"]), #enqueue_form *:not([type="checkbox"]),
#pause_btn { #pause_btn {
display: block; display: block;
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
margin: 0; margin: 0;
} }
#tasks_tbl td { #tasks_tbl td {
border: 1px solid #f8f8f2; border: 1px solid #f8f8f2;
} }
#tasks_tbl { #tasks_tbl {
width: 100%; width: 100%;
} }
.gray { .gray {
color: #6272a4; color: #6272a4;
} }
button, button,
input { input {
border: 2px solid #f8f8f2; border: 2px solid #f8f8f2;
background-color: #282a36; background-color: #282a36;
color: #f8f8f2; color: #f8f8f2;
} }
button:hover, button:hover,
input[type="submit"]:hover { input[type="submit"]:hover {
cursor: pointer; cursor: pointer;
} }
button.vid_del_btn:hover { button.vid_del_btn:hover {
background-color: #ff5555; background-color: #ff5555;
} }
#enqueue_btn:hover { #enqueue_btn:hover {
background-color: #8be9fd; background-color: #8be9fd;
} }
#pause_btn:hover { #pause_btn:hover {
background-color: #ffb86c; background-color: #ffb86c;
} }
ul { ul {
list-style-type: square; list-style-type: square;
} }
.audio_only_txt { .audio_only_txt {
color: #ff5555; color: #ff5555;
}
.description_txt {
color: #8be9fd;
} }

View file

@ -13,6 +13,10 @@ const audio_only_prefix_html =
\\<span class="audio_only_txt">Audio Only </span> \\<span class="audio_only_txt">Audio Only </span>
; ;
const description_prefix_html =
\\<span class="description_txt">Description </span>
;
pub fn routeCb(comptime routeFn: anytype, comptime has_state: bool) *anyopaque { pub fn routeCb(comptime routeFn: anytype, comptime has_state: bool) *anyopaque {
return @intToPtr(*anyopaque, @ptrToInt(&struct { return @intToPtr(*anyopaque, @ptrToInt(&struct {
fn f( fn f(
@ -85,10 +89,11 @@ pub fn indexRoute(
if (state.downloads.active_task) |active| { if (state.downloads.active_task) |active| {
try w.print( try w.print(
\\<p>Active task: <b>{s}{s}</b> -> <b>{s}</b></p> \\<p>Active task: <b>{s}{s}{s}</b> -> <b>{s}</b></p>
\\<hr> \\<hr>
, ,
.{ .{
if (active.description) description_prefix_html else "",
if (active.audio_only) audio_only_prefix_html else "", if (active.audio_only) audio_only_prefix_html else "",
active.url, active.url,
active.outname orelse inferred_html, active.outname orelse inferred_html,
@ -104,9 +109,10 @@ pub fn indexRoute(
var task = state.downloads.tasks.last; var task = state.downloads.tasks.last;
while (task) |t| { while (task) |t| {
try w.print( try w.print(
\\<tr><td>{s}{s}</td><td>{s}</td></tr> \\<tr><td>{s}{s}{s}</td><td>{s}</td></tr>
, ,
.{ .{
if (t.data.description) description_prefix_html else "",
if (t.data.audio_only) audio_only_prefix_html else "", if (t.data.audio_only) audio_only_prefix_html else "",
t.data.url, t.data.url,
t.data.outname orelse inferred_html, t.data.outname orelse inferred_html,
@ -134,6 +140,7 @@ pub fn indexRoute(
\\ <input type="text" placeholder="URL" id="url_inp"><br> \\ <input type="text" placeholder="URL" id="url_inp"><br>
\\ <input type="text" placeholder="output name" id="outname_inp"><br> \\ <input type="text" placeholder="output name" id="outname_inp"><br>
\\ <input type="checkbox" id="prepend_switch">Prepend<br> \\ <input type="checkbox" id="prepend_switch">Prepend<br>
\\ <input type="checkbox" id="description_switch">Description<br>
\\ <input type="checkbox" id="audio_only_switch">Audio Only<br> \\ <input type="checkbox" id="audio_only_switch">Audio Only<br>
\\ <input type="submit" id="enqueue_btn" value="Enqueue"> \\ <input type="submit" id="enqueue_btn" value="Enqueue">
\\</form> \\</form>
@ -241,6 +248,7 @@ pub const ApiTask = struct {
url: []const u8, url: []const u8,
outname: ?[]const u8, outname: ?[]const u8,
audio_only: bool = false, audio_only: bool = false,
description: bool = false,
prepend: bool = false, prepend: bool = false,
}; };
@ -282,7 +290,12 @@ pub fn vidsRoute(
std.log.info("adding {s} to queue", .{task.url}); std.log.info("adding {s} to queue", .{task.url});
try state.downloads.pushTask( try state.downloads.pushTask(
.{ .url = task.url, .outname = task.outname, .audio_only = task.audio_only }, .{
.url = task.url,
.outname = task.outname,
.audio_only = task.audio_only,
.description = task.description,
},
task.prepend, task.prepend,
); );