Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
You can’t perform that action at this time.