diff --git a/lib/commands/parser.pm b/lib/commands/parser.pm
index a97923bfebae884f9a8b867a7e6f71aa4097a171..9dc60689951ab1207c5c9fffc73f3411a1a5a9c2 100644
--- a/lib/commands/parser.pm
+++ b/lib/commands/parser.pm
@@ -1,12 +1,14 @@
 package commands::parser;
 
 use strict;
+use Try::Tiny;
 
 use lib "$FindBin::Bin/lib/";
 use commands::fav;
 use commands::later;
 use commands::tag;
 use commands::get;
+use utils::id;
 
 my $lastID;
 my $irc;
@@ -19,11 +21,13 @@ sub setConf {
     $commands::tag::dbh = $dbhNew;
     $commands::get::dbh = $dbhNew;
     $commands::later::dbh = $dbhNew;
+    $utils::id::dbh = $dbhNew;
 
     $commands::fav::log = $log;
     $commands::tag::log = $log;
     $commands::get::log = $log;
     $commands::later::log = $log;
+    $utils::id::log = $log;
 
     $commands::fav::irc = $ircNew;
     $commands::get::irc = $ircNew;
diff --git a/lib/utils/id.pm b/lib/utils/id.pm
new file mode 100644
index 0000000000000000000000000000000000000000..a473b7d25e480ff6c2ecb9b5489bfbc198ca55c2
--- /dev/null
+++ b/lib/utils/id.pm
@@ -0,0 +1,117 @@
+package utils::id;
+
+use strict;
+use Scalar::Util qw(looks_like_number);
+
+# Used to get a proper id from an index.
+# The public subroutine is get($chan, $index).
+# args :
+#   - $chan : the chan initiating the request. It cannot be empty and must
+#       start with '#' except if it is a query.
+#   - $index : the index.
+#       - an id (ex: 5089)
+#       - an offset (ex: -3 to have the third track before the last one).
+#           0 means the last track.
+#       - empty, wich means the last one.
+
+# The object used to communicate with the database and the loging object.
+# MUST BE SET before using any subrouting.
+our $dbh; 
+our $log;
+
+# The public method.
+sub get {
+    my ($chan, $index) = @_;
+    my $id;
+
+    if (!defined($index) or !length($index)) {
+        $id = _get_last_id ($chan);
+    } elsif (!looks_like_number($index)) {
+        die "wrong index";
+    } elsif ($index < 0) {
+        $id = _get_from_offset ($index, $chan);
+    } elsif (_test_if_exists ($index, $chan)) {
+        $id = $index;
+    } else {
+        die "wrong index";
+    }
+
+    return $id;
+}
+
+sub _get_from_offset {
+    my ($offset, $chan) = @_;
+    my $id = _get_last_id ($chan);
+
+    while ($offset < 0) {
+        my $sth = $dbh->prepare('
+            SELECT content
+            FROM playbot_chan
+            WHERE date < (SELECT date
+                        FROM playbot_chan
+                        WHERE content = ?
+                        AND chan = ?
+                        ORDER BY date DESC
+                        LIMIT 1)
+            AND chan = (SELECT chan
+                        FROM playbot_chan
+                        WHERE content = ?
+                        AND chan = ?
+                        ORDER BY date DESC
+                        LIMIT 1)
+            ORDER BY date DESC
+            LIMIT 1');
+	    unless (defined $sth) {
+            $log->error("Couldn't prepare querie; aborting");
+            return;
+        }	
+        $sth->execute($id, $chan, $id, $chan)
+            or $log->error("Couldn't finish transaction: " . $dbh->errstr);
+
+        my $content = $sth->fetch;
+        return unless ($content);
+        $id = $content->[0];
+        $offset++;
+    }
+
+    return $id;
+}
+
+sub _test_if_exists {
+    my ($index, $chan) = @_;
+
+    my $sth = $dbh->prepare('
+        SELECT content
+        FROM playbot_chan
+        WHERE content = ?
+        AND chan = ?
+        LIMIT 1
+    ');
+
+    $sth->execute($index, $chan)
+        or $log->error("Couldn't finish transaction: " . $dbh->errstr);
+
+    my $content = $sth->fetch;
+    if ($content) {
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+
+sub _get_last_id {
+    my ($chan) = @_;
+
+    my $sth = $dbh->prepare('
+        SELECT content
+        FROM playbot_chan
+        WHERE chan = ?
+        AND date <= NOW()
+        ORDER BY date DESC
+        LIMIT 1');
+    $sth->execute($chan);
+    return $sth->fetch->[0];
+}
+
+1;