#!/usr/local/bin/perl

use strict;
use warnings;
use Scalar::Util qw(looks_like_number);
use File::HomeDir qw(home);
use File::Basename qw(basename);
use Cwd qw(cwd);
use Term::ReadKey;
use Capture::Tiny qw(capture);
use POSIX qw(setsid);

use constant {
	TERMINAL_PATH	=> '/usr/local/bin/st',
	MPVIEW_PATH		=> '/home/jozan/.local/bin/mpview',
	MPV_PATH		=> '/usr/local/bin/mpv',
	YTDL_PATH		=> '/usr/local/bin/yt-dlp',
	FETCH_PATH		=> '/usr/bin/fetch',
	IMGVIEW_PATH	=> '/usr/local/bin/nsxiv',
	ZATHURA_PATH	=> '/usr/local/bin/zathura',
	W3M_PATH		=> '/usr/local/bin/w3m',
	BROWSER_PATH	=> '/usr/local/bin/firefox',
	NOTIFYSEND_PATH	=> '/usr/local/bin/notify-send'
};
use constant PROG_LIST	=> "" .
"mpv"					. "\n" .
"mpv-term"				. "\n" .
"youtube-dl"			. "\n" .
"youtube-dl thumbnail"	. "\n" .
"fetch"					. "\n" .
"nsxiv"					. "\n" .
"zathura"				. "\n" .
"w3m"					. "\n" .
"firefox"				. "\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(MPVIEW_PATH, $url) != 0) {
			system(
				NOTIFYSEND_PATH,
				'-u', 'critical',
				'-t', '10000',
				'playback failed',
				'  Failed to open <b>' . $url . '</b>'
				);
		}
		exit 0;
	}
	elsif ($a eq "mpv-term") {
		exec(TERMINAL_PATH, '-e', MPV_PATH, '--audio-channels=stereo', $url);
	}
	elsif ($a eq "fetch" || $a eq "youtube-dl") {
		$pid = fork();
		if (not $pid) {
			setsid();
			$ret = -1;
			if ($a eq "youtube-dl") {
				$list = QUAL_LIST;
				$quality = `printf "$list" | dmenu -i -l 8 -m 0`;
				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 = `youtube-dl -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',
					'  <b>' . $file_name . '</b> 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);
						}
						else {
							system(YTDL_PATH . " -f '[height<=" . $quality . "]' --newline --add-metadata " . $url . ' >' . $tmpfile);
						}
					};
					if ($ret == 0) {
						system(
							NOTIFYSEND_PATH,
							'-u', 'normal',
							'-t', '10000',
							'download complete',
							'  <b>' . $file_name . '</b> downloaded successfully to ' .
							'<b>' . $pwd . '</b>'
							);
					}
					else {
						system(
							NOTIFYSEND_PATH,
							'-u', 'critical',
							'-t', '10000',
							'download failed',
							'  failed to download <b>' . $file_name . '</b>'
							);
					}
					exit 0;
				}
				elsif ($pid2 < 0) {
					system(
						NOTIFYSEND_PATH,
						'-u', 'critical',
						'-t', '10000',
						'download failed',
						'  failed to <b>fork(2)</b>'
						);
					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 <b>' . $file_name . '</b>'
							);
							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',
					'  <b>' . $file_name . '</b> started downloading'
				);
				(undef, undef, $ret) = capture {
					system(FETCH_PATH, $url);
				};
				if ($ret == 0) {
					system(
						NOTIFYSEND_PATH,
						'-u', 'normal',
						'-t', '10000',
						'download complete',
						'  <b>' . $file_name . '</b> downloaded successfully to ' .
						'<b>' . $pwd . '</b>'
						);
				}
				else {
					system(
						NOTIFYSEND_PATH,
						'-u', 'critical',
						'-t', '10000',
						'download failed',
						'  failed to download <b>' . $file_name . '</b>'
						);
				}
			}
			exit 0;
		}
		elsif ($pid < 0) {
			system(
				NOTIFYSEND_PATH,
				'-u', 'critical',
				'-t', '10000',
				'download failed',
				'  failed to <b>fork(2)</b>'
				);
			exit 0;
		}
		else {
			exit 0;
		}
	}
	elsif ($a eq "youtube-dl 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 = `youtube-dl -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 <b>'. $file_name . '</b>'
				);
			($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 <b>'. $file_name . '</b>'
					);
				exit 0;
			}
			system(FETCH_PATH, '-q', $tmp);
			$file_name = $tmp;
			$file_name =~ s/.+\///g;
			chomp $file_name;
			system(IMGVIEW_PATH, '-f', '-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 <b>'. $file_name . '</b> to <b>/tmp</b>'
				);
			system(FETCH_PATH, '-q', $url);
			if ($a == "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 "firefox") {
		$pid = fork();
		if (not $pid) {
			setsid();
			capture {
				exec(BROWSER_PATH, $url);
			};
		}
	}
	return;
}

sub dmenu_prompt
{
	my ($url) = @_;
	my $answer;
	my $list = PROG_LIST;

	$answer = `printf "$list\nURL: $url\n" | dmenu -i -l 11 -m 0`;
	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__