diff --git a/PlayBot.pl b/PlayBot.pl
index 23ab7090028548d93e5d4910ccf7aa49b56be1b4..7ba0881551581d7ea63a0e106497f82099a7f87c 100755
--- a/PlayBot.pl
+++ b/PlayBot.pl
@@ -1,14 +1,19 @@
 #!/usr/bin/perl -w
 use strict;
 use warnings;
+
 use POE;
 use POE::Component::IRC;
 use POSIX 'strftime';
 use DBI;
 use Tie::File;
 use JSON;
+use FindBin;
 
+use lib "$FindBin::Bin/lib/";
 use Logging;
+
+use lib "$FindBin::Bin/lib/sites";
 use youtube;
 use soundcloud;
 use mixcloud;
diff --git a/lib/Logging.pm b/lib/Logging.pm
new file mode 100644
index 0000000000000000000000000000000000000000..6b7085bbfda620b556316df2384c1a529e868b98
--- /dev/null
+++ b/lib/Logging.pm
@@ -0,0 +1,606 @@
+package Logging;
+
+# ==============[ Classe pour gérer les logs correctement ]============== #
+#  Date : 29/10/2010                                                      #
+#  Auteur : TC                                                            #
+# ======================================================================= #
+
+use strict;
+use warnings;
+
+use Fcntl ':mode';
+
+
+# ###
+#  new
+# Instancie la classe - un constructeur en somme
+# ###
+sub new
+{
+	my $class = shift;
+	my $self = {
+		_file    =>   shift,
+		_colored =>   0,
+		_pending =>   0,
+		_utf8    =>   0,
+		_right_align => shift,
+	};
+	
+	bless $self, $class;
+	
+	# On active la couleur que si on est sur un terminal
+	# C'est moche après pour les fichiers ou un less
+	if($self->file eq "STDOUT")
+	{
+		$self->{"_colored"} = 1 if((stat(STDOUT))[2] & S_IFCHR);
+	}
+	elsif($self->file eq "STDERR")
+	{
+		$self->{"_colored"} = 1 if((stat(STDERR))[2] & S_IFCHR);
+	}
+	else
+	{
+		$self->{"_colored"} = 1 if((stat($self->file))[2] & S_IFCHR);
+	}
+	
+	
+	unless(defined $self->{"_right_align"})
+	{
+		$self->{"_right_align"} = 0;
+	}
+	
+	return $self;
+} # Fin new
+
+
+# ###
+#  file
+# Renvoie/maj $self->{'_file'}
+# ###
+sub file
+{
+	my $self = shift;
+	$self->{"_file"} = $_[0] if(defined($_[0]));
+	return $self->{"_file"};
+} # Fin file
+
+
+# ###
+#  colored
+# Renvoie/maj $self->{'_colored'}
+# ###
+sub colored
+{
+	my $self = shift;
+	$self->{"_colored"} = $_[0] if(defined($_[0]));
+	return $self->{"_colored"};
+} # Fin colored
+
+
+# ###
+#  pending
+# Renvoie/maj $self->{'_pending'}
+# ###
+sub pending
+{
+	my $self = shift;
+	$self->{"_pending"} = $_[0] if(defined($_[0]));
+	return $self->{"_pending"};
+} # Fin pending
+
+
+# ###
+#  utf8
+# Renvoie/maj $self->{"_utf8"}
+# ###
+sub utf8
+{
+	my $self = shift;
+	$self->{"_utf8"} = $_[0] if(defined($_[0]));
+	return $self->{"_utf8"};
+} # Fin utf8
+
+
+# ###
+#  right_align
+# Renvoie/maj $self->{"_right_align"}
+# ###
+sub right_align
+{
+	my $self = shift;
+	$self->{"_right_align"} = $_[0] if(defined($_[0]));
+	return $self->{"_right_align"};
+} # Fin right_align
+
+
+# ###
+#  debug
+# Fonction gérant les logs du niveau debug (1)
+# ###
+sub debug
+{
+	my ($self, $text) = @_;
+	return unless(defined $text);
+	
+	chomp $text;
+	
+	my $parent = ( caller(1) )[3];
+	$parent = "" if(!defined($parent));
+	
+	if($self->colored)
+	{
+		$text = "\e[36mDEBUG\e[0m:$parent:$text";
+	}
+	else
+	{
+		$text = "DEBUG:$parent:$text";
+	}
+	
+	return $self->print_in_file($text, $self->DEBUG);
+} # Fin debug
+
+
+# ###
+#  pending_debug
+# Fonction gérant les logs du niveau debug (1)
+# ###
+sub pending_debug
+{
+	my ($self, $text) = @_;
+	chomp $text;
+	
+	my $parent = ( caller(1) )[3];
+	$parent = "" if(!defined($parent));
+	
+	if($self->colored)
+	{
+		$text = "\e[36mDEBUG\e[0m:$parent:$text";
+	}
+	else
+	{
+		$text = "DEBUG:$parent:$text";
+	}
+	
+	return $self->pending_in_file($text, $self->DEBUG);
+} # Fin pending_debug
+
+
+# ###
+#  info
+# Fonction gérant les logs du niveau info (2)
+# ###
+sub info
+{
+	my ($self, $text) = @_;
+	return unless(defined $text);
+	
+	chomp $text;
+	
+	my $parent = ( caller(1) )[3];
+	$parent = "" if(!defined($parent));
+	
+	if($self->colored)
+	{
+		$text = "\e[33;1mINFO\e[0m:$parent:$text";
+	}
+	else
+	{
+		$text = "INFO:$parent:$text";
+	}
+	
+	return $self->print_in_file($text, $self->INFO);
+} # Fin info
+
+
+# ###
+#  pending_info
+# Fonction gérant les logs du niveau info (2)
+# ###
+sub pending_info
+{
+	my ($self, $text) = @_;
+	return unless(defined $text);
+	
+	chomp $text;
+	
+	my $parent = ( caller(1) )[3];
+	$parent = "" if(!defined($parent));
+	
+	if($self->colored)
+	{
+		$text = "\e[33;1mINFO\e[0m:$parent:$text";
+	}
+	else
+	{
+		$text = "INFO:$parent:$text";
+	}
+	
+	return $self->pending_in_file($text, $self->INFO);
+} # Fin pending_info
+
+
+# ###
+#  warning
+# Fonction gérant les logs du niveau warning (3)
+# ###
+sub warning
+{
+	my ($self, $text) = @_;
+	return unless(defined $text);
+	
+	chomp $text;
+	
+	my $parent = ( caller(1) )[3];
+	$parent = "" if(!defined($parent));
+	
+	if($self->colored)
+	{
+		$text = "\e[33mWARNING\e[0m:$parent:$text";
+	}
+	else
+	{
+		$text = "WARNING:$parent:$text";
+	}
+	
+	return $self->print_in_file($text, $self->WARNING);
+} # Fin warning
+
+
+# ###
+#  pending_warning
+# Fonction gérant les logs du niveau warning (3)
+# ###
+sub pending_warning
+{
+	my ($self, $text) = @_;
+	return unless(defined $text);
+	
+	chomp $text;
+	
+	my $parent = ( caller(1) )[3];
+	$parent = "" if(!defined($parent));
+	
+	if($self->colored)
+	{
+		$text = "\e[33mWARNING\e[0m:$parent:$text";
+	}
+	else
+	{
+		$text = "WARNING:$parent:$text";
+	}
+	
+	return $self->pending_in_file($text, $self->WARNING);
+} # Fin pending_warning
+
+
+# ###
+#  error
+# Fonction gérant les logs du niveau error (4)
+# ###
+sub error
+{
+	my ($self, $text) = @_;
+	return unless(defined $text);
+	
+	chomp $text;
+	
+	my $parent = ( caller(1) )[3];
+	$parent = "" if(!defined($parent));
+	
+	if($self->colored)
+	{
+		$text = "\e[31mERROR\e[0m:$parent:$text";
+	}
+	else
+	{
+		$text = "ERROR:$parent:$text";
+	}
+	
+	return $self->print_in_file($text, $self->ERROR);
+} # Fin error
+
+
+# ###
+#  pending_error
+# Fonction gérant les logs du niveau error (4)
+# ###
+sub pending_error
+{
+	my ($self, $text) = @_;
+	return unless(defined $text);
+	
+	chomp $text;
+	
+	my $parent = ( caller(1) )[3];
+	$parent = "" if(!defined($parent));
+	
+	if($self->colored)
+	{
+		$text = "\e[31mERROR\e[0m:$parent:$text";
+	}
+	else
+	{
+		$text = "ERROR:$parent:$text";
+	}
+	
+	return $self->pending_in_file($text, $self->ERROR);
+} # Fin pending_error
+
+
+# ###
+#  critical
+# Fonction gérant les logs du niveau critical (5)
+# ###
+sub critical
+{
+	my ($self, $text) = @_;
+	return unless(defined $text);
+	
+	chomp $text;
+	
+	my $parent = ( caller(1) )[3];
+	$parent = "" if(!defined($parent));
+	
+	if($self->colored)
+	{
+		$text = "\e[31;1mCRITICAL\e[0m:$parent:$text";
+	}
+	else
+	{
+		$text = "CRITICAL:$parent:$text";
+	}
+	
+	return $self->print_in_file($text, $self->CRITICAL);
+} # Fin critical
+
+
+# ###
+#  pending_critical
+# Fonction gérant les logs du niveau critical (5)
+# ###
+sub pending_critical
+{
+	my ($self, $text) = @_;
+	return unless(defined $text);
+	
+	chomp $text;
+	
+	my $parent = ( caller(1) )[3];
+	$parent = "" if(!defined($parent));
+	
+	if($self->colored)
+	{
+		$text = "\e[31;1mCRITICAL\e[0m:$parent:$text";
+	}
+	else
+	{
+		$text = "CRITICAL:$parent:$text";
+	}
+	
+	return $self->pending_in_file($text, $self->CRITICAL);
+} # Fin pending_critical
+
+
+# ###
+#  print_in_file
+# Écrit dans le fichier
+# ###
+sub print_in_file
+{
+	my ($self, $text, $level) = @_;
+	return unless(defined $text);
+	
+	chomp $text;
+	$text = "[\e[32m" . (scalar localtime time) . "\e[0m] $text";
+	
+	$self->end_pending(0, $level) if($self->pending);
+	
+	if($self->file eq "STDOUT")
+	{
+		print STDOUT $text."\n";
+	}
+	elsif($self->file eq "STDERR")
+	{
+		print STDERR $text."\n";
+	}
+	else
+	{
+		open LOG, ">>", $self->file or return 0;
+		print LOG $text."\n";
+		close LOG;
+		
+		print $text."\n" if(defined($level) && $Config::debug >= $level);
+	}
+	
+	return 1;
+} # Fin print_in_file
+
+
+# ###
+#  pending_in_file
+# Écrit dans le fichier en attendant de savoir si ça a réussi ou pas
+# ###
+sub pending_in_file
+{
+	my ($self, $text, $level) = @_;
+	return unless(defined $text);
+	
+	chomp $text;
+	$text = "[" . (scalar localtime time) . "] $text";
+	
+	if($self->file eq "STDOUT")
+	{
+		if($self->right_align)
+		{
+			printf STDOUT "%-90s", $text;
+		}
+		else
+		{
+			print STDOUT $text;
+		}
+	}
+	elsif($self->file eq "STDERR")
+	{
+		if($self->right_align)
+		{
+			printf STDERR "%-90s", $text;
+		}
+		else
+		{
+			print STDERR $text;
+		}
+	}
+	else
+	{
+		if($self->right_align)
+		{
+			open LOG, ">>", $self->file or return 0;
+			printf LOG "%-90s", $text;
+			close LOG;
+			
+			printf "%-90s", $text if(defined($level) && $Config::debug >= $level);
+		}
+		else
+		{
+			open LOG, ">>", $self->file or return 0;
+			print LOG $text;
+			close LOG;
+			
+			print $text if(defined($level) && $Config::debug >= $level);
+		}
+	}
+	
+	$self->pending(1);
+	
+	return 1;
+} # Fin pending_in_file
+
+
+# ###
+#  end_pending
+# Écrit dans le fichier le résultat de l'attente
+# ###
+sub end_pending
+{
+	my ($self, $done_or_error, $level) = @_;
+	
+	my $done = "";
+	
+	if($done_or_error)
+	{
+		if($self->colored)
+		{
+			$done = sprintf "%c[32m Done ", 0x1B;
+		}
+		else
+		{
+			$done = sprintf " Done \n";
+		}
+		
+		$done .= "☑" if($self->utf8);
+	}
+	else
+	{
+		if($self->colored)
+		{
+			$done = sprintf "%c[31m Error ", 0x1B;
+		}
+		else
+		{
+			$done = sprintf " Error \n";
+		}
+		
+		$done .= "☒" if($self->utf8);
+	}
+	
+	$done .= "\e[0m\n" if($self->colored);
+	
+	
+	# À partir d'ici, $done peut vouloir dire que c'est bon, ou pas
+	if($self->file eq "STDOUT")
+	{
+		printf STDOUT $done;
+	}
+	elsif($self->file eq "STDERR")
+	{
+		printf STDERR $done;
+	}
+	else
+	{
+		open LOG, ">>", $self->file or return 0;
+		printf LOG $done;
+		close LOG;
+		
+		printf $done if(defined($level) && $Config::debug >= $level);
+	}
+	
+	
+	$self->pending(0);
+	
+	return 1;
+} # Fin end_pending
+
+
+#
+# Fonctions pour récupérer les différents niveaux de debug
+#
+sub DEBUG   { return 3; }
+sub INFO    { return 2; }
+sub WARNING { return 1; }
+sub ERROR   { return 0; }
+sub CRITICAL { return -1; }
+# Pour ceux qui préfèrent utiliser des variables...
+our $DEBUG    = 3;
+our $INFO     = 2;
+our $WARNING  = 1;
+our $ERROR    = 0;
+our $CRITICAL = -1;
+our %LVL_NAME = (
+	"DEBUG"    => 3,
+	"INFO"     => 2,
+	"WARNING"  => 1,
+	"ERROR"    => 0,
+	"CRITICAL" => -1
+);
+
+# Et dans l'autre sens
+sub LVL
+{
+	my ($self, $num) = @_;
+	
+	my %LVL = (
+		3    => "DEBUG",
+		2    => "INFO",
+		1    => "WARNING",
+		0    => "ERROR",
+		"-1" => "CRITICAL"
+	);
+	
+	return $LVL{$num};
+}
+our %LVL = (
+	3    => "DEBUG",
+	2    => "INFO",
+	1    => "WARNING",
+	0    => "ERROR",
+	"-1" => "CRITICAL"
+);
+
+
+# ###
+#  dbg
+# Imprime des infos de debug à l'écran (STDOUT)
+# ###
+sub dbg
+{
+	my $self = shift;
+	
+	require Data::Dumper;
+	print Data::Dumper->Dump([$self], [qw(Logging)]);
+} # Fin dbg
+
+
+1;
+
+__END__
+
diff --git a/lib/sites/mixcloud.pm b/lib/sites/mixcloud.pm
new file mode 100644
index 0000000000000000000000000000000000000000..8cd29a53518b7b1021a9f25c6e7623648b7071ee
--- /dev/null
+++ b/lib/sites/mixcloud.pm
@@ -0,0 +1,71 @@
+package mixcloud;
+
+use LWP::UserAgent;
+use HTML::Parser;
+use HTML::Entities;
+
+require Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(mixcloud);
+
+
+my $inTitle = 0;
+my $inAuthor = 0;
+my %infos;
+
+
+sub mixcloud {
+	my ($url) = @_;
+
+	my $ua = LWP::UserAgent->new(
+		agent   => "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 GTB7.1",
+		timeout => 30
+	);
+
+	my $response = $ua->get($url);
+	die($response->status_line) unless ($response->is_success);
+
+	my $content = $response->decoded_content;
+
+	my $parser = HTML::Parser->new();
+	$parser->handler(text => \&parser_text, 'text');
+	$parser->handler(start => \&parser_start, 'tagname');
+	$parser->handler(end => \&parser_end, 'tagname');
+	$parser->unbroken_text(1);
+	$parser->report_tags('title', 'a');
+	$parser->parse($content);
+	$parser->eof();
+	
+	$infos{'url'} = $url;
+	
+	return %infos;
+}
+
+sub parser_text
+{
+	my ($text) = @_;
+	chomp $text;
+	$text = decode_entities($text);
+
+	if ($inTitle) {
+		$text =~ s/\n//;
+		$text =~ s/ \| Mixcloud .*//;
+		$text =~ s/^ *//;
+		$text =~ s/[^a-zA-Z0-9\(\)\[\]]*$//;
+		($infos{'author'}, $infos{'title'}) = split (' - ', $text, 2);
+	}
+}
+
+sub parser_start
+{
+	my ($tag) = @_;
+	$inTitle = 1 if ($tag eq 'title');
+}
+
+sub parser_end
+{
+	my ($tag) = @_;
+	$inTitle = 0 if ($tag eq 'title');
+}
+
+1;
diff --git a/lib/sites/soundcloud.pm b/lib/sites/soundcloud.pm
new file mode 100644
index 0000000000000000000000000000000000000000..1e00ebfb755515ed016121cf8e9d045a9f1bf001
--- /dev/null
+++ b/lib/sites/soundcloud.pm
@@ -0,0 +1,35 @@
+package soundcloud;
+
+use LWP::UserAgent;
+use JSON;
+
+require Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(soundcloud);
+
+
+my $root = 'http://api.soundcloud.com';
+my $clientId = 'f4956716fe1a9dc9c3725af822963365';
+
+
+sub soundcloud {
+	my ($url) = @_;
+
+	my $ua = LWP::UserAgent->new(timeout => 30);
+
+	my $response = $ua->get($root.'/resolve.json?url='.$url.'&client_id='.$clientId);
+	die($response->status_line) unless ($response->is_success);
+
+	$content = decode_json($response->decoded_content);
+	$infos{'title'} = $content->{'title'};
+	$infos{'author'} = $content->{'user'}->{'username'};
+	$infos{'url'} = $url;
+
+	if ($content->{'downloadable'}) {
+		$infos{'ddl'} = $content->{'download_url'};
+	}
+	
+	return %infos;
+}
+
+1;
diff --git a/lib/sites/youtube.pm b/lib/sites/youtube.pm
new file mode 100644
index 0000000000000000000000000000000000000000..d9039b50ce6425aa736166fbeb465b13d0bd3ed4
--- /dev/null
+++ b/lib/sites/youtube.pm
@@ -0,0 +1,76 @@
+package youtube;
+
+use LWP::UserAgent;
+use HTML::Parser;
+use HTML::Entities;
+
+require Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(youtube);
+
+
+my $inTitle = 0;
+my $inAuthor = 0;
+my %infos;
+
+
+sub youtube {
+	my ($url) = @_;
+
+	my $ua = LWP::UserAgent->new(
+		agent   => "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 GTB7.1",
+		timeout => 30
+	);
+
+	my $response = $ua->get($url);
+	die($response->status_line) unless ($response->is_success);
+
+	my $content = $response->decoded_content;
+
+	my $parser = HTML::Parser->new();
+	$parser->handler(text => \&parser_text, 'text');
+	$parser->handler(start => \&parser_start, 'tagname,attr');
+	$parser->handler(end => \&parser_end, 'tagname');
+	$parser->unbroken_text(1);
+	$parser->report_tags('title', 'a');
+	$parser->parse($content);
+	$parser->eof();
+	
+	$infos{'url'} = $url;
+	
+	return %infos;
+}
+
+sub parser_text
+{
+	my ($text) = @_;
+	chomp $text;
+
+	if ($inTitle) {
+		$text =~ s/\n//;
+		$text =~ s/- YouTube//;
+		$text =~ s/^ *//;
+		$text =~ s/[^a-zA-Z0-9\(\)\[\]]*$//;
+		$infos{'title'} = decode_entities($text);
+	}
+	elsif ($inAuthor) {
+		$infos{'author'} = $text;
+	}
+}
+
+sub parser_start
+{
+	my ($tag, $attr) = @_;
+	$inTitle = 1 if ($tag eq 'title');
+	return unless (defined $attr);
+	$inAuthor = 1 if ($tag eq 'a' && exists($attr->{'class'}) && $attr->{'class'} =~ /yt-user-name author/);
+}
+
+sub parser_end
+{
+	my ($tag) = @_;
+	$inTitle = 0 if ($tag eq 'title');
+	$inAuthor = 0 if ($tag eq 'a');
+}
+
+1;
diff --git a/lib/sites/zippy.pm b/lib/sites/zippy.pm
new file mode 100644
index 0000000000000000000000000000000000000000..872b13a6ac2b2a12ee61e2752398181d4eb25038
--- /dev/null
+++ b/lib/sites/zippy.pm
@@ -0,0 +1,70 @@
+package zippy;
+
+use LWP::UserAgent;
+use HTML::Parser;
+use HTML::Entities;
+
+require Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(zippy);
+
+
+my $inTitle = 0;
+my $inAuthor = 0;
+my %infos;
+
+
+sub zippy {
+	my ($url) = @_;
+
+	my $ua = LWP::UserAgent->new(
+		agent   => "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 GTB7.1",
+		timeout => 30
+	);
+
+	my $response = $ua->get($url);
+	die($response->status_line) unless ($response->is_success);
+
+	my $content = $response->decoded_content;
+
+	my $parser = HTML::Parser->new();
+	$parser->handler(text => \&parser_text, 'text');
+	$parser->handler(start => \&parser_start, 'tagname');
+	$parser->handler(end => \&parser_end, 'tagname');
+	$parser->unbroken_text(1);
+	$parser->report_tags('title', 'a');
+	$parser->parse($content);
+	$parser->eof();
+	
+	$infos{'url'} = $url;
+	$infos{'author'} = undef;
+	
+	return %infos;
+}
+
+sub parser_text
+{
+	my ($text) = @_;
+	chomp $text;
+	$text = decode_entities($text);
+
+	if ($inTitle) {
+		$text =~ s/^Zippyshare.com - //;
+		$text =~ s/\.mp3$//;
+		$infos{'title'} = $text;
+	}
+}
+
+sub parser_start
+{
+	my ($tag) = @_;
+	$inTitle = 1 if ($tag eq 'title');
+}
+
+sub parser_end
+{
+	my ($tag) = @_;
+	$inTitle = 0 if ($tag eq 'title');
+}
+
+1;