Auto-embed URLs from YouTube, Vimeo, Gists and more
rails app:template LOCATION='https://perron.railsdesigner.com/library/embed-content/template.rb'
This processor automatically converts plain text URLs in paragraphs to embedded content. Simply paste a URL to a supported platform and it will be transformed into an interactive embed.
Example
When you write:
```markdown
Check out this video:
https://www.youtube.com/watch?v=dQw4w9WgXcQ
```
It automatically becomes an embedded YouTube player instead of plain text.
Supported platforms
- YouTube
- Vimeo
- GitHub Gist
- CodePen
- Loom
Adding your own providers
To add support for a new platform, create a new class in app/processors/embed_processor/
and add it to the PROVIDERS
array in EmbedProcessor
. Each provider needs a matches?
method to detect URLs and an embed
method to generate the iframe or script tag.
Usage
Add the processor to your pipeline and paste any supported URL on its own line. The processor will detect and transform it automatically.
Template source
create_file "app/processors/embed_processor", <<~ERB class EmbedProcessor < Perron::HtmlProcessor::Base def process @html.css("p").each do |paragraph| text = paragraph.text provider = PROVIDERS.find { it.constantize.matches?(text) } if text.present? paragraph.replace(provider.constantize.embed(text, @html)) if provider end end private PROVIDERS = %w[ EmbedProcessor::Codepen EmbedProcessor::Gist EmbedProcessor::Loom EmbedProcessor::Vimeo EmbedProcessor::Youtube ] end end file "app/processors/embed_processor/codepen.rb" do <<~"_" class EmbedProcessor class Codepen def self.matches?(text) text.match?(%r{https?://codepen\.io/}) end def self.embed(text, html) # extracts username/pen_id from URLs like `https://codepen.io/railsdesigner/pen/PwZJqqb` username, id = text.match(%r{codepen\.io/([^/]+)/pen/([^\s?]+)}).captures Nokogiri::XML::Node.new("iframe", html).tap do |iframe| iframe["src"] = "https://codepen.io/#{username}/embed/#{id}?default-tab=result" iframe["width"] = "100%" iframe["height"] = "500" iframe["allowfullscreen"] = "true" end end end end _ end file "app/processors/embed_processor/gist.rb" do <<~"_" class EmbedProcessor class Gist def self.matches?(text) text.match?(%r{https?://gist\.github\.com/}) end def self.embed(text, html) url = text[%r{https?://gist\.github\.com/[^\s]+}, 0] Nokogiri::XML::Node.new("script", html).tap do |script| script["src"] = "#{url}.js" end end end end _ end file "app/processors/embed_processor/loom.rb" do <<~"_" class EmbedProcessor class Loom def self.matches?(text) text.match?(%r{https?://(?:www\.)?loom\.com/share/}) end def self.embed(text, html) id = text[%r{loom\.com/share/([^\s?]+)}, 1] Nokogiri::XML::Node.new("iframe", html).tap do |iframe| iframe["src"] = "https://www.loom.com/embed/#{id}" iframe["width"] = "100%" iframe["height"] = "400" iframe["allowfullscreen"] = "true" iframe["frameborder"] = "0" end end end end _ end file "app/processors/embed_processor/vimeo.rb" do <<~"_" class EmbedProcessor class Vimeo def self.matches?(text) text.match?(%r{https?://(?:www\.)?vimeo\.com/}) end def self.embed(text, html) id = text[%r{vimeo\.com/(\d+)}, 1] Nokogiri::XML::Node.new("iframe", html).tap do |iframe| iframe["src"] = "https://player.vimeo.com/video/#{id}" iframe["width"] = "100%" iframe["height"] = "400" iframe["allowfullscreen"] = "true" end end end end _ end file "app/processors/embed_processor/youtube.rb" do <<~"_" class EmbedProcessor class Youtube def self.matches?(text) text.match?(%r{https?://(?:www\.)?(?:youtube\.com/watch\?v=|youtu\.be/)}) end def self.embed(text, html) id = text[/(?:v=|youtu\.be\/)([^&?\s]+)/, 1] Nokogiri::XML::Node.new("iframe", html).tap do |iframe| iframe["src"] = "https://www.youtube.com/embed/#{id}" iframe["width"] = "100%" iframe["height"] = "400" iframe["allowfullscreen"] = "true" end end end end _ end end