#!/usr/bin/env perl
use strict;
use warnings;
use Sys::Hostname;
use Scalar::Util qw(looks_like_number);
use File::HomeDir qw(home);
use File::Basename qw(basename);
use Cwd qw(cwd);
use Env qw(BROWSER TERMINAL);
use Term::ReadKey;
use Capture::Tiny qw(capture);
use POSIX qw(setsid);
use feature qw(switch);
no warnings qw(experimental::smartmatch);
use constant {
TERMINAL_PATH => $TERMINAL,
MPV_PATH => 'mpv',
YTDL_PATH => 'yt-dlp',
FETCH_PATH => 'fetch',
CURL_PATH => 'curl',
IMGVIEW_PATH => 'nsxiv',
ZATHURA_PATH => 'zathura',
W3M_PATH => 'w3m',
BROWSER_PATH => $BROWSER,
NOTIFYSEND_PATH => 'notify-send',
COPYQ_PATH => 'copyq',
HOSTNAME => (split /\./, hostname())
};
use constant PROG_LIST => "" .
"mpv" . "\n" .
"mpv-term" . "\n" .
"ytdl" . "\n" .
"ytdl thumbnail" . "\n" .
"fetch" . "\n" .
"nsxiv" . "\n" .
"zathura" . "\n" .
"w3m" . "\n" .
"browser" . "\n" .
"clip" . "\n";
use constant QUAL_LIST => "" .
"1440" . "\n" .
"1080" . "\n" .
"720" . "\n" .
"480" . "\n" .
"360" . "\n" .
"240" . "\n" .
"144" . "\n" .
"uncap" . "\n";
sub open_link
{
my ($a, $url) = @_;
my $count;
my $file_name;
my $i;
my $list;
my $pid;
my $pid2;
my $pwd;
my $quality;
my $ret;
my $tmp;
my $tmpfile;
my $val;
my @wc;
if ($a eq "mpv") {
if (system(MPV_PATH, $url) != 0) {
system(
NOTIFYSEND_PATH,
'-u', 'critical',
'-t', '10000',
'playback failed',
' Failed to open ' . $url . ''
);
}
exit 0;
}
elsif ($a eq "mpv-term") {
exec(TERMINAL_PATH, '-e', MPV_PATH, '--audio-channels=stereo', $url);
}
elsif ($a eq "fetch" || $a eq "ytdl") {
$pid = fork();
if (not $pid) {
setsid();
$ret = -1;
if ($a eq "ytdl") {
$list = QUAL_LIST;
$quality = `printf "$list" | dmenu -i -l 8`;
if (not $quality) {
exit 0;
}
chomp $quality;
chdir home() . "/dl" or
chdir home() . "/Downloads" or
chdir home() or die $!;
if (basename(cwd()) eq basename(home())) {
$pwd = '~/';
}
else {
$pwd = '~/' . basename(cwd());
}
$file_name = $url;
$file_name =~ s/.+\///g;
$file_name = `yt-dlp -e $url`;
if (not $file_name) {
$file_name = "YouTube video";
}
chomp $file_name;
@wc = split / /, $file_name;
if (@wc > 8) {
$file_name = "";
$i = 0;
while ($i < 8) {
$file_name .= "$wc[$i] ";
$i++;
}
$file_name .= "[...]";
}
$file_name =~ s/^[0-9]+/\[\.\.\.\]/;
system(
NOTIFYSEND_PATH,
'-u', 'low',
'-t', '2000',
'download started',
' ' . $file_name . ' started downloading'
);
$tmpfile = `mktemp`;
chomp $tmpfile;
$pid2 = fork();
if (not $pid2) {
(undef, undef, $ret) = capture {
if ($quality eq 'uncap') {
system(YTDL_PATH . ' --newline --add-metadata ' . $url . ' >' . $tmpfile);
}
elsif ($quality eq '1440') {
system(YTDL_PATH . " -f '308+140' --newline --add-metadata " . $url . ' >' . $tmpfile);
}
elsif ($quality eq '1080') {
system(YTDL_PATH . " -f '299+140' --newline --add-metadata " . $url . ' >' . $tmpfile);
}
elsif ($quality eq '720') {
system(YTDL_PATH . " -f '298+140' --newline --add-metadata " . $url . ' >' . $tmpfile);
}
else {
system(YTDL_PATH . " -f '[height<=" . $quality . "]' --newline --add-metadata " . $url . ' >' . $tmpfile);
}
};
if ($ret == 0) {
system(
NOTIFYSEND_PATH,
'-u', 'normal',
'-t', '10000',
'download complete',
' ' . $file_name . ' downloaded successfully to ' .
'' . $pwd . ''
);
}
else {
system(
NOTIFYSEND_PATH,
'-u', 'critical',
'-t', '10000',
'download failed',
' failed to download ' . $file_name . ''
);
}
exit 0;
}
elsif ($pid2 < 0) {
system(
NOTIFYSEND_PATH,
'-u', 'critical',
'-t', '10000',
'download failed',
' failed to fork(2)'
);
exit 0;
}
else {
$count = 0;
while (1) {
$val = `tail -n 1 "$tmpfile" | awk '{print \$2}' | tr -d '%'`;
if (looks_like_number($val) != 0) {
system(
NOTIFYSEND_PATH,
'-h',
'int:value:' . $val,
'-u', 'low',
'-t', '5000',
'downloading',
' downloading ' . $file_name . ''
);
if ($val == 100 || system('pgrep python >/dev/null 2>&1') != 0) {
last;
}
}
else {
if ($count == 10) {
last;
}
$count += 1;
}
sleep 2;
}
unlink $tmpfile;
}
exit 0;
}
else {
chdir home() . "/dl" or
chdir home() . "/Downloads" or
chdir home() or die $!;
if (basename(cwd()) eq basename(home())) {
$pwd = '~/';
}
else {
$pwd = '~/' . basename(cwd());
}
$file_name = $url;
$file_name =~ s/.+\///g;
@wc = split / /, $file_name;
if (@wc > 8) {
$file_name = "";
$i = 0;
while ($i < 8) {
$file_name .= "$wc[$i] ";
$i++;
}
$file_name .= "[...]";
}
$file_name =~ s/^[0-9]+/\[\.\.\.\]/;
system(
NOTIFYSEND_PATH,
'-u', 'low',
'-t', '10000',
'download started',
' ' . $file_name . ' started downloading'
);
(undef, undef, $ret) = capture {
if (HOSTNAME eq "mother" or "po-rbo") {
system(CURL_PATH, "-fsSLO", $url);
} elsif (HOSTNAME == "mars") {
system(FETCH_PATH, $url);
}
};
if ($ret == 0) {
system(
NOTIFYSEND_PATH,
'-u', 'normal',
'-t', '10000',
'download complete',
' ' . $file_name . ' downloaded successfully to ' .
'' . $pwd . ''
);
}
else {
system(
NOTIFYSEND_PATH,
'-u', 'critical',
'-t', '10000',
'download failed',
' failed to download ' . $file_name . ''
);
}
}
exit 0;
}
elsif ($pid < 0) {
system(
NOTIFYSEND_PATH,
'-u', 'critical',
'-t', '10000',
'download failed',
' failed to fork(2)'
);
exit 0;
}
else {
exit 0;
}
}
elsif ($a eq "ytdl thumbnail") {
$pid = fork();
if (not $pid) {
setsid();
chdir '/tmp' or die $!;
$file_name = $url;
$file_name =~ s/.+\///g;
if ($file_name =~ m/^watch\?v=.+/) {
$file_name = `yt-dlp -e $url`;
if (not $file_name) {
$file_name = "Youtube video";
}
chomp $file_name;
}
system(
NOTIFYSEND_PATH,
'-u', 'low',
'-t', '5000',
'download started',
' fetching thumbnail for '. $file_name . ''
);
($tmp, undef, $ret) = capture {
system(YTDL_PATH, '--get-thumbnail', $url);
};
chomp $tmp;
if ($ret != 0) {
system(
NOTIFYSEND_PATH,
'-u', 'critical',
'-t', '10000',
'failed to get thumbnail',
' failed to get thumbail for '. $file_name . ''
);
exit 0;
}
given (HOSTNAME) {
when(["mother", "po-rbo"]) {
system(CURL_PATH, "-fsSLO", $tmp);
}
when("mars") {
system(FETCH_PATH, '-q', $tmp);
}
}
$file_name = $tmp;
$file_name =~ s/.+\///g;
chomp $file_name;
system(IMGVIEW_PATH, '-b', '-a', $file_name);
unlink($file_name);
exit 0;
}
}
elsif ($a eq "nsxiv" || $a eq "zathura") {
$pid = fork();
if (not $pid) {
setsid();
chdir '/tmp' or die $!;
$file_name = $url;
$file_name =~ s/.+\///g;
system(
NOTIFYSEND_PATH,
'-u', 'low',
'-t', '5000',
'download started',
' fetching '. $file_name . ' to /tmp'
);
given (HOSTNAME) {
when(["mother", "po-rbo"]) {
system(CURL_PATH, "-fsSLO", $url);
}
when("mars") {
system(FETCH_PATH, '-q', $url);
}
}
if ($a eq "nsxiv") {
exec(IMGVIEW_PATH, '-b', '-a', $file_name);
}
else {
exec(ZATHURA_PATH, $file_name);
}
}
}
elsif ($a eq "w3m") {
exec(TERMINAL_PATH, '-e', W3M_PATH, $url);
}
elsif ($a eq "browser") {
$pid = fork();
if (not $pid) {
setsid();
capture {
exec(BROWSER_PATH, $url);
};
}
}
elsif ($a eq "clip") {
$pid = fork();
if (not $pid) {
setsid();
capture {
exec(COPYQ_PATH, "copy", $url);
};
}
}
return;
}
sub dmenu_prompt
{
my ($url) = @_;
my $answer;
my $list = PROG_LIST;
$answer = `printf "$list\nURL: $url\n" | dmenu -i`;
chomp $answer;
return $answer;
}
sub main
{
my $answer;
if (@ARGV == 0) {
print STDERR "linkview: no URL\n";
exit 1;
}
$answer = dmenu_prompt($ARGV[0]);
open_link($answer, $ARGV[0]);
return;
}
main();
__END__