Created
November 16, 2024 10:52
-
-
Save floehopper/fe59485e96c6f856a9c060b892d03f00 to your computer and use it in GitHub Desktop.
Revisions
-
floehopper created this gist
Nov 16, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,77 @@ #!/usr/bin/env ruby require "bundler/inline" gemfile do source "https://rubygems.org" gem "typhoeus" end require "uri" require "typhoeus" abort "Usage: ruby download.rb <url>" if ARGV.empty? url = ARGV.first response = Typhoeus.head(url) if response.success? if content_length = response.headers["Content-Length"] total_size = content_length.to_i else abort "Content-Length header is missing, unable to determine file size." end if content_disposition = response.headers["Content-Disposition"] match = response.headers["Content-Disposition"].match(/filename="([^"]+)"/) filename = match[1] if match end else abort "HEAD request failed: #{response.code}" end unless filename uri = URI.parse(url) filename = File.basename(uri.path) end num_parts = 4 part_size = (total_size / num_parts.to_f).ceil ranges = Array.new(num_parts) do |i| start_byte = i * part_size end_byte = [start_byte + part_size - 1, total_size - 1].min "bytes=#{start_byte}-#{end_byte}" end hydra = Typhoeus::Hydra.new parts = [] ranges.each_with_index do |range, index| request = Typhoeus::Request.new(url, headers: { "Range" => range }) request.on_complete do |response| if response.success? file_name = "part_#{index}" File.write(file_name, response.body) parts << file_name puts response.headers["Content-Range"] puts "Downloaded part #{index}: #{response.code}" else puts "Failed to download part #{index}: #{response.code}" end end hydra.queue(request) end hydra.run File.open(filename, "wb") do |output| parts.each do |part| File.open(part, "rb") do |input| IO.copy_stream(input, output) end end end parts.each { |part| File.delete(part) } puts "Download complete: #{filename}"