youtube_utils 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. data/bin/youtube_utils +57 -0
  2. data/lib/youtube_utils.rb +151 -0
  3. 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
+