Youtube: remove old matching code
[videosite.git] / videosite.pl
index 00af09f..d7a549f 100644 (file)
@@ -22,7 +22,9 @@ use vars qw($VERSION %IRSSI);
 use XML::Simple;
 use Data::Dumper;
 use File::Spec;
+use File::Temp qw(tempfile);
 use BettIrssi 101 qw(_bcb _bcs);
+use LWP::UserAgent;
 
 my @grabbers;
 my @getters;
@@ -35,7 +37,9 @@ my @outputstack = (undef);
 
 my $PARAMS = {
     'getter' => '',
-    'mode' => 'download'
+    'mode' => 'download',
+    'connectorlist' => ['direct'],
+    'connectors' => {},
 };
 
 
@@ -108,6 +112,10 @@ my $videosite_commands = {
         cmd_mode(@_);
     },
 
+    'connector' => sub {
+        cmd_connector(@_);
+    },
+
     'debug' => sub {
         $debug = 1;
         foreach (@grabbers, @getters) {
@@ -148,6 +156,77 @@ sub write_debug {
     }
 }
 
+sub expand_url_shortener {
+    my $s = shift;
+    my $os = '';
+    my @urlshortener = (
+        'is\.gd/[[:alnum:]]+',
+        'otf\.me/[[:alnum:]]+',
+        'hel\.me/[[:alnum:]]+',
+        '7ax\.de/[[:alnum:]]+',
+        'ow\.ly/[[:alnum:]]+',
+        'j\.mp/[[:alnum:]]+',
+        'bit\.ly/[[:alnum:]]+',
+        'tinyurl\.com/[[:alnum:]]+',
+        'pop\.is/[[:alnum:]]+',
+        'post\.ly/[[:alnum:]]+',
+        '1\.ly/[[:alnum:]]+',
+        '2\.ly/[[:alnum:]]+',
+        't\.co/[[:alnum:]]+',
+        'shar\.es/[[:alnum:]]+',
+        'goo\.gl/[[:alnum:]]+',
+        );
+    my $ua = LWP::UserAgent->new(agent => 'Mozilla', max_redirect => 0);
+    my $i = 10;
+
+    OUTER: while (($os ne $s) and ($i > 0)) {
+        study($s);
+        $os = $s;
+        $i--;
+
+        foreach my $pattern (@urlshortener) {
+            my $p = "https?:\/\/" . $pattern;
+
+            write_debug("Matching %s against %s", $p, $s);
+            if ($s =~ m|($p)|) {
+                my $matched = $1;
+                my $res;
+
+                write_debug("Found %s", $matched);
+                $res = $ua->head($matched);
+                if ($res->is_redirect()) {
+                    my $new = $res->headers()->header("Location");
+
+                    write_debug("Replacing %s with %s", $matched, $new);
+                    $s =~ s/$matched/$new/;
+                    next OUTER;
+                } else {
+                    write_debug("Error resolving %s", $matched);
+                }
+            }
+        }
+    }
+
+    if ($i == 0) {
+        write_debug("Loop terminated by counter");
+    }
+
+    write_debug("Final string: %s", $s);
+
+    return $s;
+}
+
+sub connectorlist {
+    my @c;
+
+    foreach (@{$conf->{'videosite'}->{'connectorlist'}}) {
+        push(@c, $conf->{'videosite'}->{'connectors'}->{$_});
+    }
+
+    return @c;
+}
+
+
 sub check_for_link {
     my $event = shift;
     my $message = $event->message();
@@ -163,6 +242,7 @@ sub check_for_link {
     }
 
     push_output($event->ewpf);
+    $message = expand_url_shortener($message);
 
     study($message);
 
@@ -197,10 +277,12 @@ sub check_for_link {
 
 sub cmd_save {
 
+
     eval {
-        open(CONF, '>'.$conffile) or die 'Could not open config file';
-        print CONF XML::Simple::XMLout($conf, KeepRoot => 1, KeyAttr => {'config' => 'module', 'option' => 'key'});
-        close(CONF);
+        my ($tempfile, $tempfn) = tempfile("videosite.xml.XXXXXX", dir => Irssi::get_irssi_dir());
+        print $tempfile XML::Simple::XMLout($conf, KeepRoot => 1, KeyAttr => {'connector' => '+name', 'config' => 'module', 'option' => 'key'});
+        close($tempfile);
+        rename($tempfn, $conffile);
     };
     if ($@) {
         write_irssi('Could not save config to %s: %s', ($conffile, $@));
@@ -304,6 +386,7 @@ Supported commands:
  disable [modulename]: disable the usage of this module (grabbers only)
  reload: reload all modules (this is somewhat experimental)
  mode [modename]: display or set the operation mode (download/display)
+ connector [subcommand]: manage connectors (proxies)
  debug: enable debugging messages
  nodebug: disable debugging messages
 EOT
@@ -345,6 +428,169 @@ sub cmd_mode {
     }
 }
 
+sub cmd_connector {
+    my $subcmd = shift;
+    my $connconf = $conf->{'videosite'}->{'connectors'};
+
+    unless(defined($subcmd)) {
+        $subcmd = "help";
+    }
+
+    $subcmd = lc($subcmd);
+
+    if ($subcmd eq 'list') {
+        write_irssi("Defined connectors");
+        foreach (keys(%{$connconf})) {
+            write_irssi($_);
+            my $schemas = $connconf->{$_}->{'schemas'};
+            if (scalar(keys(%{$schemas})) == 0) {
+                write_irssi(" No schemas defined");
+            } else {
+                foreach (keys(%{$schemas})) {
+                    write_irssi(' %s: %s', $_, $schemas->{$_});
+                }
+            }
+        }
+
+        write_irssi();
+        write_irssi("Selected connectors: %s", join(", ", @{$conf->{'videosite'}->{'connectorlist'}}));
+    } elsif ($subcmd eq 'add') {
+        my ($name) = @_;
+
+        unless(defined($name)) {
+            write_irssi("No name given");
+            return;
+        }
+
+        $name = lc($name);
+
+        if (exists($connconf->{$_})) {
+            write_irssi("Connector already exists");
+            return;
+        }
+
+        $connconf->{$name} = {'name' => $name, 'schemas' => {}};
+    } elsif ($subcmd eq 'del') {
+        my ($name) = @_;
+
+        unless(defined($name)) {
+            write_irssi("No name given");
+            return;
+        }
+
+        $name = lc($name);
+
+        unless (exists($connconf->{$name})) {
+            write_irssi("Connector does not exist");
+            return;
+        }
+
+        if (exists($connconf->{$name}->{'_immutable'})) {
+            write_irssi("Connector cannot be removed");
+            return;
+        }
+
+        delete($connconf->{$name});
+
+        # Remove from list of active connectors
+        $conf->{'videosite'}->{'connectorlist'} =
+            [ grep { $_ ne $name } @{$conf->{'videosite'}->{'connectorlist'}} ];
+
+        if (scalar(@{$conf->{'videosite'}->{'connectorlist'}}) == 0) {
+            write_irssi("List of selected connectors is empty, resetting to direct");
+            $conf->{'videosite'}->{'connectorlist'} = [ 'direct' ];
+        }
+    } elsif ($subcmd eq 'addschema') {
+        my ($conn, $schema, $proxy) = @_;
+
+        unless(defined($conn)) {
+            write_irssi("No connector name given");
+            return;
+        }
+
+        $conn = lc($conn);
+
+        if (exists($connconf->{$conn}->{'_immutable'})) {
+            write_irssi("Connector cannot be modified");
+            return;
+        }
+
+        unless(defined($schema)) {
+            write_irssi("No schema given");
+            return;
+        }
+
+        $schema = lc($schema);
+
+        unless(defined($proxy)) {
+            write_irssi("No proxy given");
+            return;
+        }
+
+        unless(exists($connconf->{$conn})) {
+            write_irssi("Connector does not exist");
+            return;
+        }
+
+        $connconf->{$conn}->{'schemas'}->{$schema} = $proxy;
+    } elsif ($subcmd eq 'delschema') {
+        my ($conn, $schema) = @_;
+
+        unless(defined($conn)) {
+            write_irssi("No connector name given");
+            return;
+        }
+
+        $conn = lc($conn);
+
+        if (exists($connconf->{$conn}->{'_immutable'})) {
+            write_irssi("Connector cannot be modified");
+            return;
+        }
+
+        unless(defined($schema)) {
+            write_irssi("No schema given");
+            return;
+        }
+
+        $schema = lc($schema);
+
+        unless(exists($connconf->{$conn})) {
+            write_irssi("Connector does not exist");
+            return;
+        }
+
+        delete($connconf->{$conn}->{'schemas'}->{$schema});
+    } elsif ($subcmd eq 'select') {
+        my @connlist = map { lc } @_;
+
+        if (scalar(@connlist) == 0) {
+            write_irssi("No connectors given");
+            return;
+        }
+
+        foreach (@connlist) {
+            unless(exists($connconf->{$_})) {
+                write_irssi("Connector %s does not exist", $_);
+                return;
+            }
+        }
+
+        $conf->{'videosite'}->{'connectorlist'} = [ @connlist ];
+    } else {
+        write_irssi("connector [list|add|del|addschema|delschema|help] <options>");
+        write_irssi(" help: Show this help");
+        write_irssi(" list: List the defined connectors");
+        write_irssi(" add <name>: Add a connector with name <name>");
+        write_irssi(" del <name>: Delete the connector with name <name>");
+        write_irssi(" addschema <name> <schema> <proxy>: Add proxy to connector for the given schema");
+        write_irssi(" delschema <name> <schema>: Remove the schema from the connector");
+        write_irssi(" select <name> [<name>...]: Select the connectors to use");
+    }
+}
+
+
+
 
 # save on unload
 sub sig_command_script_unload {
@@ -388,6 +634,7 @@ sub ploader {
         if ($type eq $g->{'TYPE'}) {
             push(@g, $g);
             $g->setio(\&write_irssi);
+            $g->setconn(\&connectorlist);
         } else {
             write_irssi('%s has wrong type (got %s, expected %s)', $p, $g->{'TYPE'}, $type);
             delete($INC{$p});
@@ -419,7 +666,7 @@ sub init_videosite {
     my $bindings = shift;
     my $p;
 
-    unless(-r $conffile && defined($conf = XML::Simple::XMLin($conffile, ForceArray => ['config', 'option'], KeepRoot => 1, KeyAttr => {'config' => 'module', 'option' => 'key'}))) {
+    unless(-r $conffile && defined($conf = XML::Simple::XMLin($conffile, ForceArray => ['config', 'option', 'connectorlist'], KeepRoot => 1, KeyAttr => {'connector' => '+name', 'config' => 'module', 'option' => 'key'}))) {
         # No config, start with an empty one
         write_debug('No config found, using defaults');
         $conf = { 'videosite' => { }};
@@ -430,6 +677,16 @@ sub init_videosite {
         }
     }
 
+    # Make sure there is a connector called 'direct', which defines no
+    # proxies
+    unless (exists($conf->{'videosite'}->{'connectors'}->{'direct'})) {
+        $conf->{'videosite'}->{'connectors'}->{'direct'} = {
+                'name' => 'direct',
+                '_immutable' => '1',
+                'schemas' => {},
+        };
+    }
+
     _load_modules($plugindir);
 
     unless (defined(@grabbers) && defined(@getters)) {