#!/usr/bin/perl # autonuts v2.1 - automation of gnut using expect.pm # by steven fountain (cider@compulsion.org) # web: http://enraptured.compulsion.org/autonuts # web: http://enraptured.compulsion.org/code/ # # autonuts is designed to pillage and data-mine gnutella using the # command line gnutella client "gnut", using perl and Expect.pm # in a very hacked fashion. # # this tool succeeds at identifying unique file names # when given enough responses to chew through. # # in order to have it not grab files you already have, you must # change the $archive variable to point to where your mp3's are, # ie, /mp3 # then you must move the contents of a retrieval for "the fish" # into /mp3/the_fish # or "fish" as # /mp3/fish # # after identifying available unique songs by a band that you # dont already have, you can then queue them all.. # take the path of no return and jump into interactive mode # to watch the files download. # # usage: autonuts your simple text bandname here # ie: autonuts sneakerpimps & # autonuts the cure & # autonuts fugazi & # ;) # # requirements: # expect perl module w/stty/pty dependencies (deb users: libexpect- +perl) # gnut (deb users: gnut) # some bandwidth # some harddrive space # # where your files are mostly stored.. for re-running $archive = "/ok/muse"; # change to /mp3 or something if i had drives? use Term::ANSIColor; # allways like to have this on my plate... use Expect; # gnut's kinda like ftp. *wink* use Text::Soundex; # for assistance in finding unique filenames $|++; # i like autoflushing too much. $*{STDERR} = \*{STDOUT}; # wouldnt want to miss anything now $SIG{INT} = sub { $nut -> hard_close(); die "exiting.\n"; }; # hand +le ctl-C $Expect::Debug=0; $Expect::Exp_Internals=0; $Expect::Log_Stdout=0; # turn this on for annoying debugging... $Expect::Multiline_Matching = 0; $Expect::Exp_Max_Accum = 0; $Expect::Manual_Stty = 1; # take a band name from command line. $band = join ' ', @ARGV; $band = lc($band); if ($band =~ /^\w/) { print "Good bandname found from commandline: $ba +nd\n"; } else { undef $band; } # coloring debugging output routines sub red { print color 'red'; } sub pred { $_ = shift; print color 'red'; print "$_"; print color 'res +et'; print "\n"; } sub pgreen { $_ = shift; print color 'green'; print "$_"; print color +'reset'; print "\n"; } sub pbgreen { $_ = shift; print color 'bold green'; print "$_"; print +color 'reset'; print "\n"; } sub white { print color 'bold white'; } sub creset { print color 'reset'; } sub pret { print "\n"; } sub wait_for_prompt { $quiet = @_; print "waiting for prompt.. "; unless($nut -> expect(15, "autonuts>")) { print "NOT ok.\n"; return 0; } print "ok.\n"; return 1; } sub waitfor { $waitfor = shift; $howlong = shift || 60; print "expecting \"$waitfor\" for ${howlong}s.. "; unless($nut -> expect($howlong, '-re', "$waitfor")) { print "NOT found.\n"; return 0; } print "ok.\n"; return 1; } sub start { print "spawning gnut process.. "; ($nut = Expect->spawn("gnut 2>&1")) || die "Couldn't spawn gnut: $ +!"; print "ok.\n"; print "waiting for gnut to start.. "; unless($nut -> expect(15, "at your service")) { die "gnut didn't start successfully.\n"; } print "ok.\n"; } @settings = ( "set prompt autonuts>\\n", # without this, wait_for_prompt would b +reak "set response_format sz:{S} :: sp:{s} :: {f#} :: {N} ::", # needed + for "resp" "set paginate 0", # gets rid of requests to more every 25 lines "set stats_format 1", # one line serverstats instead of two, i thi +nk "set max_downloads 100", "set max_incoming 100", "set sort_order p", # sort by speed, show the fastest ones at bott +om ); sub settings { foreach $setting (@settings) { print "$setting.. "; $nut->send_slow(0, "$setting\r\n"); print "ok. "; wait_for_prompt(); } } sub sane { print "waiting for network to become ready..\n"; until($network_is_ready) { print "gathering... "; $nut->clear_accum(); $nut->send_slow(0, "info\r\n"); unless($nut -> expect(2, '-re', "HOST STATS:") ) { print "blah.\n"; } $host_stats = $nut->exp_after(); @host_stats = (); @host_stats = split /\n/, $host_stats; foreach (@host_stats) { if (/Unique GUIDs in memory: (\d+)/) { $users = $1; print "unique users: $users (not >500)"; $network_is_ready++ if ($users > 500); } } print " resting 20s" unless $network_is_ready; sleep 20 unless $network_is_ready; print ";\n"; } wait_for_prompt(quiet); $nut->send_slow(0, "info\r\n"); wait_for_prompt(quiet); pgreen "sane connectivity scenario reached."; } #until($cmd eq "stop"||$cmd eq "quit"||(!$nut)) { # print "autonuts: "; # chomp($cmd = <STDIN>) unless $auto; # $auto=0 if $auto; # disable if previously auto... sub info { $nut->clear_accum(); $nut->send_slow(0, "info\r\n"); waitfor "HOST STATS:"; pgreen "playing back..."; $info = $nut->exp_after(); @info = (); @info = split /\n/, $info; foreach (@info) { chomp; $l++; pgreen "$l: $_"; } undef $l; wait_for_prompt(); } sub band { print "band presently set to: $band\n"; } sub bandset { $band = shift; $band = lc($band); band(); } sub search { pred("searching for stuff by ${band}... 75 second headstart... + "); $nut->clear_accum(); $nut->send_slow(0, "search $band\r"); sleep 75; # the funny thing is that after 60s this picks up ~365, 495, e +tc. waitfor("responses received.", 120) ? $results=0 : $results=1 +; $nut->send_slow(0, "\r"); search() unless $results; resp() if $results; } sub resp { pred("showing responses..."); $nut->clear_accum(); $nut->send_slow(0, "resp\r"); $results = wait_for_prompt(); if($results) { $responses = $nut->exp_before(); @responses = (); @responses = split /\n/, $responses; $fmp3=0; %leech = (); %titles = (); %sounds = (); foreach (@responses) { chomp; $l++; pgreen "$l: $_"; if (/mp3/i) { $fmp3++; /sz:(.*?)\s+::\ssp:\s{0,}(\d+)\s::\s(\d+)\s::\s(.*?)\s +::/; $song = $4; # and print "song: $song\n"; $number = $3; # and print "number: $number\n"; $speed = $2; # and print "speed: $speed\n"; $size = $1; # and print "size: $size\n"; $isize = int($size); next unless ($size =~ /m$/i); # should be in the meg b +allpark next unless ($isize > 2); # should be bigger then two +megs next unless ($isize < 10); # should be less than ten m +egs next unless ($speed > 200); # should get it faster tha +n isdn $song = lc($song); # change the song to lowercase $song =~ s/_/ /g; # change underscores to spaces $song =~ s/\.mp3//gi; # remove the file extension $song =~ s/\s{0,}[\(\[].*?[\[\(].*?[\]\)].*?[\]\)]\s{0 +,}//g; # remove double variant comments eg: (remix(its phat)) $song =~ s/\s{0,}[\(\[].*?[\]\)]\s{0,}//g; # remove va +riant comments eg: (remix) $song =~ s/${band} - .* - (.*?)$/${band} - $1/g; # gre +edy attempt at removing album names next unless ($song =~ /$band - .*?/i); # should resemb +le band with a title $title = $1 if ($song =~ /${band} - (.*?)$/); $code = soundex $title; $already_have = 0; foreach (@already_have) { $ihave = $_; $ihavecode = $1 if ($ihave =~ /^(.*?) /); $uhave = "$code $title"; # if it sounds like something we already have, # we probably dont want it. if ($uhave =~ /^$ihavecode /) { $already_have = 1; print "passing by: $code $title\n"; } } if ($already_have eq 0) { print "marking: $code $title\n"; $sounds{$code}{title} = $title; $sounds{$code}{number} = $number; } }; } unless ($l > 20 && $number / 2 < $l) { print "not happy with these results, trying again.\n"; $auto=1; $resp_sucks++; if ($resp_sucks > 5) { undef $resp_sucks; print "hrm. you might want to try typing search again. +\n"; print "searching again...\n"; search(); # ha figured it out heh } search(); } else { print "i'm happy with the results. you should now type lis +t\n"; } undef $l; } $auto=1 unless $fmp3; } sub list { foreach $codes (sort keys %sounds) { $uniq++; print "$codes [$sounds{$codes}{number}]\t$sounds{$codes}{t +itle}\n"; } print "$uniq uniq.\n"; search() unless ($uniq =~ /^\d+/); undef $uniq; } sub getuniq { print "i'll take"; foreach $codes (sort keys %sounds) { $num = $sounds{$codes}{number}; print " ${num},"; $nut->send_slow(0, "g $num\r\n"); } print " and that aughta do it.\n"; print "requested all unique files.\n"; } sub log { if ($log) { pred "turning log off."; $log=0; $Expect::Log_Stdo +ut=0; } unless ($log) { pred "turning log on."; $log=1; $Expect::Log_S +tdout=1; } } sub before { print $nut->exp_before(); } sub after { print $nut->exp_after(); } sub interact { print "please do not return to autonuts, i'm changing your pro +mpt...\n"; print "setting prompt.. "; $nut->send_slow(0, "set prompt gnut+autonutted>\r\n"); print "ok.\n"; $nut->interact(); $cmd = "stop"; # eh who knows might work... } sub help { print "commands..\nband info search resp list getuniq log befo +re after interact\nif you run them in no specific order your mileage +will vary\n"; } sub check_existing_songs { $group = shift; $group =~ s/ /_/g; print "opening existing $group...\n"; opendir OFF, "$archive/$group" or return "no archive directory fou +nd.\n"; while($song = readdir OFF) { next if ($song =~ /^\.|\.\.$/); next unless ($song =~ /\.mp3$/i); $song = lc($song); # change the song to lowercase $song =~ s/_/ /g; # change underscores to spaces $song =~ s/\.mp3//gi; # remove the file extension $song =~ s/\s{0,}[\(\[].*?[\[\(].*?[\]\)].*?[\]\)]\s{0,}//g; # + remove double variant comments eg: (remix(its phat)) $song =~ s/\s{0,}[\(\[].*?[\]\)]\s{0,}//g; # remove variant co +mments eg: (remix) $song =~ s/${band} - .* - (.*?)$/${band} - $1/g; # greedy atte +mpt at removing album names next unless ($song =~ /$band - .*?/i); # should resemble band +with a title $title = $1 if ($song =~ /${band} - (.*?)$/); $code = soundex $title; print "already have: $code $title\n"; push @already_have, "$code $title"; } closedir OFF; } # roadmap.. print "band: " unless(defined($band)); chomp($band = <STDIN>) unless(defined($band)); start(); settings(); check_existing_songs($band); sane(); bandset($band) if(defined($band)); search(); list(); getuniq(); print "abandoning you now to the gnut program, press enter once inside +.\n"; interact(); # lost into gnut... # shouldnt get here... print "aah, they got me.\n"; print "i'm dying.\n"; $nut->hard_close(); die "dead.\n";

In reply to autonuts by cider

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.