开发者

Converting a regular Youtube 'link' into an embedded video

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 askin开发者_如何学Cg the user to supply the link (not the entire embed code), from where I can somehow paste that link into the embed code.

I've tried doing a simple substitution with a few Youtube links (http://youtu.be/...) but they don't work, saying 'movie not loaded'. Is there a dependable way to do this?


I do this quite often for clients, the gist of it is that you parse out the ID from the URL, then generate the iframe HTML using this.

def youtube_embed(youtube_url)
  if youtube_url[/youtu\.be\/([^\?]*)/]
    youtube_id = $1
  else
    # Regex from # http://stackoverflow.com/questions/3452546/javascript-regex-how-to-get-youtube-video-id-from-url/4811367#4811367
    youtube_url[/^.*((v\/)|(embed\/)|(watch\?))\??v?=?([^\&\?]*).*/]
    youtube_id = $5
  end

  %Q{<iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/#{ youtube_id }" frameborder="0" allowfullscreen></iframe>}
end

youtube_embed('youtu.be/jJrzIdDUfT4')
# => <iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/jJrzIdDUfT4" frameborder="0" allowfullscreen></iframe>

I put this in a helper. Change the height, width and options to taste.


Another answer is to use this gem which handles youtube and vimeo, and could be expanded to more. It also integrates well with AR so you can cache the resulting html instead of filtering on each render:

https://github.com/dejan/auto_html


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>


something like this (for ex. in model):

@@video_regexp = [ /^(?:https?:\/\/)?(?:www\.)?youtube\.com(?:\/v\/|\/watch\?v=)([A-Za-z0-9_-]{11})/, 
                   /^(?:https?:\/\/)?(?:www\.)?youtu\.be\/([A-Za-z0-9_-]{11})/,
                   /^(?:https?:\/\/)?(?:www\.)?youtube\.com\/user\/[^\/]+\/?#(?:[^\/]+\/){1,4}([A-Za-z0-9_-]{11})/
                   ]

def video_id
  @@video_regexp.each { |m| return m.match(source_url)[1] unless m.nil? }
end

where source_url is the full link to video. then a helper:

def youtube_video(video_id)
  render :partial => 'youtube_video', :locals => { :id => video_id }
end

and sample partial (haml):

%iframe{:allowfullscreen => "", :frameborder => "0", :height => "349",
        :src => "http://www.youtube.com/embed/#{id}", :width => "560"}

and in view as simple as:

= youtube_video Model.video_id


This is what youtube uses:

<iframe width="425" height="349" src="http://www.youtube.com/embed/zb-gmJVW5lw" frameborder="0" allowfullscreen></iframe>

Then just use a regexp to change the link from:

http://www.youtube.com/watch?v=zb-gmJVW5lw

into:

http://www.youtube.com/embed/zb-gmJVW5lw

Here's a proof of concept regexp for matching regular youtube links:

  • http://rubular.com/r/Fitt7PPJW1

And here's a proof of concept regexp for matching youtu.be links:

  • http://rubular.com/r/MTgd9nXzFA

Note that the embed url can also be loaded in the browser which opens a page where the video is fullscreen.


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 + "&amp;hl=en_US&amp;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


You might prefer to roll your own solution, but it's worth considering the Embedly API. http://embed.ly/


I think the simplest way to achieve what you're trying to do is the following:

You're trying to get from this:

http://www.youtube.com/watch?v=zb-gmJVW5lw

To this:

<iframe width="640" height="360" src="http://www.youtube.com/embed/zb-gmJVW5l" frameborder="0" allowfullscreen></iframe>

So you can just simply do this:

#### Use a regular expression to extract the video code
@video_id = (/([\w-]{11})/.match(@v_url)).to_s
#### Put this information in the right format
@embed_code = "<iframe width='640' height='360' src='http://www.youtube.com/embed/#{@video_id}' frameborder='0' allowfullscreen></iframe>"

And then in your view, just do:

<%= raw(@embed_code) %>


I have created a simple helper to embed YouTube videos:

# Helpers for better embedding and manipulation of videos
module VideosHelper
  # Regex to find YouTube's video ID
  YOUTUBE_REGEX = %r(^(http[s]*:\/\/)?(www.)?(youtube.com|youtu.be)\/(watch\?v=){0,1}([a-zA-Z0-9_-]{11}))

  # Embeds YouTube video of given URL in an iframe
  #
  # @param url [String] URL of desired video
  # @param width [String] width of embedded video. Can be any valid CSS unit
  # @param height [String] height of embedded video. Can be any valid CSS unit
  # @return [String] HTML string of embedded video
  def youtube_embed(url, width = "100%", height = "250px")
    youtube_id = find_youtube_id(url)

    result = %(<iframe title="YouTube video player" width="#{width}"
                height="#{height}" src="//www.youtube.com/embed/#{ youtube_id }"
                frameborder="0" allowfullscreen></iframe>)
    result.html_safe
  end

  # Finds YouTube's video ID from given URL or [nil] if URL is invalid
  # The video ID matches the RegEx \[a-zA-Z0-9_-]{11}\
  #
  # @param url [String] URL of desired video
  # @return [String] video ID of given URL
  def find_youtube_id(url)
    url = sanitize(url).to_str

    matches = YOUTUBE_REGEX.match url

    if matches
      matches[6] || matches[5]
    end
  end
end


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, 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:

  #show (before_save)
  # Returns a string (html_safe) .. iframe element from the embed string field
  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>").html_safe
      ## 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>").html_safe
      ### 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 %>
    </div><!-- .embed-responsive -->
  <% end %>

If you want to grab the thumbnail for the embed, this method works the same way:

  #_articles (before_save)
  # Returns a string (html_safe) .. img element from the embed string field
  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='https://img.youtube.com/vi/#{self.embed[32..42]}/0.jpg' />").html_safe
      elsif self.embed =~ /^(https?:\/\/)?(www\.)?youtu.be\//
        ("<img alt='Media' class='card-img-top' src='https://img.youtube.com/vi/#{self.embed[17..27]}/0.jpg' />").html_safe
      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, article_path(article) %>
<% end %>

In each case, you'll use an activerecord callback in the article.rb model:

before_save :iframe, :thumb
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜