flv-dl 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ -
2
+ ChangeLog.md
3
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ doc/
2
+ pkg/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown --title "flv-dl Documentation" --protected
data/ChangeLog.md ADDED
@@ -0,0 +1,4 @@
1
+ ### 0.1.0 / 2012-07-14
2
+
3
+ * Initial release:
4
+
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Postmodern
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # flv-dl
2
+
3
+ * [Homepage](https://github.com/sophsec/flv-dl#readme)
4
+ * [Issues](https://github.com/sophsec/flv-dl/issues)
5
+ * [Documentation](http://rubydoc.info/gems/flv-dl/frames)
6
+ * [Email](mailto:postmodern.mod3 at gmail.com)
7
+
8
+ ## Description
9
+
10
+ Downloads or plays Flash Video (flv) file directly from their web-page.
11
+
12
+ ## Why?
13
+
14
+ Because **fuck flash**, that's why.
15
+
16
+ ## Features
17
+
18
+ * Extracts `flashvars` from:
19
+ * `param` tags.
20
+ * `embed` / `object` tags.
21
+ * JavaScript
22
+
23
+ ## Synopsis
24
+
25
+ Downloads a video:
26
+
27
+ flv-dl "URL"
28
+
29
+ Plays a video:
30
+
31
+ flv-dl -p totem "URL"
32
+
33
+ List available formats / URLs:
34
+
35
+ flv-dl -U "URL"
36
+
37
+ Dumps the collected `flashvars`:
38
+
39
+ flv-dl -D "URL"
40
+
41
+ ## Requirements
42
+
43
+ * [nokogiri](https://github.com/tenderlove/nokogiri) ~> 1.4
44
+
45
+ ## Install
46
+
47
+ $ gem install flv-dl
48
+
49
+ ## Copyright
50
+
51
+ Copyright (c) 2012 Postmodern
52
+
53
+ See {file:LICENSE.txt} for details.
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+
6
+ begin
7
+ gem 'rubygems-tasks', '~> 0.2'
8
+ require 'rubygems/tasks'
9
+
10
+ Gem::Tasks.new
11
+ rescue LoadError => e
12
+ warn e.message
13
+ warn "Run `gem install rubygems-tasks` to install 'rubygems/tasks'."
14
+ end
15
+
16
+ begin
17
+ gem 'rspec', '~> 2.4'
18
+ require 'rspec/core/rake_task'
19
+
20
+ RSpec::Core::RakeTask.new
21
+ rescue LoadError => e
22
+ task :spec do
23
+ abort "Please run `gem install rspec` to install RSpec."
24
+ end
25
+ end
26
+
27
+ task :test => :spec
28
+ task :default => :spec
29
+
30
+ begin
31
+ gem 'yard', '~> 0.7'
32
+ require 'yard'
33
+
34
+ YARD::Rake::YardocTask.new
35
+ rescue LoadError => e
36
+ task :yard do
37
+ abort "Please run `gem install yard` to install YARD."
38
+ end
39
+ end
40
+ task :doc => :yard
data/bin/flv-dl ADDED
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'net/http'
4
+ require 'optparse'
5
+ require 'pp'
6
+
7
+ require 'flv/video'
8
+
9
+ options = {
10
+ :mode => :play,
11
+ :player => ENV['VIDEO_PLAYER'],
12
+ :format => :flv
13
+ }
14
+
15
+ optparser = OptionParser.new do |opts|
16
+ opts.banner = "Usage: #{File.basename($0)} [options] URL"
17
+
18
+ opts.on('-o','--output PATH','Path to download the video to') do |output|
19
+ options[:mode] = :download
20
+ options[:output] = output
21
+ end
22
+
23
+ opts.on('-p','--play [COMMAND]','Play the video URL') do |player|
24
+ options[:mode] = :play
25
+ options[:player] = player if player
26
+ end
27
+
28
+ opts.on('-f',"--format [#{FLV::Video::FORMATS.keys.join(', ')}]",'The video format') do |format|
29
+ options[:format] = format.to_sym
30
+ end
31
+
32
+ opts.on('-F', '--formats','Lists the available video formats') do
33
+ options[:mode] = :list
34
+ options[:list] = :formats
35
+ end
36
+
37
+ opts.on('-U', '--urls','Lists the available video URLs') do
38
+ options[:mode] = :list
39
+ options[:list] = :urls
40
+ end
41
+
42
+ opts.on('-D', '--dump','Dumps the flashvars') do
43
+ options[:mode] = :list
44
+ options[:list] = :flashvars
45
+ end
46
+ end
47
+
48
+ optparser.parse!
49
+
50
+ video = FLV::Video.new(ARGV[0])
51
+
52
+ if options[:list]
53
+ case options[:list]
54
+ when :formats
55
+ puts(*video.formats)
56
+ when :urls
57
+ video.video_urls.each do |format,url|
58
+ puts "#{format}: #{url}"
59
+ end
60
+ when :flashvars
61
+ pp video.flashvars
62
+ end
63
+ else
64
+ unless video.flashvars
65
+ $stderr.puts "Could not extract flashvars from #{video.url}"
66
+ exit -1
67
+ end
68
+
69
+ unless video.formats.include?(options[:format])
70
+ $stderr.puts "Unknown format: #{options[:format]}"
71
+ exit -1
72
+ end
73
+
74
+ video_url = video.video_urls[options[:format]]
75
+
76
+ case options[:mode]
77
+ when :play
78
+ unless options[:player]
79
+ $stderr.puts "Must specify the video player via --play or $VIDEO_PLAYER"
80
+ exit -1
81
+ end
82
+
83
+ system(options[:player],video_url)
84
+ when :download
85
+ unless options[:output]
86
+ $stderr.puts "Must specify --output PATH"
87
+ exit -1
88
+ end
89
+
90
+ puts ">>> Requesting #{video_url} ..."
91
+
92
+ http = Net::HTTP.new(video_url.host,video_url.port)
93
+
94
+ if video_url.scheme == 'https'
95
+ require 'net/https'
96
+
97
+ http.use_ssl = true
98
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
99
+ end
100
+
101
+ request = Net::HTTP::Get.new(video_url.request_uri)
102
+ request['Referer'] = video_url
103
+ request['User-Agent'] = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)'
104
+
105
+ http.request(request) do |response|
106
+ size, total = 0, response.header['Content-Length'].to_i
107
+
108
+ video_path = options.fetch(:output)
109
+
110
+ puts ">>> Downloading to #{video_path.dump} ..."
111
+
112
+ File.open(video_path,"wb") do |file|
113
+ response.read_body do |chunk|
114
+ file.write(chunk)
115
+
116
+ size += chunk.size
117
+ printf "\r>>> [%d / %d] %d%% ...", size, total, ((size * 100) / total)
118
+ end
119
+ end
120
+
121
+ puts "\n>>> Download complete!"
122
+ end
123
+ end
124
+ end
data/flv-dl.gemspec ADDED
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'flv/dl/version'
14
+ Flv::Dl::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+
24
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
25
+
26
+ gem.files = `git ls-files`.split($/)
27
+ gem.files = glob[gemspec['files']] if gemspec['files']
28
+
29
+ gem.executables = gemspec.fetch('executables') do
30
+ glob['bin/*'].map { |path| File.basename(path) }
31
+ end
32
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
33
+
34
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
35
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
36
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
37
+
38
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
39
+ %w[ext lib].select { |dir| File.directory?(dir) }
40
+ })
41
+
42
+ gem.requirements = gemspec['requirements']
43
+ gem.required_ruby_version = gemspec['required_ruby_version']
44
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
45
+ gem.post_install_message = gemspec['post_install_message']
46
+
47
+ split = lambda { |string| string.split(/,\s*/) }
48
+
49
+ if gemspec['dependencies']
50
+ gemspec['dependencies'].each do |name,versions|
51
+ gem.add_dependency(name,split[versions])
52
+ end
53
+ end
54
+
55
+ if gemspec['development_dependencies']
56
+ gemspec['development_dependencies'].each do |name,versions|
57
+ gem.add_development_dependency(name,split[versions])
58
+ end
59
+ end
60
+ end
data/gemspec.yml ADDED
@@ -0,0 +1,18 @@
1
+ name: flv-dl
2
+ version: 0.1.0
3
+ summary: Downloads Flash Video (flv) files from web-pages.
4
+ description:
5
+ Downloads or plays Flash Video (flv) files directly from web-pages.
6
+
7
+ license: MIT
8
+ authors: Postmodern
9
+ email: postmodern.mod3@gmail.com
10
+ homepage: https://github.com/sophsec/flv-dl#readme
11
+
12
+ dependencies:
13
+ nokogiri: ~> 1.4
14
+
15
+ development_dependencies:
16
+ rubygems-tasks: ~> 0.2
17
+ rspec: ~> 2.4
18
+ yard: ~> 0.7
data/lib/flv/video.rb ADDED
@@ -0,0 +1,128 @@
1
+ require 'uri'
2
+ require 'open-uri'
3
+ require 'nokogiri'
4
+ require 'json'
5
+ require 'uri/query_params'
6
+
7
+ module FLV
8
+ class Video
9
+
10
+ FORMATS = {
11
+ :mp4 => ['mp4_url'],
12
+ :flv => ['flv_url', 'flv', 'video_url', 'file'],
13
+ :flv_h264 => ['flv_h264']
14
+ }
15
+
16
+ attr_reader :url
17
+
18
+ def initialize(url)
19
+ @url = URI(url)
20
+ @doc = Nokogiri::HTML(open(@url))
21
+ end
22
+
23
+ def title
24
+ @title ||= @doc.at('//title').inner_text
25
+ end
26
+
27
+ def flashvars
28
+ @flashvars ||= (
29
+ extract_flashvars_from_html ||
30
+ extract_flashvars_from_embedded_html ||
31
+ extract_flashvars_from_javascript ||
32
+ {}
33
+ )
34
+ end
35
+
36
+ def formats
37
+ @formats ||= FORMATS.keys.select do |format|
38
+ FORMATS[format].any? { |var| flashvars.has_key?(var) }
39
+ end
40
+ end
41
+
42
+ def video_urls
43
+ @video_urls ||= begin
44
+ urls = {}
45
+
46
+ FORMATS.each do |format,vars|
47
+ vars.each do |var|
48
+ if flashvars.has_key?(var)
49
+ urls[format] = @url.merge(flashvars[var])
50
+ next
51
+ end
52
+ end
53
+ end
54
+
55
+ urls
56
+ end
57
+ end
58
+
59
+ protected
60
+
61
+ FLASHVARS_XPATHS = [
62
+ '//@flashvars',
63
+ '//param[@name="flashvars"]/@value',
64
+ '//param[@name="FlashVars"]/@value'
65
+ ]
66
+
67
+ def extract_flashvars_from_html(doc=@doc)
68
+ if (flashvars = doc.at(FLASHVARS_XPATHS.join('|')))
69
+ URI::QueryParams.parse(flashvars.value)
70
+ end
71
+ end
72
+
73
+ EMBEDDED_FLASHVARS_XPATHS = [
74
+ '//*[contains(.,"flashvars")]',
75
+ '//*[contains(.,"FlashVars")]'
76
+ ]
77
+
78
+ def extract_flashvars_from_embedded_html
79
+ if (attr = @doc.at(EMBEDDED_FLASHVARS_XPATHS.join('|')))
80
+ html = Nokogiri::HTML(attr.inner_text)
81
+
82
+ extract_flashvars_from_html(html)
83
+ end
84
+ end
85
+
86
+ FLASHVARS_JAVASCRIPT_XPATHS = [
87
+ '//script[contains(.,"flashvars")]',
88
+ '//script[contains(.,"jwplayer")]',
89
+ ]
90
+
91
+ def extract_flashvars_from_javascript
92
+ if (script = @doc.at(FLASHVARS_JAVASCRIPT_XPATHS.join('|')))
93
+ code = script.inner_text
94
+
95
+ return extract_flashvars_from_javascript_function(code) ||
96
+ extract_flashvars_from_javascript_hash(code)
97
+ end
98
+ end
99
+
100
+ FLASHVARS_FUNCTION_REGEXP = /['"]flashvars['"]\s*,\s*['"]([^'"]+)['"]/
101
+
102
+ def extract_flashvars_from_javascript_function(code)
103
+ if (match = code.match(FLASHVARS_FUNCTION_REGEXP))
104
+ URI::QueryParams.parse(match[1])
105
+ end
106
+ end
107
+
108
+ FLASHVARS_HASH_REGEXP = /(?:flashvars\s*=\s*|jwplayer\(['"][a-z]+['"]\).setup\()(\{[^\}]+\})/m
109
+
110
+ def extract_flashvars_from_javascript_hash(code)
111
+ regexp = lambda { |vars|
112
+
113
+ }
114
+
115
+ flashvars = {}
116
+
117
+ vars = FORMATS.values.flatten
118
+ regexp = /['"](#{Regexp.union(vars)})['"]:\s*['"]([^'"]+)['"]/
119
+
120
+ if (match = code.match(regexp))
121
+ flashvars[match[1]] = URI.decode(match[2])
122
+ end
123
+
124
+ return flashvars
125
+ end
126
+
127
+ end
128
+ end
@@ -0,0 +1,5 @@
1
+ gem 'rspec', '~> 2.4'
2
+ require 'rspec'
3
+ require 'flv/dl/version'
4
+
5
+ include Flv::Dl
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flv-dl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Postmodern
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nokogiri
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.4'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.4'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rubygems-tasks
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '0.2'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '0.2'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.4'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.4'
62
+ - !ruby/object:Gem::Dependency
63
+ name: yard
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '0.7'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '0.7'
78
+ description: Downloads or plays Flash Video (flv) files directly from web-pages.
79
+ email: postmodern.mod3@gmail.com
80
+ executables:
81
+ - flv-dl
82
+ extensions: []
83
+ extra_rdoc_files:
84
+ - ChangeLog.md
85
+ - LICENSE.txt
86
+ - README.md
87
+ files:
88
+ - .document
89
+ - .gitignore
90
+ - .rspec
91
+ - .yardopts
92
+ - ChangeLog.md
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - bin/flv-dl
97
+ - flv-dl.gemspec
98
+ - gemspec.yml
99
+ - lib/flv/video.rb
100
+ - spec/spec_helper.rb
101
+ homepage: https://github.com/sophsec/flv-dl#readme
102
+ licenses:
103
+ - MIT
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 1.8.24
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: Downloads Flash Video (flv) files from web-pages.
126
+ test_files: []