trans-api 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +22 -0
- data/README.md +334 -0
- data/Rakefile +1 -0
- data/examples/basic_setup.rb +78 -0
- data/examples/torrents/debian-6.0.6-amd64-CD-10.iso.torrent +0 -0
- data/lib/trans-api/client.rb +30 -0
- data/lib/trans-api/connect.rb +331 -0
- data/lib/trans-api/file.rb +56 -0
- data/lib/trans-api/session.rb +83 -0
- data/lib/trans-api/torrent.rb +292 -0
- data/lib/trans-api/version.rb +5 -0
- data/lib/trans-api.rb +12 -0
- data/test/test_helper.rb +8 -0
- data/test/unit/torrents/debian-6.0.6-amd64-CD-1.iso.torrent +0 -0
- data/test/unit/torrents/debian-6.0.6-amd64-CD-2.iso.torrent +0 -0
- data/test/unit/torrents/debian-6.0.6-amd64-CD-3.iso.torrent +0 -0
- data/test/unit/torrents/debian-6.0.6-amd64-CD-4.iso.torrent +0 -0
- data/test/unit/torrents/debian-6.0.6-amd64-CD-5.iso.torrent +0 -0
- data/test/unit/torrents/debian-6.0.6-amd64-CD-6.iso.torrent +0 -0
- data/test/unit/torrents/debian-6.0.6-amd64-CD-7.iso.torrent +0 -0
- data/test/unit/trans_connect.rb +459 -0
- data/test/unit/trans_session_object.rb +82 -0
- data/test/unit/trans_torrent_object.rb +354 -0
- data/trans-api.gemspec +24 -0
- metadata +124 -0
@@ -0,0 +1,292 @@
|
|
1
|
+
module Trans
|
2
|
+
module Api
|
3
|
+
|
4
|
+
#
|
5
|
+
# Torrent class
|
6
|
+
#
|
7
|
+
|
8
|
+
class Torrent
|
9
|
+
|
10
|
+
# torrent status value
|
11
|
+
STATUS = [ :stopped, :checkQueue, :checkFiles, :downloadQueue, :downloading, :seedQueue, :seeding, :isolated ]
|
12
|
+
|
13
|
+
# torrent get fields
|
14
|
+
ACCESSOR_FIELDS = [
|
15
|
+
:activityDate, :addedDate, :bandwidthPriority, :comment, :corruptEver, :creator, :dateCreated, :desiredAvailable,
|
16
|
+
:doneDate, :downloadDir, :downloadedEver, :downloadLimit, :downloadLimited, :error, :errorString, :eta, :files,
|
17
|
+
:fileStats, :hashString, :haveUnchecked, :haveValid, :honorsSessionLimits, :id, :isFinished, :isPrivate, :isStalled,
|
18
|
+
:leftUntilDone, :magnetLink, :manualAnnounceTime, :maxConnectedPeers, :metadataPercentComplete, :name, :peer_limit,
|
19
|
+
:peers, :peersConnected, :peersFrom, :peersGettingFromUs, :peersSendingToUs, :percentDone, :pieces, :pieceCount,
|
20
|
+
:pieceSize, :priorities, :queuePosition, :rateDownload, :rateUpload, :recheckProgress, :secondsDownloading,
|
21
|
+
:secondsSeeding, :seedIdleLimit, :seedIdleMode, :seedRatioLimit, :seedRatioMode, :sizeWhenDone, :startDate, :status,
|
22
|
+
:trackers, :trackerStats, :totalSize, :torrentFile, :uploadedEver, :uploadLimit, :uploadLimited, :uploadRatio,
|
23
|
+
:wanted, :webseeds, :webseedsSendingToUs ]
|
24
|
+
|
25
|
+
# torrent set fields
|
26
|
+
MUTATOR_FIELDS = [ :bandwidthPriority, :downloadLimit, :downloadLimited, :files_wanted, :files_unwanted, :honorsSessionLimits,
|
27
|
+
:ids, :location, :peer_limit, :priority_high, :priority_low, :priority_normal, :queuePosition, :seedIdleLimit,
|
28
|
+
:seedIdleMode, :seedRatioLimit, :seedRatioMode, :trackerAdd, :trackerRemove, :trackerReplace, :uploadLimit, :uploadLimited ]
|
29
|
+
|
30
|
+
# torrent add fields
|
31
|
+
ADD = [ :cookies, :download_dir, :filename, :metainfo, :paused, :peer_limit, :bandwidthPriority, :files_wanted,
|
32
|
+
:files_unwanted, :priority_high, :priority_low, :priority_normal ]
|
33
|
+
|
34
|
+
DELETE = [ :ids, :delete_local_data ]
|
35
|
+
|
36
|
+
LOCATION = [ :ids, :move, :location ]
|
37
|
+
|
38
|
+
|
39
|
+
@@default_fields = [ :id, :name, :status ]
|
40
|
+
|
41
|
+
|
42
|
+
# constructor
|
43
|
+
def initialize(options={})
|
44
|
+
@client = Client.new
|
45
|
+
@fields = options[:torrent] if options.include? :torrent
|
46
|
+
@old_fields = @fields.clone
|
47
|
+
@last_error = {error: "", message: ""}
|
48
|
+
self.attach_methods!
|
49
|
+
end
|
50
|
+
|
51
|
+
# placeholder for fields
|
52
|
+
def metaclass
|
53
|
+
class << self; self; end
|
54
|
+
end
|
55
|
+
|
56
|
+
def status_name
|
57
|
+
STATUS[self.status]
|
58
|
+
end
|
59
|
+
|
60
|
+
# store changed field
|
61
|
+
def save!
|
62
|
+
# reject unchanged fields
|
63
|
+
changed = @fields.reject{|k,v| @old_fields[k] == v}
|
64
|
+
# reject inmutable fields
|
65
|
+
changed.reject!{|k,v| !MUTATOR_FIELDS.include?(k) }
|
66
|
+
# reject empty arrays
|
67
|
+
changed.reject!{|k,v| v.class == Array && v.empty? }
|
68
|
+
if changed.size > 0
|
69
|
+
# call api, and store changed fields
|
70
|
+
@client.connect.torrent_set changed, [self.id]
|
71
|
+
@old_fields = @fields.clone
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# get registered fields
|
76
|
+
def fields
|
77
|
+
@fields
|
78
|
+
end
|
79
|
+
|
80
|
+
# files wrapped by an File object
|
81
|
+
def files_objects
|
82
|
+
ret = []
|
83
|
+
# i = -1
|
84
|
+
torrent = @client.connect.torrent_get([:files, :fileStats], [self.id]).first
|
85
|
+
@fields[:files] = torrent[:files]
|
86
|
+
@fields[:fileStatus] = torrent[:fileStats]
|
87
|
+
self.files.each_with_index{ |f,i| ret << Trans::Api::File.new( torrent: self, fields: @fields,
|
88
|
+
file: f.merge(id: i).merge(fileStat: torrent[:fileStats][i])) }
|
89
|
+
ret
|
90
|
+
end
|
91
|
+
|
92
|
+
# reload current object
|
93
|
+
def reset!
|
94
|
+
@fields = @client.connect.torrent_get( @fields.map{|k,v| k}, [self.id]).first
|
95
|
+
@old_fields = @fields.clone
|
96
|
+
@last_error = {error: "", message: ""}
|
97
|
+
end
|
98
|
+
|
99
|
+
def start!
|
100
|
+
@client.connect.torrent_start [self.id]
|
101
|
+
end
|
102
|
+
|
103
|
+
def start_now!
|
104
|
+
@client.connect.torrent_start_now [self.id]
|
105
|
+
end
|
106
|
+
|
107
|
+
def stop!
|
108
|
+
@client.connect.torrent_stop [self.id]
|
109
|
+
end
|
110
|
+
|
111
|
+
def verify!
|
112
|
+
@client.connect.torrent_verify [self.id]
|
113
|
+
end
|
114
|
+
|
115
|
+
def reannounce!
|
116
|
+
@client.connect.torrent_reannounce [self.id]
|
117
|
+
end
|
118
|
+
|
119
|
+
def set_location!(file, move = false)
|
120
|
+
@client.connect.torrent_set_location({location: file, move: move}, [self.id])
|
121
|
+
end
|
122
|
+
|
123
|
+
def delete!(options={})
|
124
|
+
options[:delete_local_data] = false unless options.include? :delete_local_data # optional
|
125
|
+
@client.connect.torrent_remove options, [self.id]
|
126
|
+
end
|
127
|
+
|
128
|
+
def queue_top!
|
129
|
+
@client.connect.queue_move_top [self.id]
|
130
|
+
end
|
131
|
+
|
132
|
+
def queue_bottom!
|
133
|
+
@client.connect.queue_move_bottom [self.id]
|
134
|
+
end
|
135
|
+
|
136
|
+
def queue_up!
|
137
|
+
@client.connect.queue_move_up [self.id]
|
138
|
+
end
|
139
|
+
|
140
|
+
def queue_down!
|
141
|
+
@client.connect.queue_move_down [self.id]
|
142
|
+
end
|
143
|
+
|
144
|
+
# wait for a specific torrent lambda after call
|
145
|
+
# Ex: lamb = instance.waitfor_after(lambda{|torrent| torrent.status_name != :stopped}, :after).start!
|
146
|
+
def waitfor(lamb, place = :after)
|
147
|
+
TorrentDummy.new lamb, self, place
|
148
|
+
end
|
149
|
+
|
150
|
+
# static methods
|
151
|
+
class << self
|
152
|
+
def all
|
153
|
+
torrents = Client.new.connect.torrent_get( @@default_fields )
|
154
|
+
torrents.map{|t| Torrent.new torrent: t}
|
155
|
+
end
|
156
|
+
|
157
|
+
def find(id)
|
158
|
+
torrents = Client.new.connect.torrent_get( @@default_fields , [id])
|
159
|
+
remap = torrents.map{|t| Torrent.new torrent: t }
|
160
|
+
return remap.first if torrents.size == 1
|
161
|
+
return nil if torrents.empty?
|
162
|
+
remap
|
163
|
+
end
|
164
|
+
|
165
|
+
def find_by_field_value(field, value)
|
166
|
+
# set a reduced search field (with some default values)
|
167
|
+
fields = [field, :id, :name, :status]
|
168
|
+
torrents = Client.new.connect.torrent_get( fields )
|
169
|
+
torrents.reject!{|t| t[field] != value}
|
170
|
+
# TODO: perhaps add original default values??
|
171
|
+
remap = torrents.map{|t| Torrent.new torrent: t }
|
172
|
+
return remap.first if torrents.size == 1
|
173
|
+
return nil if torrents.empty?
|
174
|
+
remap
|
175
|
+
end
|
176
|
+
|
177
|
+
def start_all
|
178
|
+
torrents = Client.new.connect.torrent_get [:id, :status]
|
179
|
+
remap = torrents.map{ |t| Torrent.new torrent: t }
|
180
|
+
Client.new.connect.torrent_start remap.map{|t| t.id}
|
181
|
+
end
|
182
|
+
|
183
|
+
def stop_all
|
184
|
+
torrents = Client.new.connect.torrent_get [:id, :status]
|
185
|
+
remap = torrents.map{ |t| Torrent.new torrent: t }
|
186
|
+
Client.new.connect.torrent_stop remap.map{|t| t.id}
|
187
|
+
end
|
188
|
+
|
189
|
+
def delete_all(torrents, options={})
|
190
|
+
raise "no ids assigned" if torrents.empty? || !torrents.kind_of?(Array)
|
191
|
+
raise "expected type: Torrent" if torrents.size > 0 && !torrents.first.kind_of?(Torrent)
|
192
|
+
ids = torrents.map{|torrent| torrent.id}
|
193
|
+
client = Client.new
|
194
|
+
options[:delete_local_data] = false unless options.include? :delete_local_data # optional
|
195
|
+
client.connect.torrent_remove options
|
196
|
+
end
|
197
|
+
|
198
|
+
def add_file(filename, options={})
|
199
|
+
raise "file not found: #{filename}" unless ::File.exists? filename
|
200
|
+
client = Client.new
|
201
|
+
options[:filename] = filename
|
202
|
+
torrent = client.connect.torrent_add options
|
203
|
+
torrent = client.connect.torrent_get( @@default_fields, [torrent[:id]]).first
|
204
|
+
Torrent.new torrent: torrent
|
205
|
+
end
|
206
|
+
|
207
|
+
def default_fields=(list=[])
|
208
|
+
@@default_fields << :id unless list.include? :id
|
209
|
+
@@default_fields |= list
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
protected
|
215
|
+
|
216
|
+
# define helper methods for setting and getting field information
|
217
|
+
def attach_methods!
|
218
|
+
|
219
|
+
# NOTE: not all accessor fields are mutators as well!!
|
220
|
+
|
221
|
+
MUTATOR_FIELDS.each do |k|
|
222
|
+
# setter
|
223
|
+
self.metaclass.send(:define_method, "#{k}=") do |value|
|
224
|
+
unless @fields.include? k
|
225
|
+
fields = @client.connect.torrent_get([k], [self.id]).first
|
226
|
+
@fields.merge! fields
|
227
|
+
@old_fields.merge! fields
|
228
|
+
end
|
229
|
+
@fields[k] = value
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
ACCESSOR_FIELDS.each do |k|
|
235
|
+
# getter
|
236
|
+
self.metaclass.send(:define_method, "#{k}") do
|
237
|
+
# request handler to get new field
|
238
|
+
unless @fields.include? k
|
239
|
+
fields = @client.connect.torrent_get([k], [self.id]).first
|
240
|
+
@fields.merge! fields
|
241
|
+
@old_fields.merge! fields
|
242
|
+
end
|
243
|
+
@fields[k]
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
|
250
|
+
protected
|
251
|
+
|
252
|
+
# Dummy class to handle chained calling
|
253
|
+
# Inspired by delayed_job (message_sending.rb)
|
254
|
+
# https://github.com/collectiveidea/delayed_job/blob/master/lib/delayed/message_sending.rb
|
255
|
+
class TorrentDummy
|
256
|
+
|
257
|
+
def initialize(task, target_object, place)
|
258
|
+
@task = task # lambda
|
259
|
+
@target_object = target_object
|
260
|
+
@place = place
|
261
|
+
|
262
|
+
self.wait if @place == :before
|
263
|
+
end
|
264
|
+
|
265
|
+
# handling Torrent method calls
|
266
|
+
def method_missing(method, *args)
|
267
|
+
|
268
|
+
unless args.empty?
|
269
|
+
@target_object.send method, args
|
270
|
+
else
|
271
|
+
@target_object.send method
|
272
|
+
end
|
273
|
+
|
274
|
+
self.wait if @place == :after
|
275
|
+
|
276
|
+
end
|
277
|
+
|
278
|
+
def wait
|
279
|
+
# keep trying task (and refreshing the torrent file)
|
280
|
+
while true do
|
281
|
+
@target_object.reset!
|
282
|
+
t = @task.call @target_object
|
283
|
+
break if t # task achieved!
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
|
291
|
+
end
|
292
|
+
end
|
data/lib/trans-api.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/trans-api/version")
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/trans-api/client")
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/trans-api/connect")
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + "/trans-api/session")
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + "/trans-api/torrent")
|
6
|
+
require File.expand_path(File.dirname(__FILE__) + "/trans-api/file")
|
7
|
+
|
8
|
+
module Trans
|
9
|
+
module Api
|
10
|
+
# placeholder
|
11
|
+
end
|
12
|
+
end
|
data/test/test_helper.rb
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|