#!/usr/bin/perl

use strict;
use LWP::Simple;

# Author: Paul Kocialkowski, based on http://userscripts.org/scripts/show/42944 from "bitbit"
# Copyright: Creative Commons BY-SA 3.0
# Date: 17/10/2010
# Version: 0.1
# Requires: perl-libwww-perl

### Needed tools ###

sub char_at
{
	my $argc = scalar(@_);
	my @argv=@_;

	if($argc != 2)
	{
		print STDERR "Please, specify 2 arguments to this function.\n";
		exit;
	}

	my $string=$argv[0];
	my $length=$argv[1];

	return substr($string, $length-1, 1);
}

sub dec2bin
{
	my $argc = scalar(@_);
	my @argv=@_;

	if($argc != 1)
	{
		print STDERR "Please, specify 1 argument to this function.\n";
		exit;
	}

	return sprintf("%b", $argv[0]);
}

sub bin2dec
{
	my $argc = scalar(@_);
	my @argv=@_;

	if($argc != 1)
	{
		print STDERR "Please, specify 1 argument to this function.\n";
		exit;
	}

	return unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}

sub dec2hex
{
	my $argc = scalar(@_);
	my @argv=@_;

	if($argc != 1)
	{
		print STDERR "Please, specify 1 argument to this function.\n";
		exit;
	}

	my $hex;
	$hex=sprintf("%x", $argv[0]);
	return $hex;
}

sub parse_hex2dec
{
	my $argc = scalar(@_);
	my @argv=@_;

	if($argc != 1)
	{
		print STDERR "Please, specify 1 argument to this function.\n";
		exit;
	}

	my @text=$argv[0] =~ m{^([[0-9A-Fa-f]*).*}gmxs;
	my $hex=sprintf("%d",  hex(@text[0]));

	return $hex;
}

sub parse_bin2dec
{
	my $argc = scalar(@_);
	my @argv=@_;

	if($argc != 1)
	{
		print STDERR "Please, specify 1 argument to this function.\n";
		exit;
	}

	my @bin=$argv[0] =~ m{^([[0-1]*).*}gmxs;
	my $dec=bin2dec($bin[0]);

	return $dec;
}



sub cut_from_end
{
	my $argc = scalar(@_);
	my @argv=@_;

	if($argc != 2)
	{
		print STDERR "Please, specify 2 arguments to this function.\n";
		exit;
	}

	my $text=$argv[0];
	my $cut=$argv[1];

	return substr($text, length($text)-$cut, length($text));
}

### Megavideo Downloader ###

my %megavideo_dl_config=( "quiet" => 0 );

sub megavideo_decrypt
{
	my $argc = scalar(@_);
	my @argv=@_;

	if($argc != 3)
	{
		print STDERR "Please, specify 3 arguments to this function.\n";
		exit;
	}

	if(!$megavideo_dl_config{"quiet"}){ print("[Info] Decrypting Infos.\n"); }

	my $str=$argv[0];
	my $key1=$argv[1];
	my $key2=$argv[2];

	my @loc1;

	my $loc3;
	for ($loc3 = 1; $loc3 <= length($str); ++$loc3) {
		push(@loc1, cut_from_end("000".dec2bin(parse_hex2dec(char_at($str, $loc3))), 4) );
	}

	@loc1=split( "", join("", @loc1));

	my @loc6;
	for ($loc3 = 0; $loc3 < 384; ++$loc3) {
		$key1 = ($key1 * 11 + 77213) % 81371;
		$key2 = ($key2 * 17 + 92717) % 192811;
		@loc6[$loc3] = ($key1 + $key2) % 128;
	}
	for ($loc3 = 256; $loc3 >= 0; --$loc3) {
		my $loc5 = $loc6[$loc3];
		my $loc4 = $loc3 % 128;
		my $loc8 = $loc1[$loc5];
		$loc1[$loc5] = $loc1[$loc4];
		$loc1[$loc4] = $loc8;
	}
	for ($loc3 = 0; $loc3 < 128; ++$loc3) {
		$loc1[$loc3] = $loc1[$loc3] ^ $loc6[$loc3 + 256] & 1;
	}

	my $loc12 = join("", @loc1);

	my @loc7;
	my $loc9;

	for ($loc3 = 0; $loc3 < length($loc12); $loc3 = $loc3 + 4) {
		$loc9 = substr($loc12, $loc3, 4);
		push(@loc7, $loc9);
	}

	my @loc2;

	for ($loc3 = 0; $loc3 < scalar(@loc7); ++$loc3) {
		push(@loc2, dec2hex(parse_bin2dec($loc7[$loc3])) );
	}

	return join("", @loc2);
}

sub megavideo_infos
{
	my $argc = scalar(@_);
	my @argv=@_;

	if($argc != 1)
	{
		print STDERR "Please, specify 1 argument to this function.\n";
		exit;
	}

	if(!$megavideo_dl_config{"quiet"}){ print("[Info] Getting Infos.\n"); }

	my $megavideo_id=$argv[0];
	my $megavideo_video_url;

	my $megavideo_infos_page_url="http://www.megavideo.com/xml/videolink.php?v=$megavideo_id";
	my $megavideo_infos_page_content=get($megavideo_infos_page_url);

	my $str_m=" un=";
	my $key1_m=" k1=";
	my $key2_m=" k2=";
	my $server_m=" s=";

	if(!$megavideo_dl_config{"quiet"}){ print("[Info] Parsing Infos.\n"); }

	if($megavideo_infos_page_content =~ m{.*error="1".*})
	{
		print STDERR "Error: This video has been removed.\n";
		exit;
	}

	my $str=join("", $megavideo_infos_page_content =~ /.*$str_m"([^"]*)"/ );
	my $key1=join("", $megavideo_infos_page_content =~ /.*$key1_m"([^"]*)"/ );
	my $key2=join("", $megavideo_infos_page_content =~ /.*$key2_m"([^"]*)"/ );
	my $server=join("", $megavideo_infos_page_content =~ /.*$server_m"([^"]*)"/ );

	$megavideo_video_url="http://www".$server.".megavideo.com/files/".megavideo_decrypt($str, $key1, $key2)."/megavideo_$megavideo_id.flv";

	if(!$megavideo_dl_config{"quiet"}){ print("[Info] Got video URL.\n"); }

	return $megavideo_video_url;
}

sub megavideo_url_parse
{
	my $argc = scalar(@_);
	my @argv=@_;

	if($argc != 1)
	{
		print STDERR "Please, specify 1 argument to this function.\n";
		exit;
	}

	if(!$megavideo_dl_config{"quiet"}){ print("[Info] Parsing URL.\n"); }

	my $megavideo_link=$argv[0];
	my @megavideo_link_infos=$megavideo_link =~ m{.*[\?&]v=([^&]*)}g;
	my $megavideo_link_id;

	if(scalar(@megavideo_link_infos) != 1)
	{
		print STDERR "Parse failed. Aborting.";
		exit;
	}

	$megavideo_link_id=$megavideo_link_infos[0];
	return $megavideo_link_id;
}

sub megavideo_flash_parse
{
	my $argc = scalar(@_);
	my @argv=@_;

	if($argc != 1)
	{
		print STDERR "Please, specify 1 argument to this function.\n";
		exit;
	}

	if(!$megavideo_dl_config{"quiet"}){ print("[Info] Parsing Flash URL.\n"); }

	my $megavideo_link=$argv[0];
	my @megavideo_link_infos=$megavideo_link =~ m{.*\/v\/([A-Z0-9]{8})}g;
	my $megavideo_link_id;

	if(scalar(@megavideo_link_infos) != 1)
	{
		print STDERR "Parse failed. Aborting.";
		exit;
	}

	$megavideo_link_id=$megavideo_link_infos[0];
	return $megavideo_link_id;
}

sub megavideo_parse
{
	my $argc = scalar(@_);
	my @argv=@_;

	if($argc != 1)
	{
		print STDERR "Please, specify 1 argument to this function.\n";
		exit;
	}

	my $megavideo_link=$argv[0];
	my $megavideo_link_id;

	if($megavideo_link =~ m{.*megavideo.com/.*\?v=.*}g)
	{
		$megavideo_link_id=megavideo_url_parse($megavideo_link);
	}
	elsif($megavideo_link =~ m{.*megavideo.com/v/.*}g)
	{
		$megavideo_link_id=megavideo_flash_parse($megavideo_link);
	}
	else
	{
		print STDERR "Parse failed. Aborting.\n";
		exit;
	}

	return megavideo_infos($megavideo_link_id);
}

sub args_parse
{
	my $argc=$#ARGV+1;
	my @argv=@ARGV;

	my $megavideo_link;
	my $megavideo_link_id;
	my $force_id_append;


	for(my $i=0 ; $i < $argc ; $i++)
	{
		if($argv[$i] =~ /^-(.*)/)
		{
			if($1 eq "f" || $1 eq "-force-id")
			{
				$force_id_append=1;
			}
			elsif($1 eq "q" || $1 eq "-quiet")
			{
				$megavideo_dl_config{"quiet"}=1;
			}
			elsif($1 eq "h" || $1 eq "-help")
			{
				print "megavideo_dl\nUsage: megavideo_dl [OPTIONS] [URL]\n\n";
				print "  -f, --force-id                Force video id\n";
				print "  -q, --quiet                   Only print the video URL\n";
				print "  -h, --help                    Shows this help message\n";
				exit;
			}
			else 
			{
				print STDERR "Unknown or unexpected arg: \"-".$1."\".\n";
			}
		}
		else
		{
			if($force_id_append && !$megavideo_link_id)
			{
				$megavideo_link_id=$argv[$i];
			}
			elsif(!$megavideo_link && !$force_id_append)
			{
				$megavideo_link=$argv[$i];
			}
			else 
			{
				print STDERR "Unknown or unexpected arg: \"".$argv[$i]."\".\n";
			}
		}
	}

	if($force_id_append && $megavideo_link_id)
	{
		print megavideo_infos($megavideo_link_id)."\n";
	}
	elsif($megavideo_link && !$force_id_append)
	{
		print megavideo_parse($megavideo_link)."\n";
	}
	else
	{
		print STDERR "No URL specified. Aborting.\n";
		exit;
	}
}

args_parse;

