viddl-rb 0.65 → 0.66

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 (5) hide show
  1. data/README.md +11 -2
  2. data/bin/viddl-rb +1 -0
  3. data/plugins/vimeo.rb +38 -24
  4. data/plugins/youtube.rb +27 -7
  5. metadata +22 -8
data/README.md CHANGED
@@ -18,16 +18,25 @@ Download a video and extract the audio:
18
18
 
19
19
  In both cases we'll name the output file according to the video title.
20
20
 
21
- Download all videos on a Youtube playlist:
21
+ __Youtube plugin specifics:__
22
+
23
+ Download all videos on a playlist:
22
24
  viddl-rb http://www.youtube.com/playlist?list=PL7E8DA0A515924126
23
25
 
24
- Download all videos from a Youtube user:
26
+ Download all videos from a user:
25
27
  viddl-rb http://www.youtube.com/user/tedtalksdirector
26
28
 
29
+ Filter videos to download from a user/playlist:
30
+ viddl-rb http://www.youtube.com/user/tedtalksdirector --filter=internet/i
31
+
32
+ The --filter argument accepts a regular expression and will only download videos where the title matches the regex.
33
+ The /i option does a case-insensitive search.
34
+
27
35
  __Requirements:__
28
36
 
29
37
  * curl/wget or the [progress bar](http://github.com/nex3/ruby-progressbar/) gem
30
38
  * [Nokogiri](http://nokogiri.org/)
39
+ * [Mechanize](http://mechanize.rubyforge.org/)
31
40
  * ffmpeg if you want to extract audio tracks from the videos
32
41
 
33
42
 
@@ -3,6 +3,7 @@ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'helper')
3
3
 
4
4
  require "rubygems"
5
5
  require "nokogiri"
6
+ require "mechanize"
6
7
  require "cgi"
7
8
  require "open-uri"
8
9
  require "open3"
@@ -1,25 +1,39 @@
1
+
1
2
  class Vimeo < PluginBase
2
- #this will be called by the main app to check whether this plugin is responsible for the url passed
3
- def self.matches_provider?(url)
4
- url.include?("vimeo.com")
5
- end
6
-
7
- def self.get_urls_and_filenames(url)
8
- #the vimeo ID consists of 7 decimal numbers in the URL
9
- vimeo_id = url[/\d{7,8}/]
10
- doc = Nokogiri::XML(open("http://www.vimeo.com/moogaloop/load/clip:#{vimeo_id}"))
11
- title = doc.at("//video/caption").inner_text
12
- puts "[VIMEO] Title: #{title}"
13
- request_signature = doc.at("//request_signature").inner_text
14
- request_signature_expires = doc.at("//request_signature_expires").inner_text
15
-
16
-
17
- puts "[VIMEO] Request Signature: #{request_signature} expires: #{request_signature_expires}"
18
-
19
- download_url = "http://www.vimeo.com/moogaloop/play/clip:#{vimeo_id}/#{request_signature}/#{request_signature_expires}/?q=hd"
20
- #todo: put the filename cleaning stuff into a seperate helper
21
- file_name = title.delete("\"'").gsub(/[^0-9A-Za-z]/, '_') + ".flv"
22
- puts "downloading to " + file_name
23
- [{:url => download_url, :name => file_name}]
24
- end
25
- end
3
+ #this will be called by the main app to check whether this plugin is responsible for the url passed
4
+ def self.matches_provider?(url)
5
+ url.include?("vimeo.com")
6
+ end
7
+
8
+ def self.get_urls_and_filenames(url)
9
+ #the vimeo ID consists of 7 decimal numbers in the URL
10
+ vimeo_id = url[/\d{7,8}/]
11
+
12
+ agent = Mechanize.new #use Mechanize for the automatic cookie handeling
13
+ agent.redirect_ok = false #don't follow redirects so we do not download the video when we get it's url
14
+
15
+ video_page = agent.get("http://vimeo.com/#{vimeo_id}")
16
+ page_html = video_page.root.inner_html
17
+
18
+ title = page_html[/<meta\s+property="og:title"\s+content="(.+?)"/, 1]
19
+ puts "[VIMEO] Title: #{title}"
20
+
21
+ #the timestamp and sig info is in the embedded player javascript in the video page
22
+ timestamp = page_html[/"timestamp":(\d+),/, 1]
23
+ signature = page_html[/"signature":"([\d\w]+)",/, 1]
24
+
25
+ # The quality and codecs are listed in order of preference in the url. If HD is not availabe SD will be download for example.
26
+ redirect_url = "http://player.vimeo.com/play_redirect?clip_id=#{vimeo_id}&sig=#{signature}&time=#{timestamp}&quality=hd,sd&codecs=H264,VP8,VP6"
27
+
28
+ #the download url is the value of the location (redirect) header
29
+ download_url = agent.get(redirect_url).header["location"]
30
+
31
+ file_name = make_filename(title)
32
+
33
+ [{:url => download_url, :name => file_name}]
34
+ end
35
+
36
+ def self.make_filename(title)
37
+ title.delete("\"'").gsub(/[^\d\w]/, '_') + ".mp4"
38
+ end
39
+ end
@@ -7,23 +7,43 @@ class Youtube < PluginBase
7
7
 
8
8
  #get all videos and return their urls in an array
9
9
  def self.get_video_urls(feed_url)
10
- urls = []
10
+ puts "[YOUTUBE] Retrieving videos..."
11
+ urls_titles = Hash.new
11
12
  result_feed = Nokogiri::HTML(open(feed_url))
12
- urls << grab_urls(result_feed)
13
+ urls_titles.merge!(grab_ut(result_feed))
13
14
 
14
15
  #as long as the feed has a next link we follow it and add the resulting video urls
15
16
  loop do
16
17
  next_link = result_feed.search("//feed/link[@rel='next']").first
17
18
  break if next_link.nil?
18
19
  result_feed = Nokogiri::HTML(open(next_link["href"]))
19
- urls << grab_urls(result_feed)
20
+ urls_titles.merge!(grab_ut(result_feed))
21
+ end
22
+
23
+ self.filter_urls(urls_titles)
24
+ end
25
+
26
+ #returns only the urls that match the --filter argument regex (if present)
27
+ def self.filter_urls(url_hash)
28
+ #get the --filter arg or "" if it is not present (because nil would break the next line)
29
+ filter = ARGV.find( proc {""} ) { |arg| arg =~ /--filter=/ }
30
+ regex = filter[/--filter=(.+?)(?:\/|$)/, 1]
31
+ if regex
32
+ puts "[YOUTUBE] Using filter: #{regex}"
33
+ ignore_case = filter.include?("/i")
34
+ filtered = url_hash.select { |url, title| title =~ Regexp.new(regex, ignore_case) }
35
+ filtered.keys
36
+ else
37
+ url_hash.keys
20
38
  end
21
- urls.flatten
22
39
  end
23
40
 
24
- #extract all video urls form a feed an return in an array
25
- def self.grab_urls(feed)
26
- feed.search("//entry/link[@rel='alternate']").map { |link| link["href"] }
41
+ #extract all video urls and their titles from a feed and return in a hash
42
+ def self.grab_ut(feed)
43
+ feed.remove_namespaces! #so that we can get to the titles easily
44
+ urls = feed.search("//entry/link[@rel='alternate']").map { |link| link["href"] }
45
+ titles = feed.search("//entry/group/title").map { |title| title.text }
46
+ Hash[urls.zip(titles)] #hash like this: url => title
27
47
  end
28
48
 
29
49
  def self.parse_playlist(url)
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: viddl-rb
3
3
  version: !ruby/object:Gem::Version
4
- hash: 137
4
+ hash: 143
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 65
9
- version: "0.65"
8
+ - 66
9
+ version: "0.66"
10
10
  platform: ruby
11
11
  authors:
12
12
  - Marc Seeger
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2012-05-02 00:00:00 Z
17
+ date: 2012-06-03 00:00:00 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: nokogiri
@@ -31,7 +31,7 @@ dependencies:
31
31
  type: :runtime
32
32
  version_requirements: *id001
33
33
  - !ruby/object:Gem::Dependency
34
- name: rake
34
+ name: mechanize
35
35
  prerelease: false
36
36
  requirement: &id002 !ruby/object:Gem::Requirement
37
37
  none: false
@@ -42,10 +42,10 @@ dependencies:
42
42
  segments:
43
43
  - 0
44
44
  version: "0"
45
- type: :development
45
+ type: :runtime
46
46
  version_requirements: *id002
47
47
  - !ruby/object:Gem::Dependency
48
- name: minitest
48
+ name: rake
49
49
  prerelease: false
50
50
  requirement: &id003 !ruby/object:Gem::Requirement
51
51
  none: false
@@ -59,7 +59,7 @@ dependencies:
59
59
  type: :development
60
60
  version_requirements: *id003
61
61
  - !ruby/object:Gem::Dependency
62
- name: rest-client
62
+ name: minitest
63
63
  prerelease: false
64
64
  requirement: &id004 !ruby/object:Gem::Requirement
65
65
  none: false
@@ -72,6 +72,20 @@ dependencies:
72
72
  version: "0"
73
73
  type: :development
74
74
  version_requirements: *id004
75
+ - !ruby/object:Gem::Dependency
76
+ name: rest-client
77
+ prerelease: false
78
+ requirement: &id005 !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ hash: 3
84
+ segments:
85
+ - 0
86
+ version: "0"
87
+ type: :development
88
+ version_requirements: *id005
75
89
  description: An extendable commandline video downloader for flash video sites. Includes plugins for vimeo, youtube and megavideo
76
90
  email: mail@marc-seeger.de
77
91
  executables: