youtube_utils 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/youtube_utils +57 -0
- data/lib/youtube_utils.rb +151 -0
- metadata +82 -0
data/bin/youtube_utils
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'youtube_utils'
|
5
|
+
|
6
|
+
def usage
|
7
|
+
puts 'Usage:'
|
8
|
+
puts 'youtube_utils <youtube_url>'
|
9
|
+
puts 'Example:'
|
10
|
+
puts 'youtube_utils http://www.youtube.com/watch?v=cRdxXPV9GNQ'
|
11
|
+
end
|
12
|
+
|
13
|
+
def download url, output
|
14
|
+
if `/usr/bin/env curl --version` =~ /libcurl/
|
15
|
+
run_command "/usr/bin/env curl -L -C - -o #{output} '#{url}'"
|
16
|
+
elsif `/usr/bin/env wget --version` =~ /Wget/
|
17
|
+
run_command "/usr/bin/env wget '#{url}' -c -O #{output}"
|
18
|
+
else
|
19
|
+
puts "Can not find curl or wget!"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def ask_user_which_one_to_download videos
|
24
|
+
i = 0
|
25
|
+
videos.each {|x|
|
26
|
+
puts "#{i}\t#{x['quality']}\t#{YoutubeUtils.type2suffix(x['type'])}"
|
27
|
+
i += 1
|
28
|
+
}
|
29
|
+
print "Please select a video to download by enter its number:"
|
30
|
+
return $stdin.gets
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_filename url, type
|
34
|
+
vid = YoutubeUtils.get_vid(url)
|
35
|
+
suffix = YoutubeUtils.type2suffix(type)
|
36
|
+
return vid + "." + suffix
|
37
|
+
end
|
38
|
+
|
39
|
+
def run_command command
|
40
|
+
puts command
|
41
|
+
result = `#{command}`
|
42
|
+
puts result
|
43
|
+
return result
|
44
|
+
end
|
45
|
+
|
46
|
+
def run url
|
47
|
+
videos = YoutubeUtils.new.get_videos url
|
48
|
+
index = ask_user_which_one_to_download(videos).to_i
|
49
|
+
download videos[index]['url'], build_filename(url, videos[index]['type'])
|
50
|
+
end
|
51
|
+
|
52
|
+
if ARGV.empty?
|
53
|
+
usage
|
54
|
+
else
|
55
|
+
run ARGV[0]
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'yajl'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
#http://unlockforus.blogspot.com/2010/04/downloading-youtube-videos-not-working.html
|
6
|
+
#http://board.jdownloader.org/showthread.php?t=18520
|
7
|
+
class YoutubeUtils
|
8
|
+
def get_videos youtube_watch_url
|
9
|
+
res = get_webpage(youtube_watch_url);
|
10
|
+
unless res.code == '200'
|
11
|
+
puts res.code
|
12
|
+
return []
|
13
|
+
end
|
14
|
+
|
15
|
+
hash = json_to_hash(get_PLAYER_CONFIG(res.body))
|
16
|
+
unless hash
|
17
|
+
puts "no PLAYER_CONFIG"
|
18
|
+
return []
|
19
|
+
end
|
20
|
+
|
21
|
+
args = hash['args']
|
22
|
+
unless args
|
23
|
+
puts "no args"
|
24
|
+
return []
|
25
|
+
end
|
26
|
+
|
27
|
+
result = []
|
28
|
+
|
29
|
+
html5_fmt_map = args['html5_fmt_map']
|
30
|
+
result.concat(convert_html5_fmt_map(html5_fmt_map)) if html5_fmt_map
|
31
|
+
|
32
|
+
fmt_stream_map = args['fmt_stream_map']
|
33
|
+
fmt_list = args['fmt_list']
|
34
|
+
result.concat(convert_fmt_stream_map(fmt_stream_map, fmt_list)) if fmt_list&&fmt_stream_map
|
35
|
+
|
36
|
+
return result
|
37
|
+
end
|
38
|
+
|
39
|
+
#input: http://www.youtube.com/watch?v=cRdxXPV9GNQ
|
40
|
+
#output: cRdxXPV9GNQ
|
41
|
+
def self.get_vid url
|
42
|
+
querys = URI.parse(url).query.split('&')
|
43
|
+
querys.each {|x|
|
44
|
+
a = x.split('=')
|
45
|
+
if a[0] == 'v'
|
46
|
+
return a[1]
|
47
|
+
end
|
48
|
+
}
|
49
|
+
return nil
|
50
|
+
end
|
51
|
+
|
52
|
+
#input: video/webm; codecs="vp8.0, v
|
53
|
+
#outut: webm
|
54
|
+
def self.type2suffix type
|
55
|
+
return type.split(';')[0].split('/')[1]
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def convert_itag_to_type itag
|
61
|
+
case itag.to_i
|
62
|
+
when 0, 6
|
63
|
+
return "video/flv; codecs=\" h263, mp3 mono\""
|
64
|
+
when 5
|
65
|
+
return "video/flv; codecs=\"h263, mp3 stereo\""
|
66
|
+
when 34, 35
|
67
|
+
return "video/flv; codecs=\"h264, aac stereo\""
|
68
|
+
when 13
|
69
|
+
return "video/3gp; codecs=\"h263, amr mono\""
|
70
|
+
when 17
|
71
|
+
return "video/3gp; codecs=\"h264 aac stereo\""
|
72
|
+
when 18, 22, 37, 38, 78
|
73
|
+
return "video/mp4; codecs=\"h264, aac stereo\""
|
74
|
+
when 43, 45
|
75
|
+
return "video/webm; codecs=\"vp8.0, vorbis stereo\""
|
76
|
+
else
|
77
|
+
return "unknown #{itag}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
#{"url"=>"http://v5.lscache8.c.youtube.com/videoplayback?...", "type"=>"video/webm; codecs=\"vp8.0, vorbis\"", "itag"=>43, "quality"=>"medium"}
|
82
|
+
def convert_html5_fmt_map a
|
83
|
+
result = []
|
84
|
+
a.each {|x|
|
85
|
+
result << {'url' => x['url'], 'type' => x['type'], 'quality' => x['quality']}
|
86
|
+
}
|
87
|
+
return result
|
88
|
+
end
|
89
|
+
|
90
|
+
#22/1280x720/9/0/115
|
91
|
+
def convert_fmt_stream_map fmt_stream_map, fmt_list
|
92
|
+
result = []
|
93
|
+
a1 = fmt_stream_map.split(',')
|
94
|
+
a2 = fmt_list.split(',')
|
95
|
+
i = 0
|
96
|
+
a1.each {|x|
|
97
|
+
a11 = x.split('|')
|
98
|
+
itag = a11[0]
|
99
|
+
url = a11[1]
|
100
|
+
|
101
|
+
a21 = a2[i].split('/')
|
102
|
+
resolution = a21[1]
|
103
|
+
result << {'url' => url, 'type' => convert_itag_to_type(itag), 'quality' => resolution2quality(resolution)}
|
104
|
+
i += 1;
|
105
|
+
}
|
106
|
+
return result
|
107
|
+
end
|
108
|
+
|
109
|
+
def resolution2quality resolution
|
110
|
+
height = resolution.split('x')[1].to_i
|
111
|
+
if height > 1080
|
112
|
+
return "Original"
|
113
|
+
elsif height > 720
|
114
|
+
return "1080p"
|
115
|
+
elsif height > 576
|
116
|
+
return "720p"
|
117
|
+
elsif height > 360
|
118
|
+
return "480p"
|
119
|
+
elsif height > 240
|
120
|
+
return "360p"
|
121
|
+
else
|
122
|
+
return "240p"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def get_webpage youtube_watch_url
|
127
|
+
uri = URI.parse(youtube_watch_url)
|
128
|
+
res = Net::HTTP.start(uri.host, uri.port) { |http|
|
129
|
+
http.get(uri.path + "?" + uri.query, {'Cookie' => 'PREF=f2=40000000'})
|
130
|
+
}
|
131
|
+
|
132
|
+
return res
|
133
|
+
end
|
134
|
+
|
135
|
+
def json_to_hash js
|
136
|
+
json = StringIO.new(js)
|
137
|
+
parser = Yajl::Parser.new
|
138
|
+
begin
|
139
|
+
return parser.parse(json)
|
140
|
+
rescue
|
141
|
+
puts "Unable to parse as json"
|
142
|
+
return nil
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def get_PLAYER_CONFIG body
|
147
|
+
body[/\'PLAYER_CONFIG\':(.*)\}\)\;\n/]
|
148
|
+
return $1
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: youtube_utils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Xue Yong Zhi
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-04-28 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: yajl-ruby
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description:
|
36
|
+
email:
|
37
|
+
- yong@intridea.com
|
38
|
+
executables:
|
39
|
+
- youtube_utils
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
files:
|
45
|
+
- lib/youtube_utils.rb
|
46
|
+
- bin/youtube_utils
|
47
|
+
has_rdoc: true
|
48
|
+
homepage: http://github.com/yong/youtube_utils
|
49
|
+
licenses: []
|
50
|
+
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
requirements: []
|
75
|
+
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.3.7
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: youtube downloader
|
81
|
+
test_files: []
|
82
|
+
|