vsco-dll2/vsco-dl.rb
Nick/Nelson ee04f8fef3
Fix weird https redirection downgrade bug
For some reason this endpoint occasionally sends a 302 redirect to an http image instead of https. >:(
Ideally this should be reverted back to using https at some point, but I can't reproduce this in any
browser, so I have no idea what exactly is causing it. Sometimes changing the referer works for specific
images, other times it doesn't. This isn't the most secure, but it should be the most reliable. Hopefully
whoever is mitm-ing you isn't concerned with what vsco profiles you're downloading.
2018-03-21 00:45:12 +00:00

95 lines
2.7 KiB
Ruby

require 'json'
require 'open-uri'
require 'fileutils'
require 'optparse'
require 'securerandom'
options = {}
parser = OptionParser.new do |opts|
opts.banner = "Usage: vsco-dl.rb [options] username"
opts.on "-m", "--[no-]metadata", "Save metadata" do |m|
options[:metadata] = m
end
opts.on "-oOUTPUT", "--output=output", "Where to save the files (default is cwd)" do |o|
options[:output] = o
end
opts.on "-w", "--[no-]overwrite", "Overwrite previously downloaded files" do |w|
options[:overwrite] = w
end
end
parser.parse!
user = ARGV[0]
if user.nil?
$stderr.puts "Error: Username is required."
$stderr.puts parser
exit 1
end
print "Loading initial data"
# this endpoint requires the referer for some reason
initial = open "https://vsco.co/content/Static/userinfo",
'Cookie' => "vs_anonymous_id=#{SecureRandom.uuid}",
'Referer' => "https://vsco.co/#{user}/images/1"
# the ol' jsonp for same origin requests because why not
vs = JSON.parse(initial.read[/{.+}/])['tkn']
sites = JSON.load open "https://vsco.co/ajxp/#{vs}/2.0/sites?subdomain=#{user}", 'Cookie' => "vs=#{vs}"
# the ol' return an array when you only queried for one thing
site_id = sites['sites'][0]['id']
# vsco seems to timeout on requests for very large amounts of images
# it also doesn't send the actual total amount of images in requests
# total will either be the real total or page * size + 1, which means
# there's at least one more page of images to be requested (or more)
page = 1
size = 1000
images = []
loop do
response = JSON.load open "https://vsco.co/ajxp/#{vs}/2.0/medias?site_id=#{site_id}&page=#{page}&size=#{size}", 'Cookie' => "vs=#{vs}"
images.concat response['media']
break if response['total'] <= page * size
page += 1
end
puts " ...done!"
path = user
path = File.join options[:output], user unless options[:output].nil?
FileUtils.mkdir_p path unless File.exist? path
images.each_with_index do |r, i|
print "Image #{i + 1} of #{images.length}\r"
file_path = File.join path, "#{r['upload_date']}"
if options[:metadata]
json_path = "#{file_path}.json"
if options[:overwrite] or not File.exist? json_path
File.open json_path, 'w' do |file|
file.write JSON.pretty_generate r
end
end
end
image_url = r['is_video'] ? r['video_url'] : r['responsive_url']
image_path = "#{file_path}#{File.extname image_url}"
if options[:overwrite] or not File.exist? image_path
# opening these with https was oddly buggy and would constantly
# try to redirect downgrade to http no matter what I did
open "http://#{image_url}" do |f|
File.open image_path, 'wb' do |file|
file.write f.read
end
end
end
if (i + 1) == images.length
puts "Image #{i + 1} of #{images.length} ...done!"
end
end