Class: Torrent

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

Overview

Sample usage t = Torrent.new(“your.tracker.com”) t.add_file(“path/to/file.foo”) t.write_torrent(“~/Downloads/mytorrent.torrent”)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tracker) ⇒ Torrent

optionally initialize filename



16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/mktorrent.rb', line 16

def initialize(tracker)
  @tracker = tracker
  @piecelength = 512 * 1024 # 512 KB
  @files = []
  @filehashes = []
  @size = 0
  @tracker_list = [ [@tracker] ]
  @defaultdir = "torrent"
  @privacy = 0
  @webseed = ""
  @dirbase = ""
  build_the_torrent
end

Instance Attribute Details

#defaultdirObject

Returns the value of attribute defaultdir.



13
14
15
# File 'lib/mktorrent.rb', line 13

def defaultdir
  @defaultdir
end

#filehashesObject

Returns the value of attribute filehashes.



13
14
15
# File 'lib/mktorrent.rb', line 13

def filehashes
  @filehashes
end

#filesObject

Returns the value of attribute files.



13
14
15
# File 'lib/mktorrent.rb', line 13

def files
  @files
end

#infoObject

Returns the value of attribute info.



13
14
15
# File 'lib/mktorrent.rb', line 13

def info
  @info
end

#infohashObject (readonly)

Returns the value of attribute infohash.



12
13
14
# File 'lib/mktorrent.rb', line 12

def infohash
  @infohash
end

#piecelengthObject

Returns the value of attribute piecelength.



13
14
15
# File 'lib/mktorrent.rb', line 13

def piecelength
  @piecelength
end

#privacyObject

Returns the value of attribute privacy.



13
14
15
# File 'lib/mktorrent.rb', line 13

def privacy
  @privacy
end

#sizeObject

Returns the value of attribute size.



13
14
15
# File 'lib/mktorrent.rb', line 13

def size
  @size
end

#torrent_fileObject (readonly)

Returns the value of attribute torrent_file.



12
13
14
# File 'lib/mktorrent.rb', line 12

def torrent_file
  @torrent_file
end

#trackerObject

Returns the value of attribute tracker.



13
14
15
# File 'lib/mktorrent.rb', line 13

def tracker
  @tracker
end

#tracker_listObject

Returns the value of attribute tracker_list.



13
14
15
# File 'lib/mktorrent.rb', line 13

def tracker_list
  @tracker_list
end

#webseedObject

Returns the value of attribute webseed.



13
14
15
# File 'lib/mktorrent.rb', line 13

def webseed
  @webseed
end

Instance Method Details

#add_directory(path) ⇒ Object



131
132
133
134
135
# File 'lib/mktorrent.rb', line 131

def add_directory(path)
  path = Pathname.new(path)
  @dirbase = File.dirname(path) unless path.relative?
  add_directory_to_torrent(path)
end

#add_directory_to_torrent(path) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/mktorrent.rb', line 137

def add_directory_to_torrent(path)
  # Using Dir.entries instead of glob so that non-escaped paths can be used
  Dir.entries(path).each do |entry|
    # Ignore unix current and parent directories
    next if entry == '.' or entry == '..'

    filename = File.join(path, entry).gsub(@dirbase, '') # Add a relative path
    if File.directory?(filename)
      add_directory_to_torrent(filename)
    else
      add_file(filename)
    end
  end
end

#add_file(filepath) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/mktorrent.rb', line 110

def add_file(filepath)
  path_for_torrent = path_for_torrent_from_file(filepath)

  if((@files.select { |f| f[:path] == path_for_torrent } ).count > 0)
    raise IOError, "Can't add duplicate file #{File.basename(filepath)}"
  end

  # Remove a leading slash
  if ( ! @dirbase.empty?) && filepath[0] == '/'
    filepath = filepath.slice(1, filepath.length)
  end

  if File.exist?(filepath)
    @files << { path: path_for_torrent, length: File::open(filepath, "rb").size }
  elsif @dirbase && File.exist?(File.join(@dirbase, filepath))
    @files << { path: path_for_torrent, length: File::open(File.join(@dirbase, filepath), "rb").size }
  else
    raise IOError, "Couldn't access #{filepath}"
  end
end

#add_tracker(tracker) ⇒ Object



157
158
159
# File 'lib/mktorrent.rb', line 157

def add_tracker(tracker)
  @tracker_list << [tracker]
end

#all_filesObject



30
31
32
33
34
# File 'lib/mktorrent.rb', line 30

def all_files
  if @files.any?
    @files.collect { |file| file[:path] }
  end
end

#buildObject Also known as: build_the_torrent



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/mktorrent.rb', line 73

def build
  @info = {
    :announce => @tracker,
    :'announce-list' => @tracker_list,
    :'creation date' => DateTime.now.strftime("%s"),
    :info => {
      :name => @defaultdir,
      :'piece length' => @piecelength,
      :files => @files,
      :private => @privacy,
    }
  }
  @info[:info][:pieces] = ""
  @info.merge!({ :'url-list' => @webseed }) unless @webseed.empty?
  if @files.count > 0
    read_pieces(all_files, @piecelength) do |piece|
      @info[:info][:pieces] += Digest::SHA1.digest(piece)
    end
  end
end

#countObject



36
37
38
# File 'lib/mktorrent.rb', line 36

def count
  @files.count
end

#path_for_reading_pieces(f) ⇒ Object



40
41
42
43
44
45
46
# File 'lib/mktorrent.rb', line 40

def path_for_reading_pieces(f)
  if @dirbase.empty? # it's a single file torrent
    f = File.join(File.join(f))
  end
  f = File.join(@dirbase, f) unless @dirbase.empty?
  f
end

#read_pieces(files, length) {|buffer| ... } ⇒ Object

Yields:

  • (buffer)


48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/mktorrent.rb', line 48

def read_pieces(files, length)
  buffer = ""
  files.each do |file|
    f = path_for_reading_pieces(file)
    next if File.directory?(f)
    File.open(f) do |fh|
      begin
        read = fh.read(length - buffer.length)

        # Make sure file not empty
        unless read.nil?
          if (buffer.length + read.length) == length
            yield(buffer + read)
            buffer = ""
          else
            buffer += read
          end
        end
      end until fh.eof?
    end
  end

  yield buffer
end

#set_privateObject



161
162
163
# File 'lib/mktorrent.rb', line 161

def set_private
  @privacy = 1
end

#set_publicObject



165
166
167
# File 'lib/mktorrent.rb', line 165

def set_public
  @privacy = 0
end

#set_webseed(url) ⇒ Object



152
153
154
155
# File 'lib/mktorrent.rb', line 152

def set_webseed(url)
  validate_url!(url)
  @webseed = url
end

#to_sObject

Return the .torrent file as a string



104
105
106
107
108
# File 'lib/mktorrent.rb', line 104

def to_s
  return "You must add at least one file." if(@files.count < 1)
  build_the_torrent unless (@info[:info][:files].count == @files.count)
  @info.bencode
end

#write_torrent(filename) ⇒ Object



94
95
96
97
98
99
100
101
# File 'lib/mktorrent.rb', line 94

def write_torrent(filename)
  build_the_torrent
  @torrent_file = File.absolute_path(filename)
  open(@torrent_file, 'wb') do |file|
    file.write self.to_s
  end
  set_infohash
end