My goal: I am trying to allow users to embed a link to a Youtube video in my site, while giving me control over the player\'s settings.
I would like to do this by only a
Let's say you have an Article model with a field (string) called embed :
YouTube examples to handle:
https://www.youtube.com/watch?v=u75Zsl1ECPQ&list=PLu9lbDbw-S8zyBwu9_aA2nE-3QocgyzRE&index=4
https://www.youtube.com/watch?v=u75Zsl1ECPQ
https://youtu.be/u75Zsl1ECPQ
https://youtu.be/u75Zsl1ECPQ?t=12
etc..
In the model (note.. I'm not applying width and height in the iframe output, because I'll handle it globally in a stylesheet. Also, you can remove that regex and uncomment self.embed.include? .. to achieve the same validation):
def iframe
if self.embed.present?
### YouTube
## Browser link --- use array to handle most playlist links, etc
if self.embed =~ /^(https?:\/\/)?(www\.)?youtube.com\/watch\?v=/ # self.embed.include? 'https://www.youtube.com/watch?v='
"<iframe src='https://www.youtube.com/embed/#{self.embed[32..42]}' frameborder='0' allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' allowfullscreen></iframe>"
## YouTube share link --- using array, because .split('https://youtu.be/').last wouldn't handle start at option ()?t=12)
elsif self.embed =~ /^(https?:\/\/)?(www\.)?youtu.be\// # self.embed.include? 'https://youtu.be/'
"<iframe src='https://www.youtube.com/embed/#{self.embed[17..27]}' frameborder='0' allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' allowfullscreen></iframe>"
### Validate + Generate iframe for whatever other embeds you want to allow (Google Maps, Vimeo, etc)
# elsif
else
self.embed = nil
end
end
end
In the articles#show view (note.. bootstrap classes for handling responsiveness):
<% if @article.embed.present? # no markup if nil %>
<div class="embed-responsive embed-responsive-16by9">
<%= @article.iframe.html_safe %>
</div><!-- .embed-responsive -->
<% end %>
If you want to grab the thumbnail for the embed, this method works the same way:
def thumb
if self.embed.present?
### YouTube
## Each YouTube video has 4 generated images [ /0 .. /3 ]
if self.embed =~ /^(https?:\/\/)?(www\.)?youtube.com\/watch\?v=/
"<img alt='Media' class='card-img-top' src='http://img.youtube.com/vi/#{self.embed[32..42]}/0.jpg' />"
elsif self.embed =~ /^(https?:\/\/)?(www\.)?youtu.be\//
"<img alt='Media' class='card-img-top' src='http://img.youtube.com/vi/#{self.embed[17..27]}/0.jpg' />"
else
self.embed = nil
end
end
end
So, in the articles#index view, you could call on the thumb method:
<% if article.embed.present? %>
<%= link_to article.thumb.html_safe, article_path(article) %>
<% end # consider else.. fallback image ..end %>
Working Example: https://rails-react-bootstrap.herokuapp.com/articles/45
I had to incorporate this functionality in one of my recent projects. I had to support linking both YouTube and Vimeo videos. I am using the 'uri' module of Ruby and the HTTParty. Basically I came with the following:
class LinkVideo < ActiveRecord::Base
require 'uri'
include HTTParty
cattr_reader :per_page
@@per_page = 12
belongs_to :user
validates :weblink, :presence => true, :domain => true
def embed(width = "640", height = "390")
embed_code = nil
case base_uri
when "www.youtube.com"
embed_code = "<object width='#{width}' height='#{height}'>" +
"<param name='movie' value='#{url}'></param>" +
"<param name='allowFullScreen' value='false'></param>" +
"<param name='allowscriptaccess' value='always'></param>" +
"<embed src='#{url}' type='application/x-shockwave-flash' allowscriptaccess='always' allowfullscreen='false'
width='#{width}' height='#{height}'> </embed>" +
"</object>"
when "www.vimeo.com"
embed_code = "<iframe src='#{url}' width='#{width}' height='#{height}' frameborder='0'></iframe>"
end
embed_code
end
def url
url = nil
case base_uri
when "www.youtube.com"
url = "http://www.youtube.com/v/" + video_id + "&hl=en_US&fs=1"
when "www.vimeo.com"
url = "http://player.vimeo.com/video/" + video_id
end
url
end
def thumbnail
url = nil
case base_uri
when "www.youtube.com"
url = "http://img.youtube.com/vi/" + video_id + "/2.jpg"
when "www.vimeo.com"
url = thumbnail_path( image_base_uri, video_id )
end
url
end
# Video Paths:
# http://www.youtube.com/watch?v=Gqraan6sBjk
# http://www.vimeo.com/21618919
# Thumbnail Paths:
# http://img.youtube.com/vi/Gqraan6sBjk/2.jpg
private
def image_base_uri
image_base_uri = nil
case base_uri
when "www.youtube.com"
image_base_uri = "http://img.youtube.com/vi/"
when "www.vimeo.com"
image_base_uri = "http://vimeo.com/api/v2/video/"
end
image_base_uri
end
def thumbnail_path(base_uri, videoid = nil, format = 'xml')
path = nil
return path if base_uri.nil?
xml = HTTParty.get( base_uri + ( videoid.nil? ? video_id : videoid ) + format.insert(0, '.') )
values = xml.parsed_response.values_at("videos").first.fetch('video')
if values["user_portrait_medium"].include?('100')
path = values["user_portrait_medium"]
else values["user_portrait_large"].include?('100')
path = values["user_portrait_large"]
end
path
end
def base_uri
@uri ||= parse_it
@uri.host
end
def video_id
video_id = nil
case base_uri
when "www.youtube.com"
video_id = @uri.query.split('=')[1].slice(0, 11)
when "www.vimeo.com"
video_id = @uri.path.delete('/')
end
video_id
end
def parse_it
@uri = URI.parse( weblink )
end
end
I used the highest rated answer about with the function youtube_embed but when I implemented in my view I was seeing the iframe code appear in my page, but no video. I added raw before the function call and all is good with the page now.
Inside my view.html.erb
<p><%= raw(youtube_embed(@experiment.researchsection.videolink)) %></p>
You might prefer to roll your own solution, but it's worth considering the Embedly API. http://embed.ly/