Class: BTScraper::UDPScrape

Inherits:
Object
  • Object
show all
Defined in:
lib/btscraper/udpscrape.rb

Overview

This class permits you to scrape an UDP torrent tracker according to the BEP 15

See Also:

Author:

  • sherkix

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tracker, info_hash) ⇒ UDPScrape

Create a new UDPScrape object

Examples:

Default usage

scrape_object = BTScraper::UDPScrape.new('udp://example.com:3000/announce', ['c22b5f9178342609428d6f51b2c5af4c0bde6a42'], ['aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d'])
scrape_object.scrape

Parameters:

  • tracker (String)

    Bittorrent UDP tracker server

  • info_hash (Array<String>, String)

    Array of infohashes or single infohash

Raises:

  • (TypeError)

    if wrong type of argument is provided

  • (BTScraperError)

    if the infohashes provided are more than 74



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/btscraper/udpscrape.rb', line 44

def initialize(tracker, info_hash)
  unless tracker.instance_of? String
    raise TypeError, "String excpected, got #{tracker.class}"
  end
  unless info_hash.instance_of? String or info_hash.instance_of? Array
    raise TypeError, "String or Array excpected, got #{info_hash.class}"
  end
  
  # Maximum number of infohashes is 74

  if info_hash.instance_of? Array and info_hash.count > 74
    raise BTScraperError, 'The number of infohashes must be less than 74'
  end

  if info_hash.instance_of? String
    info_hash.downcase!
    BTScraper.check_info_hash Array(info_hash)
  else
    info_hash.map(&:downcase!)
    BTScraper.check_info_hash info_hash
  end
  @tracker = tracker 
  @hostname = URI(@tracker).hostname
  @port = URI(@tracker).port 
  @info_hash = Array(info_hash) 
end

Instance Attribute Details

#hostnameString (readonly)

Returns tracker’s hostname

Returns:

  • (String)

    returns tracker’s hostname



44
45
46
# File 'lib/btscraper/udpscrape.rb', line 44

def hostname
  @hostname
end

#info_hashArray<String> (readonly)

Returns array of infohashes

Returns:

  • (Array<String>)

    returns array of infohashes



44
45
46
# File 'lib/btscraper/udpscrape.rb', line 44

def info_hash
  @info_hash
end

#portInteger (readonly)

Returns tracker’s port

Returns:

  • (Integer)

    returns tracker’s port



44
45
46
# File 'lib/btscraper/udpscrape.rb', line 44

def port
  @port
end

#trackerString (readonly)

Returns tracker full url

Returns:

  • (String)

    returns tracker full url



44
45
46
# File 'lib/btscraper/udpscrape.rb', line 44

def tracker
  @tracker
end

Instance Method Details

#scrapeHash

Returns The method returns a hash with the scraped data.

Examples:

Response example

{tracker: "udp://example.com:3000/announce", scraped_data: [{infohash: "c22b5f9178342609428d6f51b2c5af4c0bde6a42", seeders: 20, completed: 1000, leechers: 30}, {infohash: "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", seeders: 350, completed: 12000, leechers: 23}]}

Returns:

  • (Hash)

    The method returns a hash with the scraped data

Raises:



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/btscraper/udpscrape.rb', line 76

def scrape
  attempt = 0
  client = connect_to_tracker
  transaction_id = rand_transaction_id
  buffer = [get_connection_id, Actionscrape, transaction_id].pack('Q>NN')
  @info_hash.each{|x| buffer << x.split.pack('H*')}
  begin
    client.send buffer, 0
    Timeout::timeout(Defaulttimeout * 2**attempt) do
      response = client.recvfrom(4096)
      if response[0].bytesize < 8
        raise BTScraperError, 'The response from the tracker is less than 8 bytes'
      end
      @unpacked_response = response[0].unpack('N*')
      if @unpacked_response[0] == Actionerr
        raise BTScraperError, 'Scrape request failed'
      end
      unless @unpacked_response[1] == transaction_id
        raise BTScraperError, 'Invalid transaction id got from tracker'
      end
    end
  rescue Timeout::Error
    attempt+=1
    puts "#{attempt} Request to #{@hostname} timed out, retying after #{Defaulttimeout * 2**attempt}s"
    retry if attempt <= Retries
    raise BTScraperError, 'Max retries exceeded'
  ensure
    client.close
  end
  hash = {tracker: @tracker, scraped_data:[]}
  create_scrape_hash @info_hash, @unpacked_response, hash
end