downthetube 0.0.2 → 0.0.3
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.
- data/downthetube.gemspec +2 -2
- data/lib/downthetube/play_list.rb +99 -0
- data/lib/downthetube/video.rb +87 -0
- data/lib/downthetube/youtube.rb +18 -0
- metadata +7 -5
- data/lib/youtube.rb +0 -121
data/downthetube.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
specification = Gem::Specification.new do |spec|
|
2
2
|
# Descriptive and source information for this gem.
|
3
3
|
spec.name = "downthetube"
|
4
|
-
spec.version = "0.0.
|
4
|
+
spec.version = "0.0.3"
|
5
5
|
spec.description = "A library to make downloading playlists and videos from Youtube less nasty."
|
6
6
|
spec.summary = "Downloads playlists and videos from Youtube."
|
7
7
|
spec.author = "Mike Williamson"
|
8
8
|
spec.email = "blessedbyvirtuosity@gmail.com"
|
9
9
|
spec.homepage = ""
|
10
10
|
require 'rake'
|
11
|
-
spec.files = %w(README lib/youtube.rb downthetube.gemspec)
|
11
|
+
spec.files = %w(README lib/downthetube/youtube.rb lib/downthetube/video.rb lib/downthetube/play_list.rb downthetube.gemspec)
|
12
12
|
spec.has_rdoc = false
|
13
13
|
spec.add_dependency("gdata", ">= 1.0.0")
|
14
14
|
spec.extra_rdoc_files = ["README"]
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Youtube
|
2
|
+
class Playlist
|
3
|
+
#TODO reduce the duplication between this and the video class
|
4
|
+
|
5
|
+
#include Naming from ActiveRecord if its here.
|
6
|
+
begin
|
7
|
+
self.extend ActiveModel::Naming
|
8
|
+
rescue NameError => e
|
9
|
+
#do nothing
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :url
|
13
|
+
|
14
|
+
def initialize entry
|
15
|
+
|
16
|
+
define_attrs
|
17
|
+
|
18
|
+
if ((entry) && (entry.class == REXML::Element))
|
19
|
+
@xml = entry
|
20
|
+
populate_attrs
|
21
|
+
|
22
|
+
elsif((entry.class==String)&&(entry =~ /\w{16}/))
|
23
|
+
@url = "http://gdata.youtube.com/feeds/api/playlists/#{entry}"
|
24
|
+
else
|
25
|
+
raise "The Playlist class did not understand the parameter it was initialized with."
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def populate_attrs
|
30
|
+
@client ||= GData::Client::YouTube.new
|
31
|
+
@xml ||= @client.get(self.url).to_xml
|
32
|
+
|
33
|
+
@id = @xml.get_text('yt:playlistId')
|
34
|
+
@title = @xml.get_text('title')
|
35
|
+
@author = @xml.get_text('author/name')
|
36
|
+
@xml.each_element_with_attribute('src'){|a| @url = a.attribute('src').to_s }
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def define_attrs
|
41
|
+
[:title, :author, :id].each do |attr|
|
42
|
+
method_def = <<-EOM
|
43
|
+
def #{attr}
|
44
|
+
if @#{attr}
|
45
|
+
@#{attr}
|
46
|
+
else
|
47
|
+
populate_attrs
|
48
|
+
@#{attr}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
EOM
|
52
|
+
class_eval method_def
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.name
|
57
|
+
"Playlist"
|
58
|
+
end
|
59
|
+
|
60
|
+
def videos limit=nil
|
61
|
+
|
62
|
+
case
|
63
|
+
when limit.nil?
|
64
|
+
get_videos unless @videos
|
65
|
+
when limit
|
66
|
+
if limit == @limit
|
67
|
+
get_videos(limit) unless @videos
|
68
|
+
else
|
69
|
+
get_videos(limit)
|
70
|
+
@limit = limit
|
71
|
+
end
|
72
|
+
else
|
73
|
+
puts "Your case has gone badly wrong"
|
74
|
+
end
|
75
|
+
@videos
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def get_videos number=nil
|
81
|
+
@client ||= GData::Client::YouTube.new
|
82
|
+
feed = @client.get(self.url).to_xml
|
83
|
+
@videos = []
|
84
|
+
counter = 1
|
85
|
+
if number
|
86
|
+
feed.elements.each('entry') do |entry|
|
87
|
+
if counter <= number
|
88
|
+
@videos<< Video.new(entry)
|
89
|
+
counter += 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
else
|
93
|
+
feed.elements.each('entry') do |entry|
|
94
|
+
@videos<< Video.new(entry)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Youtube
|
2
|
+
class Video
|
3
|
+
require 'gdata'
|
4
|
+
#include Naming from ActiveRecord if its here.
|
5
|
+
begin
|
6
|
+
self.extend ActiveModel::Naming
|
7
|
+
rescue NameError => e
|
8
|
+
#do nothing
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :url
|
12
|
+
|
13
|
+
def initialize entry
|
14
|
+
|
15
|
+
define_attrs
|
16
|
+
|
17
|
+
if entry.class == REXML::Element
|
18
|
+
@xml = entry
|
19
|
+
elsif((entry.class == String)&&(entry =~/\w{11}/))
|
20
|
+
@url = "http://gdata.youtube.com/feeds/api/videos/#{entry}?v=2"
|
21
|
+
else
|
22
|
+
raise "What was passed into Playlist class was not an REXML object"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def define_attrs
|
27
|
+
[:title, :description, :id, :uploader, :duration].each do |attr|
|
28
|
+
method_def = <<-EOM
|
29
|
+
def #{attr}
|
30
|
+
if @#{attr}
|
31
|
+
@#{attr}
|
32
|
+
else
|
33
|
+
populate_attrs
|
34
|
+
@#{attr}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
EOM
|
38
|
+
class_eval method_def
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def self.name
|
44
|
+
"Video"
|
45
|
+
end
|
46
|
+
|
47
|
+
def thumbnail size=:small
|
48
|
+
populate_attrs unless @large_thumbnail && @small_thumbnail
|
49
|
+
if size == :large
|
50
|
+
@large_thumbnail
|
51
|
+
else
|
52
|
+
@small_thumbnail
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def populate_attrs
|
58
|
+
|
59
|
+
@client ||= GData::Client::YouTube.new
|
60
|
+
@xml ||= @client.get(self.url).to_xml
|
61
|
+
|
62
|
+
|
63
|
+
@xml.elements.each('media:group') do |element|
|
64
|
+
@title = element.get_text('media:title')
|
65
|
+
@id = element.get_text('yt:videoid')
|
66
|
+
@description = element.get_text('media:description')
|
67
|
+
@uploader = element.get_text('media:credit')
|
68
|
+
element.elements.each('media:player'){|mp| @url = mp.attribute('url').to_s.gsub('&feature=youtube_gdata_player', '')}
|
69
|
+
element.elements.each('yt:duration'){|a| @duration = a.attribute('seconds').to_s }
|
70
|
+
element.elements.each('media:thumbnail') do |mt|
|
71
|
+
case mt.attribute('yt:name').to_s
|
72
|
+
when 'hqdefault'
|
73
|
+
@large_thumbnail = mt.attribute('url').to_s
|
74
|
+
when 'default'
|
75
|
+
@small_thumbnail = mt.attribute('url').to_s
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_xml
|
82
|
+
@xml.to_s
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Youtube
|
2
|
+
require 'rubygems'
|
3
|
+
require 'gdata'
|
4
|
+
|
5
|
+
def Youtube.playlists_for user
|
6
|
+
@client = GData::Client::YouTube.new
|
7
|
+
feed = @client.get("http://gdata.youtube.com/feeds/api/users/#{user}/playlists?v=2").to_xml
|
8
|
+
playlists = []
|
9
|
+
feed.elements.each('entry') do |entry|
|
10
|
+
playlists<< Playlist.new(entry)
|
11
|
+
end
|
12
|
+
playlists
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: downthetube
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Mike Williamson
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-06-
|
18
|
+
date: 2011-06-04 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -44,7 +44,9 @@ extra_rdoc_files:
|
|
44
44
|
- README
|
45
45
|
files:
|
46
46
|
- README
|
47
|
-
- lib/youtube.rb
|
47
|
+
- lib/downthetube/youtube.rb
|
48
|
+
- lib/downthetube/video.rb
|
49
|
+
- lib/downthetube/play_list.rb
|
48
50
|
- downthetube.gemspec
|
49
51
|
has_rdoc: true
|
50
52
|
homepage: ""
|
data/lib/youtube.rb
DELETED
@@ -1,121 +0,0 @@
|
|
1
|
-
class Youtube
|
2
|
-
require 'rubygems'
|
3
|
-
require 'gdata'
|
4
|
-
|
5
|
-
def Youtube.playlists_for user
|
6
|
-
@client = GData::Client::YouTube.new
|
7
|
-
feed = @client.get("http://gdata.youtube.com/feeds/api/users/#{user}/playlists?v=2").to_xml
|
8
|
-
playlists = []
|
9
|
-
feed.elements.each('entry') do |entry|
|
10
|
-
playlists<< Playlist.new(entry)
|
11
|
-
end
|
12
|
-
playlists
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
class Playlist
|
17
|
-
attr_reader :title, :author, :url, :id
|
18
|
-
|
19
|
-
def initialize entry
|
20
|
-
if ((entry) && (entry.class == REXML::Element))
|
21
|
-
@xml = entry
|
22
|
-
@id = @xml.get_text('yt:playlistId')
|
23
|
-
@title = @xml.get_text('title')
|
24
|
-
@author = @xml.get_text('author/name')
|
25
|
-
@xml.each_element_with_attribute('src'){|a| @url = a.attribute('src').to_s }
|
26
|
-
elsif((entry.class==String)&&(entry =~ /\w{16}/))
|
27
|
-
@url = "http://gdata.youtube.com/feeds/api/playlists/#{entry}"
|
28
|
-
else
|
29
|
-
raise "The Playlist class did not understand the parameter it was initialized with."
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def videos limit=nil
|
34
|
-
|
35
|
-
case
|
36
|
-
when limit.nil?
|
37
|
-
get_videos unless @videos
|
38
|
-
when limit
|
39
|
-
if limit == @limit
|
40
|
-
get_videos(limit) unless @videos
|
41
|
-
else
|
42
|
-
get_videos(limit)
|
43
|
-
@limit = limit
|
44
|
-
end
|
45
|
-
else
|
46
|
-
puts "Your case has gone badly wrong"
|
47
|
-
end
|
48
|
-
@videos
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def get_videos number=nil
|
54
|
-
@client ||= GData::Client::YouTube.new
|
55
|
-
feed = @client.get(self.url).to_xml
|
56
|
-
@videos = []
|
57
|
-
counter = 1
|
58
|
-
if number
|
59
|
-
feed.elements.each('entry') do |entry|
|
60
|
-
if counter <= number
|
61
|
-
@videos<< Video.new(entry)
|
62
|
-
counter += 1
|
63
|
-
end
|
64
|
-
end
|
65
|
-
else
|
66
|
-
feed.elements.each('entry') do |entry|
|
67
|
-
@videos<< Video.new(entry)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
|
75
|
-
class Video
|
76
|
-
attr_reader :url, :title, :description, :id, :thumbnail, :uploader, :duration
|
77
|
-
|
78
|
-
def initialize entry
|
79
|
-
if entry.class == REXML::Element
|
80
|
-
@xml = entry
|
81
|
-
@xml.elements.each('media:group') do |element|
|
82
|
-
@title = element.get_text('media:title')
|
83
|
-
@id = element.get_text('yt:videoid')
|
84
|
-
@description = element.get_text('media:description')
|
85
|
-
@uploader = element.get_text('media:credit')
|
86
|
-
element.elements.each('media:player'){|mp| @url = mp.attribute('url').to_s.gsub('&feature=youtube_gdata_player', '')}
|
87
|
-
element.elements.each('yt:duration'){|a| @duration = a.attribute('seconds').to_s }
|
88
|
-
element.elements.each('media:thumbnail') do |mt|
|
89
|
-
case mt.attribute('yt:name').to_s
|
90
|
-
when 'hqdefault'
|
91
|
-
@large_thumbnail = mt.attribute('url').to_s
|
92
|
-
when 'default'
|
93
|
-
@small_thumbnail = mt.attribute('url').to_s
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
else
|
98
|
-
raise "What was passed into Playlist class was not an REXML object"
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
extend ActiveModel::Naming
|
103
|
-
|
104
|
-
def name
|
105
|
-
"Video"
|
106
|
-
end
|
107
|
-
|
108
|
-
|
109
|
-
def thumbnail size=:small
|
110
|
-
if size == :large
|
111
|
-
@large_thumbnail
|
112
|
-
else
|
113
|
-
@small_thumbnail
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
|
118
|
-
end
|
119
|
-
|
120
|
-
|
121
|
-
end
|