#!/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 fileparse);
use Cwd qw(cwd);
use Env qw(BROWSER TERMINAL);
use Capture::Tiny qw(capture);
use POSIX qw(setsid);
use Data::UUID;
my $menu = "fzf";
use constant {
	TERMINAL_PATH	=> $TERMINAL,
	MPV_PATH		=> 'mpv',
	YTDL_PATH		=> 'yt-dlp',
	IMGVIEW_PATH	=> 'nsxiv -b -a',
	FETCH_PATH		=> 'fetch',
	CURL_PATH		=> 'curl',
	ZATHURA_PATH	=> 'zathura',
	W3M_PATH		=> 'w3m',
	BROWSER_PATH	=> $BROWSER,
	NOTIFYSEND_PATH	=> 'notify-send',
	COPYQ_PATH		=> 'copyq',
	HOSTNAME		=> (split /\./, hostname())[0]
};
my @keys      = (  'vid', 'img',     'dl', 'audio',     'pdf', 'w3m', 'web', 'clip' );
my @func_refs = ( \&vid, \&img_pdf, \&dl, \&audio, \&img_pdf, \&w3m, \&web, \&clip );
my %func_list;
@func_list{@keys} = @func_refs;
use constant QUAL_LIST	=> "" .
"uncap"		. "\n" .
"1440"		. "\n" .
"1080"		. "\n" .
"720"		. "\n" .
"480"		. "\n" .
"360"		. "\n" .
"240"		. "\n" .
"144"		. "\n";
sub vid
{
	my ($url, $article_name) = @_;
	my $pid;
	$article_name = "some media" unless defined $article_name;
	$pid = fork();
	if (not $pid) {
		setsid();
		close_io();
		system(
			NOTIFYSEND_PATH,
			'-t', '2000',
			'playing media',
			'  playing ' . $article_name . ''
		);
		if (system(MPV_PATH, "--force-window=yes", $url) != 0) {
			exec(
				NOTIFYSEND_PATH,
				'-u', 'critical',
				'-t', '10000',
				'playback failed',
				'  failed to open ' . $url . ''
			);
		}
		return;
	}
	return;
}
sub img_pdf
{
	my ($url, $article_name, $key) = @_;
	my $file_name;
	my $new_file_name;
	my $pid;
	my $ret;
	my $tmp;
	my $ug;
	my $uuid;
	$article_name = "some media" if ($article_name eq "");
	$pid = fork();
	if (not $pid) {
		setsid();
		close_io();
		chdir '/tmp' or die $!;
		$file_name = $url;
		$file_name =~ s/.+\///g;
		if (is_yt($url) != 0) {
			system(
				NOTIFYSEND_PATH,
				'-t', '5000',
				'fetching thumbnail',
				'  fetching thumbnail for ' . $article_name . ''
			);
			($tmp, undef, $ret) = capture {
				system(YTDL_PATH, '--get-thumbnail', $url);
			};
			chomp $tmp;
			if ($ret != 0) {
				system(
					NOTIFYSEND_PATH,
					'-u', 'critical',
					'failed to get thumbnail',
					'  failed to get thumbail for ' . $article_name . ''
				);
				return;
			}
			$url = $tmp;
		}
		else {
			system(
				NOTIFYSEND_PATH,
				'-t', '5000',
				'download started',
				'  fetching '. $file_name . ' to /tmp'
			);
		}
		$file_name = $url;
		$file_name =~ s/.+\///g;
		if (HOSTNAME eq "mother" or "po-rbo") {
			system(CURL_PATH, "-fsSLO", $url);
		} elsif (HOSTNAME == "mars") {
			system(FETCH_PATH, "-q", $url);
		}
		my ($name, undef, $ext) = fileparse($file_name, qr/\.[^.]*/);
		$ug = Data::UUID->new;
		$uuid = $ug->create_str();
		$ext =~ s/\?.*//;
		$new_file_name = $uuid . $ext;
		rename($file_name, $new_file_name) or die $!;
		if ($key =~ /img/) {
			$ret = system(IMGVIEW_PATH . " " . $new_file_name);
		}
		else {
			$ret = system(ZATHURA_PATH, $new_file_name);
		}
		if ($ret != 0) {
			system(
				NOTIFYSEND_PATH,
				'-u', 'critical',
				'failed to open image',
				'  failed to open file /tmp/'. $new_file_name . ''
				);
		}
		unlink($new_file_name);
		return;
	}
	return;
}
sub dl
{
	my ($url) = @_;
	my $count;
	my $file_name;
	my $i;
	my $list;
	my $pid;
	my $pid2;
	my $pwd;
	my $quality;
	my $ret;
	my $tmpfile;
	my $val;
	my @wc;
	if (is_yt($url) != 0) {
		$list = QUAL_LIST;
		$quality = `printf "$list" | $menu --prompt 'quality > '`;
		if (not $quality) {
			return;
		}
		chomp $quality;
	}
	$pid = fork();
	if (not $pid) {
		setsid();
		close_io();
		$ret = -1;
		chdir home() . "/dl" or
		chdir home() . "/Downloads" or
		chdir home() or die $!;
		if (basename(cwd()) eq basename(home())) {
			$pwd = '~/';
		}
		else {
			$pwd = '~/' . basename(cwd());
		}
		if (is_yt($url) != 0) {
			$file_name = get_yt_vid_name($url);
		}
		else {
			$file_name = $url;
			$file_name =~ s/.+\///g;
		}
		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,
			'-t', '2000',
			'download starting',
			'  downloading ' . $file_name . ''
		);
		if (is_yt($url) != 0) {
			$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',
						'download complete',
						'  ' . $file_name . ' downloaded successfully to ' .
						'' . $pwd . ''
						);
				}
				else {
					system(
						NOTIFYSEND_PATH,
						'-u', 'critical',
						'download failed',
						'  failed to download ' . $file_name . ''
						);
				}
				return;
			}
			elsif ($pid2 < 0) {
				system(
					NOTIFYSEND_PATH,
					'-u', 'critical',
					'download failed',
					'  failed to fork(2)'
					);
				return;
			}
			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 yt-dlp >/dev/null 2>&1') != 0) {
							last;
						}
					}
					else {
						if ($count == 10) {
							last;
						}
						$count += 1;
					}
					sleep 2;
				}
				unlink $tmpfile;
			}
			return;
		}
		else {
			(undef, undef, $ret) = capture {
				if (HOSTNAME eq "mother" or "po-rbo") {
					system(CURL_PATH, "-fsSLO", $url);
				} elsif (HOSTNAME == "mars") {
					system(FETCH_PATH, "-q", $url);
				}
			};
			if ($ret == 0) {
				system(
					NOTIFYSEND_PATH,
					'-u', 'normal',
					'download complete',
					'  ' . $file_name . ' downloaded successfully to ' .
					'' . $pwd . ''
					);
			}
			else {
				system(
					NOTIFYSEND_PATH,
					'-u', 'critical',
					'download failed',
					'  failed to download ' . $file_name . ''
					);
			}
		}
		return;
	}
	elsif ($pid < 0) {
		system(
			NOTIFYSEND_PATH,
			'-u', 'critical',
			'-t', '10000',
			'download failed',
			'  failed to fork(2)'
			);
		return;
	}
	return;
}
sub audio
{
	my ($url, $article_name) = @_;
	my $pid;
	$pid = fork();
	if (not $pid) {
		setsid();
		close_io();
		system(
			NOTIFYSEND_PATH,
			'-t', '2000',
			'playing media',
			'  playing ' . $article_name . ''
		);
		if (system(
				TERMINAL_PATH,
				"-e",
				MPV_PATH,
				"--vo=null",
				"--video=no",
				"--no-video",
				$url
			) != 0) {
			exec(
				NOTIFYSEND_PATH,
				'-u', 'critical',
				'-t', '10000',
				'playback failed',
				'  failed to open ' . $url . ''
			);
		}
		return;
	}
	return;
}
sub w3m
{
	my ($url) = @_;
	my $pid;
	$pid = fork();
	if (not $pid) {
		setsid();
		close_io();
		if (system(TERMINAL_PATH, '-e', W3M_PATH, $url) != 0) {
			exec(
				NOTIFYSEND_PATH,
				'-u', 'critical',
				'-t', '10000',
				'w3m failed',
				'  failed to open ' . $url . ''
			);
		}
		return;
	}
	return;
}
sub web
{
	my ($url) = @_;
	my $pid;
	$pid = fork();
	if (not $pid) {
		setsid();
		close_io();
		exec(BROWSER_PATH, $url);
	}
	return;
}
sub clip
{
	my ($url) = @_;
	my $pid;
	$pid = fork();
	if (not $pid) {
		setsid();
		close_io();
		if (defined $ENV{WAYLAND_DISPLAY}) {
			system("echo -n " . $url . " | wl-copy");
			return;
		}
		else {
			exec(COPYQ_PATH, "copy", $url);
		}
	}
	system(
		NOTIFYSEND_PATH,
		'-t', '2000',
		'clipped url',
		'  clipped url'
	);
	return;
}
sub close_io
{
	open STDIN,  '<', '/dev/null' or die $!;
	open STDOUT, '>', '/dev/null' or die $!;
	open STDERR, '>', '/dev/null' or die $!;
	return;
}
sub is_yt
{
	my ($url) = @_;
	return $url =~ m{
		^(?:https?://)?
		(?:www\.|m\.)?
		(?:youtube\.com|youtu\.be)/
		(?:
			(?:watch\?v=|embed/|v/|shorts/)?
		)
		([\w-]{11})
	}x;
}
sub get_yt_vid_name
{
	my ($url) = @_;
	my $file_name;
	system(
		NOTIFYSEND_PATH,
		'-t', '4000',
		'checking name',
		'  looking for video name'
	);
	$file_name = `yt-dlp -e $url`;
	if (not $file_name) {
		$file_name = "yt video";
	}
	chomp $file_name;
	return $file_name;
}
sub fzf_prompt
{
	my ($url) = @_;
	my $answer;
	my $list;
	$list = join("\n", @keys);
	$answer = `printf "$list\n" | $menu --prompt '$url > '`;
	chomp $answer;
	return $answer;
}
sub linkview
{
	my $answer;
	if (@ARGV == 0 || $ARGV[0] eq '') {
		print STDERR "linkview: no URL\n";
		exit 1;
	}
	$answer = fzf_prompt($ARGV[0]);
	return unless exists $func_list{$answer};
	$func_list{$answer}->($ARGV[0], $ARGV[1], $answer);
	return;
}
linkview();
__END__