#!/usr/bin/ruby require 'nntplib' require 'hpricot' require 'thread' require 'optparse' nthreads = 4 nntpserver = 'news.free.fr' subdir = '.' cont = false OptionParser.new { |opts| opts.on('-s', '--server host', 'news server') { |o| nntpserver = o } opts.on('-n', '--nthreads N', 'number of parallel connections') { |o| nthreads = o.to_i } opts.on('-d', '--downloaddir dir', 'where to put downloaded files') { |o| subdir = o } opts.on('-c', '--continue', 'do not redl existing files') { |o| cont = true } opts.on('-v', '--verbose', 'show nntp raw messages') { $VERBOSE = true } }.parse! nzb = Hpricot(File.open(ARGV.shift)) Dir.mkdir subdir unless File.directory? subdir Dir.chdir subdir group = (nzb/:group).first.innerHTML artids = [] (nzb/:file).each { |file| next if cont and Dir['?????*'].any? { |fn| file.attributes['subject'].include? fn } artids.concat((file/:segment).map { |seg| seg.innerHTML }) } m = Mutex.new Array.new(nthreads) { Thread.new(artids, m) { |artids, m| s = NntpClient.new nntpserver, group begin while id = m.synchronize { artids.shift } $stderr.print "#{artids.length} \r" if $stderr.isatty s.dl_bin "<#{id}>" end ensure p s.quit if s.sock end } }.each { |t| t.join } system 'parrar-sh', '.'