concerto_remote_video 0.0.3 → 0.0.4
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/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
|