Skip to content

Instantly share code, notes, and snippets.

@yamaimo
Last active August 29, 2015 14:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yamaimo/faa5ee763f8e33684b87 to your computer and use it in GitHub Desktop.
Save yamaimo/faa5ee763f8e33684b87 to your computer and use it in GitHub Desktop.
NicovideoDownloader-mini with Ruby
#!/usr/bin/env ruby
require 'netrc'
require 'net/http'
require 'net/https'
require 'cgi'
LoginURI = URI.parse("https://secure.nicovideo.jp/secure/login?site=niconico")
LoginPostFormat = "current_form=login&mail=%s&password=%s&login_submit=Log+In"
VideoHost = "www.nicovideo.jp"
VideoPathFormat = "/watch/%s"
VideoURLRegexp = %r{^(?:(?:http://)?(?:\w+\.)?(?:nicovideo\.jp/(?:v/|(?:watch(?:\.php)?))?/)?(\w+))}
VideoInfoPathFormat = "/api/getflv?v=%s&as3=1"
VideoTypeRegexp = %r{^http://.*\.nicovideo\.jp/smile\?(.*?)=.*}
if ARGV.size < 1
raise "URL is not specified."
end
url = ARGV[0]
puts "Download #{url}"
# get user info
netrc_info = Netrc.read
user, password = netrc_info["nicovideo"]
if user.nil? || user.empty? || password.nil? || password.empty?
raise "Netrc is invalid."
end
# login
https = Net::HTTP.new(LoginURI.host, LoginURI.port)
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
postdata = sprintf(LoginPostFormat, user, password)
response = https.post(LoginURI.request_uri, postdata)
user_session = nil
response.get_fields('set-cookie').each do |cookie|
key, value = cookie.split(';').first.split('=')
if (key == 'user_session') && (value != 'deleted')
user_session = value
break
end
end
if user_session.nil?
raise "Failed to login."
end
# get video id
video_id = nil
if match_data = VideoURLRegexp.match(url)
video_id = match_data[1]
else
raise "URL is invalid. [url=#{url}]"
end
# access video page and get cookie
http = Net::HTTP.new(VideoHost)
video_path = sprintf(VideoPathFormat, video_id)
response = http.get(video_path, {'Cookie' => "user_session=#{user_session};"})
nicohistory = nil
response.get_fields('set-cookie').each do |cookie|
key, value = cookie.split(';').first.split('=')
if key == 'nicohistory'
nicohistory = value
break
end
end
# get video uri
http = Net::HTTP.new(VideoHost)
video_info_path = sprintf(VideoInfoPathFormat, video_id)
response = http.get(video_info_path,
{'Cookie' => "user_session=#{user_session}; nicohistory=#{nicohistory};"})
while response.is_a?(Net::HTTPRedirection)
redirect_uri = URI.parse(response.get_fields('location').first)
http = Net::HTTP.new(redirect_uri.host)
response = http.get(redirect_uri.request_uri,
{'Cookie' => "user_session=#{user_session}; nicohistory=#{nicohistory};"})
end
video_uri = nil
begin
info = CGI.parse(response.body)
video_url = info['url'].first
video_uri = URI.parse(video_url)
rescue
raise "Failed to access video information."
end
# set output filename
video_extension = ".flv"
if match_data = VideoTypeRegexp.match(video_uri.to_s)
if match_data[1] == "s"
video_extension = ".swf"
elsif match_data[1] == "m"
video_extension = ".mp4"
else
video_extension = ".flv"
end
else
video_extension = ".flv"
end
output_filename = "#{video_id}#{video_extension}"
# get video data
http = Net::HTTP.new(video_uri.host)
http.request_get(video_uri.request_uri,
{'Cookie' => "user_session=#{user_session}; nicohistory=#{nicohistory};"}) do |response|
File.open(output_filename, "wb") do |file|
response.read_body do |video_block|
file.write(video_block)
end
end
end
puts "done."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment