videostore 0.0.1
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.
- checksums.yaml +7 -0
- data/README.md +32 -0
- data/lib/videostore.rb +186 -0
- data/rakefile +5 -0
- data/spec/videostore_spec.rb +58 -0
- metadata +48 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 09b1398177f07a17cf92e64abc1e80d340ec18e3
|
4
|
+
data.tar.gz: 646de11ca15ee3cdd1f45296e13b42135029de2a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 73f157b799290715c47b24a178f0b13dc0f2307f832e1ec6218e6140e8bea54e6dac9e613a2f5d6693828a5f672eda1179ab31909695091b0aa89a4afc6de9c8
|
7
|
+
data.tar.gz: 42afaca160aef9172b55bc39a3b7d100400f5017b3926fa76add8bffdbaf4d9c2959125c34ef5d52140bf4c735af42d367fa666eb9dec16cd43008a36f96e934
|
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
videostore
|
2
|
+
==========
|
3
|
+
|
4
|
+
A gem for storing information about videos on remote streaming sites
|
5
|
+
|
6
|
+
Features:
|
7
|
+
- Currenty supports Youtube and Vimeo
|
8
|
+
- Methods for checking if they're still online
|
9
|
+
- Methods for bringing down up-to-date data from API #
|
10
|
+
- Various sorting options made possible through duck typing
|
11
|
+
|
12
|
+
To start using the gem have a file to the lib directory called keys.rb that defines
|
13
|
+
YOUTUBE_DEVELOPER_KEY as your google developer key with access to the V3 Youtube API.
|
14
|
+
|
15
|
+
Instantiate a new Youtube video with
|
16
|
+
> VideoStore::Youtube.new(<insert youtube ID here>)
|
17
|
+
|
18
|
+
Do the same with Vimeo, but replace Youtube with Vimeo!!
|
19
|
+
|
20
|
+
Both classes respond to:
|
21
|
+
present? -- Returns true if the video
|
22
|
+
video_id -- ID
|
23
|
+
uri -- URI for the video
|
24
|
+
title -- The Title
|
25
|
+
thumbnail_uri -- URI for the thumbnail
|
26
|
+
channel_name -- Name of the poster of the video
|
27
|
+
views -- # of views
|
28
|
+
likes -- # of likes
|
29
|
+
comment_count -- # of comments
|
30
|
+
duration -- length of the video in seconds
|
31
|
+
|
32
|
+
This duck typing allows you to sort both kinds of videos in the same collection.
|
data/lib/videostore.rb
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'google/api_client'
|
3
|
+
require 'vimeo'
|
4
|
+
begin
|
5
|
+
load 'keys.rb' ## store your youtube API key here as the constant YOUTUBE_DEVELOPER_KEY
|
6
|
+
rescue LoadError
|
7
|
+
raise "To start using the gem have a file to the lib directory called keys.rb " <<
|
8
|
+
"that defines YOUTUBE_DEVELOPER_KEY as your google developer key (must have access to the V3 Youtube API)."
|
9
|
+
end
|
10
|
+
|
11
|
+
module VideoStore
|
12
|
+
class Video
|
13
|
+
attr_accessor :video_id
|
14
|
+
attr_reader :title, :thumbnail_uri, :channel_name, :views,
|
15
|
+
:likes, :comment_count, :duration
|
16
|
+
ATTRIBUTES = :video_id, :title, :thumbnail_uri, :channel_name, :views,
|
17
|
+
:likes, :comment_count, :duration
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
raise NoMethodError
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Youtube < Video
|
25
|
+
DEVELOPER_KEY = ::YOUTUBE_DEVELOPER_KEY
|
26
|
+
YOUTUBE_API_SERVICE_NAME = "youtube"
|
27
|
+
YOUTUBE_API_VERSION = "v3"
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def establish_connection
|
31
|
+
@client = Google::APIClient.new(key: DEVELOPER_KEY,
|
32
|
+
application_name: YOUTUBE_API_SERVICE_NAME,
|
33
|
+
application_version: YOUTUBE_API_VERSION,
|
34
|
+
authorization: nil)
|
35
|
+
@connection = @client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)
|
36
|
+
end
|
37
|
+
def connection
|
38
|
+
@connection
|
39
|
+
end
|
40
|
+
def client
|
41
|
+
@client
|
42
|
+
end
|
43
|
+
end # end of class methods
|
44
|
+
establish_connection
|
45
|
+
|
46
|
+
def initialize(video_id)
|
47
|
+
@video_id = video_id
|
48
|
+
@response_hash = Hash.new
|
49
|
+
populate_attributes
|
50
|
+
end
|
51
|
+
|
52
|
+
def connection
|
53
|
+
self.class.connection
|
54
|
+
end
|
55
|
+
def client
|
56
|
+
self.class.client
|
57
|
+
end
|
58
|
+
|
59
|
+
def present?(options = {})
|
60
|
+
JSON.parse(fetch_data('id').response.body)["pageInfo"]["totalResults"] == 1
|
61
|
+
end
|
62
|
+
|
63
|
+
def populate_attributes(options = {})
|
64
|
+
if present?
|
65
|
+
content_details = JSON.parse(fetch_data('contentDetails').response.body)['items'].first['contentDetails']
|
66
|
+
@duration = content_details["duration"].youtube_duration_to_seconds
|
67
|
+
|
68
|
+
statistics = JSON.parse(fetch_data('statistics').response.body)['items'].first['statistics']
|
69
|
+
@views = statistics["viewCount"].to_i
|
70
|
+
@likes = statistics["likeCount"].to_i
|
71
|
+
@comment_count = statistics["commentCount"].to_i
|
72
|
+
|
73
|
+
snippet = JSON.parse(fetch_data('snippet').response.body)['items'].first['snippet']
|
74
|
+
@title = snippet["title"]
|
75
|
+
@thumbnail_uri = snippet["thumbnails"]["default"]["url"]
|
76
|
+
@channel_name = snippet["channelTitle"]
|
77
|
+
end
|
78
|
+
info
|
79
|
+
end
|
80
|
+
|
81
|
+
def uri
|
82
|
+
"http://www.youtube.com/watch?v=#{@video_id}" if present?
|
83
|
+
end
|
84
|
+
|
85
|
+
def info
|
86
|
+
response = {}
|
87
|
+
if present?
|
88
|
+
ATTRIBUTES.each do |attribute|
|
89
|
+
response.merge!({attribute => send(attribute)})
|
90
|
+
end
|
91
|
+
else
|
92
|
+
response.merge!({:video_id => @video_id})
|
93
|
+
response.merge!({:video_not_found => 'video_not_found'})
|
94
|
+
end
|
95
|
+
response
|
96
|
+
end
|
97
|
+
|
98
|
+
def youtube? ; true ; end
|
99
|
+
def vimeo? ; false ; end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def fetch_data(part, options = {})
|
104
|
+
if options[:use_cache] && @response_hash[part]
|
105
|
+
@response_hash[part]
|
106
|
+
else
|
107
|
+
@response_hash[part] = client.execute!(
|
108
|
+
:api_method => connection.videos.list,
|
109
|
+
:parameters => {
|
110
|
+
:id => @video_id,
|
111
|
+
:part => part,
|
112
|
+
}
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end # end of Youtube class
|
118
|
+
|
119
|
+
class Vimeo < Video
|
120
|
+
def initialize(video_id)
|
121
|
+
@video_id = video_id
|
122
|
+
populate_attributes
|
123
|
+
end
|
124
|
+
|
125
|
+
def present?
|
126
|
+
::Vimeo::Simple::Video.info(@video_id
|
127
|
+
).parsed_response.class == Array
|
128
|
+
end
|
129
|
+
|
130
|
+
def uri
|
131
|
+
"http:://vimeo.com/#{@video_id}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def populate_attributes
|
135
|
+
if present?
|
136
|
+
fetch_data
|
137
|
+
|
138
|
+
@title = @response['title']
|
139
|
+
@thumbnail_uri = @response['thumbnail_large']
|
140
|
+
@channel_name = @response['user_name']
|
141
|
+
@views = @response['stats_number_of_plays']
|
142
|
+
@likes = @response['stats_number_of_likes']
|
143
|
+
@comment_count = @response['stats_number_of_comments']
|
144
|
+
@duration = @response['duration']
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def info
|
149
|
+
response = {}
|
150
|
+
if present?
|
151
|
+
ATTRIBUTES.each do |attribute|
|
152
|
+
response.merge!({attribute => send(attribute)})
|
153
|
+
end
|
154
|
+
else
|
155
|
+
response.merge!({:video_id => @video_id})
|
156
|
+
response.merge!({:video_not_found => 'video_not_found'})
|
157
|
+
end
|
158
|
+
response
|
159
|
+
end
|
160
|
+
|
161
|
+
def youtube? ; false ; end
|
162
|
+
def vimeo? ; true ; end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
def fetch_data
|
167
|
+
@response = JSON.parse(
|
168
|
+
::Vimeo::Simple::Video.info(@video_id).response.body
|
169
|
+
).first
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
class String
|
175
|
+
def youtube_duration_to_seconds
|
176
|
+
hours = match(/(\d+)H/)
|
177
|
+
minutes = match(/(\d+)M/)
|
178
|
+
seconds = match(/(\d+)S/)
|
179
|
+
|
180
|
+
hours = hours ? hours[1].to_i : 0
|
181
|
+
minutes = minutes ? minutes[1].to_i : 0
|
182
|
+
seconds = seconds ? seconds[1].to_i : 0
|
183
|
+
|
184
|
+
(hours * 3600) + (minutes * 60) + seconds
|
185
|
+
end
|
186
|
+
end
|
data/rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../lib/videostore"
|
2
|
+
|
3
|
+
describe VideoStore::Youtube do
|
4
|
+
before :each do
|
5
|
+
@youtube = VideoStore::Youtube.new('vWeaOG6KzqE')
|
6
|
+
@invalid_youtube = VideoStore::Youtube.new('imnotavalididlol')
|
7
|
+
@vimeo = VideoStore::Vimeo.new(39605750)
|
8
|
+
@invalid_vimeo = VideoStore::Vimeo.new(5)
|
9
|
+
end
|
10
|
+
context 'youtube' do
|
11
|
+
it "can tell when a video is and isn't there, and what it is" do
|
12
|
+
@youtube.present?.should == true
|
13
|
+
@invalid_youtube.present?.should == false
|
14
|
+
@youtube.youtube?.should == true
|
15
|
+
@youtube.vimeo?.should == false
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can pull down information" do
|
19
|
+
@youtube.video_id.should == "vWeaOG6KzqE"
|
20
|
+
@youtube.title.should == "Madeon | The incomplete mix | Not All tracks | Adio"
|
21
|
+
@youtube.thumbnail_uri.should == "https://i1.ytimg.com/vi/vWeaOG6KzqE/default.jpg"
|
22
|
+
@youtube.channel_name.should == "Adio Music"
|
23
|
+
@youtube.duration.should == 3306
|
24
|
+
@youtube.views.should > 350223
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'vimeo' do
|
29
|
+
it "can tell when a video is and isn't there" do
|
30
|
+
@vimeo.present?.should == true
|
31
|
+
@invalid_vimeo.present?.should == false
|
32
|
+
@vimeo.vimeo?.should == true
|
33
|
+
@vimeo.youtube?.should == false
|
34
|
+
end
|
35
|
+
|
36
|
+
it "can pull down information" do
|
37
|
+
@vimeo.video_id.should == 39605750
|
38
|
+
@vimeo.title.should == "woot woot"
|
39
|
+
@vimeo.thumbnail_uri.should == "http://b.vimeocdn.com/ts/273/226/273226915_640.jpg"
|
40
|
+
@vimeo.channel_name.should == "Cole Ruffing"
|
41
|
+
@vimeo.duration.should == 243
|
42
|
+
@vimeo.views.should > 1356
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'collection' do
|
47
|
+
it 'can sort collections' do
|
48
|
+
@sort_by_title = [@vimeo, @youtube].sort_by! {|x| x.title }
|
49
|
+
@sort_by_title[0].youtube?.should == true
|
50
|
+
|
51
|
+
@sort_by_channel_name = [@vimeo, @youtube].sort_by! {|x| x.channel_name }
|
52
|
+
@sort_by_channel_name[0].youtube?.should == true
|
53
|
+
|
54
|
+
@sort_by_duration = [@vimeo, @youtube].sort_by! {|x| x.views }
|
55
|
+
@sort_by_duration[0].vimeo?.should == true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: videostore
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Husa
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-12-01 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: The videostore gem is a utility for storing and tracking remote videos
|
14
|
+
at streaming sites such as Vimeo and Youtube.
|
15
|
+
email: davidhusa@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/videostore.rb
|
21
|
+
- spec/videostore_spec.rb
|
22
|
+
- rakefile
|
23
|
+
- README.md
|
24
|
+
homepage: http://davidhusa.com
|
25
|
+
licenses:
|
26
|
+
- MIT
|
27
|
+
metadata: {}
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - '>='
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubyforge_project:
|
44
|
+
rubygems_version: 2.0.7
|
45
|
+
signing_key:
|
46
|
+
specification_version: 4
|
47
|
+
summary: Utility for storing/tracking remote videos
|
48
|
+
test_files: []
|