concerto_remote_video 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -0
- data/app/assets/javascripts/remote_video.js +80 -0
- data/app/assets/stylesheets/remote_video.css +16 -0
- data/app/models/remote_video.rb +91 -32
- data/app/views/contents/remote_video/_form_middle.html.erb +4 -5
- data/app/views/contents/remote_video/_form_top.html.erb +26 -2
- data/app/views/contents/remote_video/_render_tile.html.erb +1 -1
- data/lib/concerto_remote_video/version.rb +1 -1
- data/lib/generators/concerto_remote_video/install_generator.rb +8 -0
- metadata +10 -7
data/README.md
CHANGED
@@ -5,7 +5,10 @@ This plugin provides support to play remotely hosted videos, like YouTube videos
|
|
5
5
|
2. ```bundle install```
|
6
6
|
3. ```./script/rails generate concerto_remote_video:install install```
|
7
7
|
|
8
|
+
The last step produces a lot of output, if it runs successfully, because it recompiles the frontend js files.
|
9
|
+
|
8
10
|
## Supported hosts:
|
9
11
|
* YouTube
|
12
|
+
* Vimeo
|
10
13
|
|
11
14
|
Concerto 2 Remove Video is licensed under the Apache License, Version 2.0.
|
@@ -0,0 +1,80 @@
|
|
1
|
+
// contents.js
|
2
|
+
|
3
|
+
// attach handler to video_id so when it loses focus we can look up some video details
|
4
|
+
// not dry, but no middle man
|
5
|
+
function attachHandlers() {
|
6
|
+
$('input#remote_video_config_video_id').on('blur', getVideoInfo);
|
7
|
+
$('select#remote_video_config_video_vendor').on('change', getVideoInfo);
|
8
|
+
|
9
|
+
$('select#remote_video_config_video_vendor').on('change', updateTooltip);
|
10
|
+
|
11
|
+
function updateTooltip() {
|
12
|
+
var vendor = $('select#remote_video_config_video_vendor').val();
|
13
|
+
if (vendor == 'YouTube') {
|
14
|
+
$('input#remote_video_config_video_id').attr("placeholder", "DGbqvYbPZBY");
|
15
|
+
$('div#video_hint_id').html('Specify the video id or keywords');
|
16
|
+
} else if (vendor == 'Vimeo') {
|
17
|
+
$('input#remote_video_config_video_id').attr("placeholder", "4224811");
|
18
|
+
$('div#video_hint_id').html('Specify the exact vimeo video id');
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
function getVideoInfo() {
|
23
|
+
// need to know which vendor
|
24
|
+
// will place title, description, duration into 'div.remote-video-info'
|
25
|
+
|
26
|
+
var info = '<p>Video details could not be determined.</p>';
|
27
|
+
var vendor = $('select#remote_video_config_video_vendor').val();
|
28
|
+
var video_id = $('input#remote_video_config_video_id').val();
|
29
|
+
var info_el = $('.remote-video-info');
|
30
|
+
|
31
|
+
if (info_el.length != 0) {
|
32
|
+
// we found the summary box
|
33
|
+
if (typeof vendor != 'undefined') {
|
34
|
+
// we found the vendor selection, call appropriate api
|
35
|
+
if (vendor == 'YouTube') {
|
36
|
+
$(info_el).empty().html('searching...');
|
37
|
+
// todo: dont search if video_id is empty
|
38
|
+
$.ajax({
|
39
|
+
url: 'http://gdata.youtube.com/feeds/api/videos?q='+ encodeURIComponent(video_id) +'&v=2&max-results=1&format=5&alt=jsonc',
|
40
|
+
dataType: 'jsonp',
|
41
|
+
timeout: 4000,
|
42
|
+
success: function (data) {
|
43
|
+
if (parseInt(data['data']['totalItems']) > 0) {
|
44
|
+
// we got something, repoint data to first item in results
|
45
|
+
data = data['data']['items'];
|
46
|
+
$(info_el).empty().html('<img src="' + data[0].thumbnail.hqDefault + '"/><h4>' + data[0].title + '</h4><i>' + data[0].duration + ' secs</i><br/><p>' + data[0].description + '</p>');
|
47
|
+
} else {
|
48
|
+
$(info_el).empty().html(info);
|
49
|
+
}
|
50
|
+
},
|
51
|
+
error: function (xoptions, textStatus) {
|
52
|
+
$(info_el).empty().html(info);
|
53
|
+
}
|
54
|
+
});
|
55
|
+
} else if (vendor == 'Vimeo') {
|
56
|
+
$(info_el).empty().html('searching...');
|
57
|
+
$.ajax({
|
58
|
+
url: 'http://vimeo.com/api/v2/video/' + encodeURIComponent(video_id) + '.json',
|
59
|
+
dataType: 'jsonp',
|
60
|
+
timeout: 4000,
|
61
|
+
success: function (data) {
|
62
|
+
if (data.length > 0) {
|
63
|
+
// we got something
|
64
|
+
$(info_el).empty().html('<img src="' + data[0].thumbnail_small + '"/><h4>' + data[0].title + '</h4><i>' + data[0].duration + ' secs</i><br/><p>' + data[0].description + '</p>');
|
65
|
+
} else {
|
66
|
+
$(info_el).empty().html(info);
|
67
|
+
}
|
68
|
+
},
|
69
|
+
error: function (xoptions, textStatus) {
|
70
|
+
$(info_el).empty().html(info);
|
71
|
+
}
|
72
|
+
});
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
$(document).ready(attachHandlers);
|
80
|
+
$(document).on('page:change', attachHandlers);
|
data/app/models/remote_video.rb
CHANGED
@@ -5,9 +5,15 @@ class RemoteVideo < Content
|
|
5
5
|
before_validation :save_config
|
6
6
|
|
7
7
|
validate :video_id_must_exist
|
8
|
-
|
8
|
+
#todo: put back, commented out because I keep getting duration is not a number
|
9
|
+
#validates :duration, :numericality => { :greater_than => 0 }
|
10
|
+
validate :video_vendor_supported
|
9
11
|
|
10
|
-
DISPLAY_NAME = '
|
12
|
+
DISPLAY_NAME = 'Video'
|
13
|
+
VIDEO_VENDORS = {
|
14
|
+
:YouTube => { :id => "YouTube", :url => "https://www.youtube.com/embed/" },
|
15
|
+
:Vimeo => { :id => "Vimeo", :url => "https://player.vimeo.com/video/" }
|
16
|
+
}
|
11
17
|
|
12
18
|
attr_accessor :config
|
13
19
|
|
@@ -41,37 +47,74 @@ class RemoteVideo < Content
|
|
41
47
|
|
42
48
|
def self.form_attributes
|
43
49
|
attributes = super()
|
44
|
-
|
50
|
+
# what about :thumb_url, :title, :description
|
51
|
+
attributes.concat([:config => [:video_vendor, :video_id, :allow_flash]])
|
45
52
|
end
|
46
53
|
|
47
54
|
# Load some info about this video from YouTube.
|
48
55
|
def load_info
|
49
|
-
|
56
|
+
# dont abort if there is a duration specified
|
57
|
+
return if self.config['video_id'].nil? #|| !self.duration.nil?
|
50
58
|
require 'net/http'
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
if self.config['video_vendor'] == VIDEO_VENDORS[:YouTube][:id]
|
60
|
+
#begin
|
61
|
+
video_id = URI.escape(self.config['video_id'])
|
62
|
+
url = "http://gdata.youtube.com/feeds/api/videos?q=#{video_id}&v=2&max-results=1&format=5&alt=jsonc"
|
63
|
+
json = Net::HTTP.get_response(URI.parse(url)).body
|
64
|
+
data = ActiveSupport::JSON.decode(json)
|
65
|
+
#rescue
|
66
|
+
# Rails.logger.debug("YouTube not reachable @ #{url}.")
|
67
|
+
# config['video_id'] = ''
|
68
|
+
# return
|
69
|
+
#end
|
70
|
+
if data['data']['totalItems'].to_i <= 0
|
71
|
+
Rails.logger.debug('No video found from ' + url)
|
72
|
+
self.config['video_id'] = ''
|
73
|
+
return
|
74
|
+
end
|
75
|
+
video_data = data['data']['items'][0]
|
76
|
+
self.config['video_id'] = video_data['id']
|
77
|
+
self.duration = video_data['duration'].to_i
|
78
|
+
self.config['thumb_url'] = video_data['thumbnail']['hqDefault']
|
79
|
+
self.config['title'] = video_data['title']
|
80
|
+
self.config['description'] = video_data['description']
|
81
|
+
elsif self.config['video_vendor'] == VIDEO_VENDORS[:Vimeo][:id]
|
82
|
+
#todo: put these info urls in the VV constant
|
83
|
+
#http://vimeo.com/api/v2/video/video_id.json
|
84
|
+
data=[]
|
85
|
+
#begin
|
86
|
+
video_id = URI.escape(self.config['video_id'])
|
87
|
+
url = "http://vimeo.com/api/v2/video/#{video_id}.json"
|
88
|
+
uri = URI.parse(url)
|
89
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
90
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
91
|
+
response = http.request(request)
|
92
|
+
if response.code == '200' #ok
|
93
|
+
json = response.body
|
94
|
+
data = ActiveSupport::JSON.decode(json)
|
95
|
+
end
|
96
|
+
#rescue
|
97
|
+
# Rails.logger.debug("YouTube not reachable @ #{url}.")
|
98
|
+
# config['video_id'] = ''
|
99
|
+
# return
|
100
|
+
#end
|
101
|
+
if data.empty?
|
102
|
+
Rails.logger.debug('No video found from ' + url)
|
103
|
+
self.config['video_id'] = ''
|
104
|
+
return
|
105
|
+
end
|
106
|
+
video_data = data[0]
|
107
|
+
# some vimeo videos have zero for their duration, so in that case use what the user supplied
|
108
|
+
self.duration = (video_data['duration'].to_i > 0 ? video_data['duration'].to_i : self.duration.to_i)
|
109
|
+
self.config['thumb_url'] = video_data['thumbnail_small']
|
110
|
+
self.config['title'] = video_data['title']
|
111
|
+
self.config['description'] = video_data['description']
|
65
112
|
end
|
66
|
-
video_data = data['data']['items'][0]
|
67
|
-
self.config['video_id'] = video_data['id']
|
68
|
-
self.duration = video_data['duration'].to_i
|
69
|
-
self.config['thumb_url'] = video_data['thumbnail']['hqDefault']
|
70
113
|
end
|
71
114
|
|
72
115
|
# Build a URL for an iframe player.
|
73
116
|
def player_url(params={})
|
74
|
-
url =
|
117
|
+
url = VIDEO_VENDORS[self.config['video_vendor'].to_sym][:url] + self.config['video_id']
|
75
118
|
if self.config['allow_flash'] == '0'
|
76
119
|
params['html5'] = 1
|
77
120
|
end
|
@@ -85,16 +128,32 @@ class RemoteVideo < Content
|
|
85
128
|
end
|
86
129
|
end
|
87
130
|
|
131
|
+
def video_vendor_supported
|
132
|
+
if config['video_vendor'].empty? || !VIDEO_VENDORS.collect { |a,b| b[:id] }.include?(config['video_vendor'])
|
133
|
+
errors.add(:video_vendor, 'must be ' + VIDEO_VENDORS.collect { |a,b| b[:id] }.join(" or "))
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
88
137
|
def render_details
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
138
|
+
if self.config['video_vendor'] == VIDEO_VENDORS[:YouTube][:id]
|
139
|
+
settings = {
|
140
|
+
:autoplay => 1, # Autostart the video
|
141
|
+
:end => self.duration, # Stop it around the duration
|
142
|
+
:controls => 0, # Don't show any controls
|
143
|
+
:modestbranding => 1, # Use the less fancy branding
|
144
|
+
:rel => 0, # Don't show related videos
|
145
|
+
:showinfo => 0, # Don't show the video info
|
146
|
+
:iv_load_policy => 3 # Don't show any of those in-video labels
|
147
|
+
}
|
148
|
+
elsif self.config['video_vendor'] == VIDEO_VENDORS[:Vimeo][:id]
|
149
|
+
settings = {
|
150
|
+
:api => 1, # use Javascript API
|
151
|
+
:player_id => 'playerv', #arbitrary id of iframe
|
152
|
+
:byline => 0,
|
153
|
+
:portrait => 0,
|
154
|
+
:autoplay => 1
|
155
|
+
}
|
156
|
+
end
|
98
157
|
{:path => player_url(settings)}
|
99
158
|
end
|
100
159
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
<fieldset>
|
2
|
-
<legend><span><%=t(
|
2
|
+
<legend><span><%=t('contents.provide_details')%></span></legend>
|
3
3
|
<div class="clearfix">
|
4
4
|
<%= form.label :name %>
|
5
5
|
<div class="input">
|
6
|
-
<%= form.text_field :name %>
|
6
|
+
<%= form.text_field :name, :class => "input-xlarge" %>
|
7
7
|
</div>
|
8
8
|
</div>
|
9
9
|
|
@@ -11,9 +11,8 @@
|
|
11
11
|
</fieldset>
|
12
12
|
|
13
13
|
<fieldset>
|
14
|
-
<legend><span><%=t(
|
15
|
-
<
|
16
|
-
<div class="input">
|
14
|
+
<legend><span><%=t('contents.select_feed')%></span></legend>
|
15
|
+
<div class="clearfix">
|
17
16
|
<% if @content.new_record? %>
|
18
17
|
<%= render :partial => 'contents/form_elements/feeds' %>
|
19
18
|
<% end %>
|
@@ -1,10 +1,22 @@
|
|
1
|
+
<%= javascript_include_tag "remote_video" %>
|
2
|
+
<%= stylesheet_link_tag "remote_video" %>
|
3
|
+
|
1
4
|
<fieldset>
|
2
|
-
<legend><span
|
5
|
+
<legend><span><%= RemoteVideo::DISPLAY_NAME %></span></legend>
|
6
|
+
<div class="row-fluid">
|
3
7
|
<%= form.fields_for :config do |config| %>
|
8
|
+
<div class='span4'>
|
9
|
+
<div class="clearfix">
|
10
|
+
<%= config.label :video_vendor, 'Video Vendor' %>
|
11
|
+
<div class="input">
|
12
|
+
<%= config.select :video_vendor, RemoteVideo::VIDEO_VENDORS.collect { |a,b| b[:id] } %>
|
13
|
+
</div>
|
14
|
+
</div>
|
4
15
|
<div class="clearfix">
|
5
16
|
<%= config.label :video_id %>
|
6
17
|
<div class="input">
|
7
|
-
<%= config.text_field :video_id, :placeholder =>
|
18
|
+
<%= config.text_field :video_id, :placeholder => "DGbqvYbPZBY", :class => "input-small" %>
|
19
|
+
<div id="video_id_hint">Specify the video id or keywords</div>
|
8
20
|
</div>
|
9
21
|
</div>
|
10
22
|
<div class="clearfix">
|
@@ -13,5 +25,17 @@
|
|
13
25
|
<%= config.select :allow_flash, [["No", 0], ["Yes", 1]] %>
|
14
26
|
</div>
|
15
27
|
</div>
|
28
|
+
<div class="clearfix">
|
29
|
+
<%= form.label :duration %>
|
30
|
+
<div class="input">
|
31
|
+
<%= form.number_field :duration, :class => "input-small" %><br/>
|
32
|
+
(automatically set if ascertained from video source)
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
</div>
|
36
|
+
<div>
|
37
|
+
<div class='remote-video-info'></div>
|
38
|
+
</div>
|
16
39
|
<% end %>
|
40
|
+
</div>
|
17
41
|
</fieldset>
|
@@ -1 +1 @@
|
|
1
|
-
<div style="background-image:url(<%= content.config['thumb_url'] %>); background-size: cover; width: 100%; height: 100%;"></div>
|
1
|
+
<div class="pop" style="background-image:url(<%= content.config['thumb_url'] %>); background-size: cover; width: 100%; height: 100%;" data-content="<%= content.config['description']%>" data-title="<%= content.config['title']%>"></div>
|
@@ -9,6 +9,7 @@ module ConcertoRemoteVideo
|
|
9
9
|
def install
|
10
10
|
copy_js
|
11
11
|
register
|
12
|
+
recompile
|
12
13
|
end
|
13
14
|
|
14
15
|
private
|
@@ -19,5 +20,12 @@ module ConcertoRemoteVideo
|
|
19
20
|
def register
|
20
21
|
append_file 'public/frontend_js/content_types.js', "goog.require('concerto.frontend.Content.RemoteVideo');\n"
|
21
22
|
end
|
23
|
+
|
24
|
+
def recompile
|
25
|
+
inside 'public/frontend_js' do
|
26
|
+
run('/bin/bash compile.sh', {:verbose => true})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
22
30
|
end
|
23
31
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concerto_remote_video
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-30 00:00:00.000000000 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
17
|
-
requirement: &
|
17
|
+
requirement: &70296757751560 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '3.2'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70296757751560
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: sqlite3
|
28
|
-
requirement: &
|
28
|
+
requirement: &70296757727300 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,15 +33,18 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
37
|
-
description: Adds support for remotely hosted videos, like YouTube, in Concerto
|
36
|
+
version_requirements: *70296757727300
|
37
|
+
description: Adds support for remotely hosted videos, like YouTube or vimeo, in Concerto
|
38
|
+
2
|
38
39
|
email:
|
39
40
|
- bmichalski@gmail.com
|
40
41
|
executables: []
|
41
42
|
extensions: []
|
42
43
|
extra_rdoc_files: []
|
43
44
|
files:
|
45
|
+
- app/assets/javascripts/remote_video.js
|
44
46
|
- app/assets/stylesheets/concerto_remote_video/application.css
|
47
|
+
- app/assets/stylesheets/remote_video.css
|
45
48
|
- app/controllers/concerto_remote_video/application_controller.rb
|
46
49
|
- app/helpers/concerto_remote_video/application_helper.rb
|
47
50
|
- app/models/remote_video.rb
|