Module: Rapidshare::Ext::API

Included in:
API
Defined in:
lib/rapidshare-ext/api.rb

Constant Summary collapse

FILE_COLUMNS =
'downloads,lastdownload,filename,size,serverid,type,x,y,realfolder,killdeadline,uploadtime,comment,md5hex,licids,sentby'

Instance Method Summary collapse

Instance Method Details

#add_folder(path, params = {}) ⇒ Integer

Creates a folder in a Rapidshare virtual filesystem

api.add_folder('/a/b/c') #=> <Random folder ID from Rapidshare>, 1234 for example

Parameters:

  • path (String)

    Folder name with absolute path to be created

  • params (Hash) (defaults to: {})

Returns:

  • (Integer)


14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/rapidshare-ext/api.rb', line 14

def add_folder(path, params = {})
  path = path_trim path

  @tree = folders_hierarchy
  i = 1
  parent = 0
  folder_id = nil
  while i <= path.split('/').count do
    base_path = path.split('/')[0,i].join('/')
    folder_id = self.folder_id base_path
    if folder_id
      parent = folder_id
      i += 1
    else
      # Create folder
      folder_name = path.split('/')[i-1]
      add_folder_params = {
        :name => folder_name,
        :parent => parent
      }.merge params

       # The following code deals with #{} because of rest client #to_i returns HTTP code
      folder_id = "#{addrealfolder(add_folder_params)}".to_i
      raise 'error while creating folder' if parent < 0
      @tree[folder_id] = {
        :parent => parent,
        :name => folder_name,
        :path => path_canonize((@tree[parent] || {})[:path].to_s + ('/' if @tree[parent]).to_s + folder_name)
      }
      parent = folder_id
      path == base_path + '/' + folder_name
      i += 1
      next
    end
  end
  folder_id
end

#detect_gapsObject

Returns gap list between folders See #gap? for example



388
389
390
391
392
393
# File 'lib/rapidshare-ext/api.rb', line 388

def detect_gaps
  @tree = folders_hierarchy :validate => false
  @tree.dup.keep_if do |folder_id, data|
    gap? folder_id # This is wrong
  end.keys
end

#erase_all_data!Object

The name speaks for itself WARNING!!! All data will be lost!!! Use it carefully



398
399
400
401
402
403
404
# File 'lib/rapidshare-ext/api.rb', line 398

def erase_all_data!
  @tree = folders_hierarchy! :validate => false
  @tree.keys.each do |folder_id|
    delrealfolder :realfolder => folder_id
  end
  folders_hierarchy!
end

#file_id(file_path, params = {}) ⇒ Object

Returns file ID by absolute path

api.file_id('foo/bar/baz/file.rar') # => <FILE_ID>


515
516
517
518
519
# File 'lib/rapidshare-ext/api.rb', line 515

def file_id(file_path, params = {})
  params[:fields] = ''
  file_info = file_info file_path, params
  (file_info || {})[:id].to_i
end

#file_info(file_path, params = {}) ⇒ Object

Get file info in the following format:

:downloads,
:lastdownload,
:filename,
:size,
:serverid,
:type,
:x,
:y,
:realfolder,
:killdeadline,
:uploadtime,
:comment,
:md5hex,
:licids,
:sentby

See the images.rapidshare.com/apidoc.txt for more details



483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
# File 'lib/rapidshare-ext/api.rb', line 483

def file_info(file_path, params = {})
  folder_path = File.dirname file_path
  file_name = File.basename file_path

  folder_id = folder_id folder_path

  listfiles_params = {
    :realfolder => folder_id,
    :filename => "#{file_name}",
    :fields => FILE_COLUMNS,
    :parser => :csv
  }.merge params

  resp = listfiles(listfiles_params)[0]
  return nil if 'NONE' == resp[0]

  response = {}

  fields = listfiles_params[:fields].split(',')
  fields.unshift 'id'
  fields.each_with_index do |value, index|
    response[value.to_sym] = resp[index]
  end

  response[:url] = "https://rapidshare.com/files/#{response[:id]}/#{URI::encode response[:filename]}" if response[:filename]

  response
end

#folder_id(folder_path) ⇒ Object

Get folder ID by path

api.folder_id('foo/bar/baz') # -> 123


452
453
454
455
456
457
458
459
460
461
# File 'lib/rapidshare-ext/api.rb', line 452

def folder_id(folder_path)
  folder_path = path_trim(folder_path)
  return 0 if folder_path.empty?

  @tree = folders_hierarchy
  index = @tree.find_index do |folder_id, data|
    path_trim(data[:path]) == path_trim(folder_path)
  end
  @tree.keys[index] unless index.nil?
end

#folder_path(folder_id) ⇒ Object

Translate folder ID to a human readable path

api.folder_path(123) # -> 'foo/bar/baz'


439
440
441
442
443
444
445
446
447
# File 'lib/rapidshare-ext/api.rb', line 439

def folder_path(folder_id)
  @tree = folders_hierarchy

  folder_data = @tree[folder_id] || {:parent => 0, :name => '<undefined>', :path => '<undefined>'}

  parent_id = folder_data[:parent]
  path = (folder_path(parent_id) if parent_id.nonzero?).to_s + ('/' if parent_id.nonzero?).to_s + folder_data[:name]
  parent_id.zero? ? "/#{path}" : path
end

#folders_hierarchy(params = {}) ⇒ Object

Build folders hierarchy in the following format: {

<folder ID> => {
  :parent => <parent folder ID>,
  :name => <folder name>,
  :path => <folder absolute path>
},
...

}

:force

Invalidate cached tree, default: false After each call of this method the generated tree will be saved as cache to avoid unnecessary queries to be performed fpr a future calls

:validate

Validate tree after it has been generated, default: true

:consistent

Delete all found orphans, default: false Ignored if :validate is set to false

Parameters:

  • params (Hash) (defaults to: {})

Raises:

  • (Exception)


261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/rapidshare-ext/api.rb', line 261

def folders_hierarchy(params = {})
  force_load = params.delete :force
  from_folder_path = path_trim(params.delete(:from) || '/')
  remove_orphans = params.delete(:consistent)
  perform_validation = params.delete(:validate)
  perform_validation = true if perform_validation.nil?
  remove_orphans = false unless perform_validation

  if @tree && !force_load
    if from_folder_path.empty?
      return @tree
    else
      return slice_tree @tree, :from => from_folder_path
    end
  end

  return @tree if @tree && !force_load # TODO: about slices here (:from parameter)
  @tree = {}

  from_folder_id = folder_id from_folder_path
  raise Exception, "Folder #{from_folder_path} could not be found" if from_folder_id.nil?

  response = listrealfolders

  if 'NONE' == response
    @tree = {}
  else
    intermediate = response.split(' ').map do |str|
      params = str.split ','
      [params[0].to_i, {:parent => params[1].to_i, :name => params[2]}]
    end

    @tree = Hash[intermediate]
  end

  # Kill orphans
  remove_orphans! if remove_orphans

  @tree.each_pair do |folder_id, data|
    @tree[folder_id][:path] = folder_path folder_id
  end

  if perform_validation
    # Validate folder tree consistency
    @tree.each_pair do |folder_id, data|
      parent_id = data[:parent]
      if !parent_id.zero? && @tree[parent_id].nil?
        error = "Directory tree consistency error. Parent folder ##{data[:parent]} for the folder \"#{data[:path]}\" [#{folder_id}] could not be found"
        raise error
      end
    end
  end

  @tree = slice_tree @tree, :from => from_folder_path unless from_folder_path.empty?
  @tree
end

#folders_hierarchy!(params = {}) ⇒ Object Also known as: reload!

See #folders_hierarchy method



234
235
236
237
# File 'lib/rapidshare-ext/api.rb', line 234

def folders_hierarchy!(params = {})
  params[:force] = true
  folders_hierarchy params
end

#gap?(folder_id) ⇒ Boolean

Check if the given folder has no parent

Returns:

  • (Boolean)


414
415
416
417
418
# File 'lib/rapidshare-ext/api.rb', line 414

def gap?(folder_id)
  @tree = folders_hierarchy :validate => false
  parent_id = @tree[folder_id][:parent]
  @tree[parent_id].nil?
end

#move_file(remote_path, params = {}) ⇒ Object

Moves file to a specified folder

:to

Destination folder path, default: ‘/’

api.move_file('/foo/bar/baz.rar', :to => '/foo')
api.move_file('/foo/bar/baz.rar') # move to a root folder

Parameters:

  • remote_path (String)
  • params (Hash) (defaults to: {})


221
222
223
224
225
226
227
228
229
230
231
# File 'lib/rapidshare-ext/api.rb', line 221

def move_file(remote_path, params = {})
  file_id = file_id remote_path
  dest_path = path_trim(params.delete(:to) || '/')

  params = {
    :files => file_id,
    :realfolder => folder_id(dest_path)
  }.merge params

  movefilestorealfolder params
end

#move_folder(source_path, params = {}) ⇒ Object

Moves folder into a specified one

Parameters:

  • source_path (String)
  • params (Hash) (defaults to: {})

    :to => <destination folder path>, default: ‘/’

    api.move_folder('/a/b/c', :to => '/a')
    


90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/rapidshare-ext/api.rb', line 90

def move_folder(source_path, params = {})
  dest_path = (params.delete(:to) || '/')
  source_folder_id = folder_id(source_path)
  dest_folder_id = folder_id(dest_path)

  params = {
    :realfolder => source_folder_id,
    :newparent => dest_folder_id
  }.merge params

  moverealfolder params

  @tree = folders_hierarchy
  @tree[source_folder_id][:parent] = dest_folder_id
  @tree[source_folder_id][:path] = path_canonize "#{folder_path(dest_folder_id)}/#{@tree[source_folder_id][:name]}"
  true
end

#move_orphans(params = {}) ⇒ Object

Places all existing orphan folders under the specific folder Orphan folder is a folder with non existing parent (yes, it’s possible)

Example: move_orphans :to => ‘/’



373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/rapidshare-ext/api.rb', line 373

def move_orphans(params = {})
  new_folder = path_trim(params.delete(:to) || '/')
  gaps = detect_gaps

  if gaps.any?
    params = {
      :realfolder => gaps.join(','),
      :newparent => new_folder
    }.merge params
    moverealfolder params
  end
end

#orphan?(folder_id) ⇒ Boolean

Check if folder has any gaps in it hierarchy For example we have the following hierarchy:

ROOT ‘-a <- if we remove just this folder then the folder ’c’ and ‘b’ will become orphans

`-b
  `-c

Returns:

  • (Boolean)


427
428
429
430
431
432
433
434
# File 'lib/rapidshare-ext/api.rb', line 427

def orphan?(folder_id)
  @tree = folders_hierarchy :validate => false
  return false if @tree[folder_id].nil?
  parent_id = @tree[folder_id][:parent]
  return false if root_folder? folder_id
  return true if gap? folder_id
  orphan?(parent_id)
end

#remove_file(path, params = {}) ⇒ Object

Delete file

Parameters:

  • path (String)
  • params (Hash) (defaults to: {})

    api.remove_file(‘/putin/is/a/good/reason/to/live/abroad/ticket_to_Nikaragua.jpg’)



185
186
187
188
189
190
191
# File 'lib/rapidshare-ext/api.rb', line 185

def remove_file(path, params = {})
  params = {
    :files => file_id(path).to_s
  }.merge params

  deletefiles params
end

#remove_folder(path, params = {}) ⇒ Array

Removes a specified folder

Parameters:

  • path (String)
  • params (Hash) (defaults to: {})

Returns:

  • (Array)

    api.remove_folder(‘/a/b/c’)

Raises:

  • (Exception)


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rapidshare-ext/api.rb', line 59

def remove_folder(path, params = {})
  folder_id = self.folder_id path_trim(path)
  raise Exception, "Folder #{path} could not be found" if folder_id.nil?

  # TODO
  tree = folders_hierarchy :from => path
  tree.each_pair do |child_folder_id, data|
    delrealfolder_params = {
      :realfolder => child_folder_id
    }.merge params

    delrealfolder delrealfolder_params
    @tree.delete folder_id
  end

  params = {
    :realfolder => folder_id
  }.merge params

  delrealfolder params

  @tree.delete folder_id
end

#remove_orphans!Object

Fix inconsistent folder tree (Yes, getting a broken folder hierarchy is possible with a stupid Rapidshare API) by deleting orphan folders (folders with no parent folder), this folders are invisible in Rapidshare File Manager So, this method deletes orphan folders



356
357
358
359
360
361
362
363
364
365
366
# File 'lib/rapidshare-ext/api.rb', line 356

def remove_orphans!
  @tree = folders_hierarchy :validate => false
  @tree.each_pair do |folder_id, data|
    @tree.delete_if do |folder_id, data|
      if orphan? folder_id
        delrealfolder :realfolder => folder_id
        true
      end
    end
  end
end

#rename_file(remote_path, name, params = {}) ⇒ Object

Rename file

Parameters:

  • remote_path (String)
  • name (String)
  • params (Hash) (defaults to: {})

    api.rename_file(‘/foo/bar.rar’, ‘baz.rar’)



200
201
202
203
204
205
206
207
208
209
210
# File 'lib/rapidshare-ext/api.rb', line 200

def rename_file(remote_path, name, params = {})
  file_id = file_id remote_path

  params = {
    :fileid => file_id,
    :newname => name
  }.merge params

  renamefile params
  # TODO: duplicates check
end

#root_folder?(folder_id) ⇒ Boolean

Check if folder with given id placed on the bottom of folder hierarchy

Returns:

  • (Boolean)


407
408
409
410
411
# File 'lib/rapidshare-ext/api.rb', line 407

def root_folder?(folder_id)
  @tree = folders_hierarchy :validate => false
  return false if @tree[folder_id].nil?
  @tree[folder_id][:parent].zero?
end

#slice_tree(tree, params = {}) ⇒ Object

Build tree relative to a specified folder If the source tree is: tree =

1 => {:parent => 0, :name => 'a', :path => 'a',
2 => => 1, :name => 'b', :path => 'a/b',
3 => => 2, :name => 'c', :path => 'a/b/c',
...

} slice_tree tree, :from => ‘/a’ Result will be as follows: {

2 => {:parent => 1, :name => 'b', :path => 'b'},
3 => {:parent => 2, :name => 'c', :path => 'b/c'},
...

}



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/rapidshare-ext/api.rb', line 333

def slice_tree(tree, params = {})
  from_folder_path = path_trim(params.delete(:from) || '/')

  result_tree = tree.dup

  unless from_folder_path == ''

    result_tree.keep_if do |folder_id, data|
      path_trim(data[:path]).start_with? "#{from_folder_path}/"
    end

    result_tree.each_pair do |folder_id, data|
      path = result_tree[folder_id][:path]
      result_tree[folder_id][:path] = path_canonize path_trim(path.gsub /#{from_folder_path.gsub /\//, '\/'}\//, '')
    end
  end

  result_tree
end

#upload(file_path, params = {}) ⇒ Object

Upload file to a specified folder

:to

Folder to place uploaded file to, default: ‘/’

:as

The name file will have in storage after it has been uploaded

:overwrite

Overwrite file if it already exists in the given folder

api.upload('/home/odiszapc/my_damn_cat.mov', :to => '/gallery/video', :as => 'cat1.mov')

Parameters:

  • file_path (String)
  • params (Hash) (defaults to: {})

Raises:

  • (Exception)


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/rapidshare-ext/api.rb', line 120

def upload(file_path, params = {})
  raise Exception unless File.exist? file_path
  dest_path = path_trim(params.delete(:to) || '/')
  folder_id = self.add_folder dest_path
  file_name = params.delete(:as) || File.basename(file_path)
  overwrite = params.delete :overwrite

  # Check file already exists within a folder
  listfiles_params = {
    :realfolder => folder_id,
    :filename => "#{file_name}",
    :fields => 'md5hex,size',
    :parser => :csv
  }
  listfiles_response = self.listfiles listfiles_params

  file_already_exists = ('NONE' != listfiles_response[0][0])
  remove_file "#{dest_path}/#{file_name}" if file_already_exists && overwrite

  # In case of file is not existing then upload it
  if !file_already_exists || overwrite
    upload_server = "rs#{self.nextuploadserver}.rapidshare.com"

    upload_params = {
      :server => upload_server,
      :folder => folder_id,
      :filename => file_name,
      :filecontent => file_path,
      :method => :post,
      :parser => :csv
    }.merge params

    resp = request(:upload, upload_params)
    raise Exception, "File uploading failed: #{resp.inspect}" unless "COMPLETE" == resp[0][0]

    id = resp[1][0].to_i
    md5_hash = resp[1][3]
    size = resp[1][2].to_i
    already_exists = false
  else
    id = listfiles_response[0][0].to_i
    md5_hash = listfiles_response[0][1]
    size = listfiles_response[0][2].to_i
    already_exists = true
  end

  raise Exception, "Invalid File ID: #{resp.inspect}" unless id
  raise Exception, "Invalid MD5 hash: #{resp.inspect}" unless md5_hash
  raise Exception, "Invalid File Size: #{resp.inspect}" unless size

  {
    :id         => id,
    :size       => size,
    :checksum   => md5_hash.downcase,
    :url        => "https://rapidshare.com/files/#{id}/#{URI::encode file_name}",
    :already_exists? => already_exists
  }
end