Last active
June 25, 2019 08:35
-
-
Save mikker/001bcfd712c67d2482150462bca27a0d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
class VideoUrlParser | |
VideoMatch = Struct.new(:type, :video_id, :matches) | |
def initialize(url) | |
@url = url | |
@match = match_url | |
@type = @match.type | |
@video_id = @match.video_id | |
end | |
attr_reader :type, :video_id, :url | |
def extras | |
@match.matches | |
end | |
def still_image_url | |
case type | |
when :youtube | |
"https://img.youtube.com/vi/#{video_id}/hqdefault.jpg" | |
when :facebook | |
"https://graph.facebook.com/#{video_id}/picture?type=normal" | |
end | |
end | |
# rubocop:disable Metrics/LineLength | |
def embed_html | |
case type | |
when :youtube | |
%(<iframe class='db' width="320" height="180" src="https://www.youtube.com/embed/#{video_id}?showinfo=0&rel=0" frameborder="0" allowfullscreen></iframe>) | |
when :facebook | |
%(<div id="fb-root"></div><script>(function(d, s, id) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.3"; fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));</script><div class="fb-video" data-allowfullscreen="1" data-href="/#{extras[:username]}/videos/#{video_id}/?type=1"></div>) | |
when :vimeo | |
%(<iframe class='db' src="https://player.vimeo.com/video/148740221" width="500" height="281" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>) | |
else | |
"Unrecognized URL type '#{url}'" | |
end | |
end | |
# rubocop:enable Metrics/LineLength | |
private | |
# rubocop:disable Metrics/LineLength, Metrics/MethodLength | |
def match_url | |
types = { | |
youtube: [ | |
%r{https?://(www\.)?youtube.com/watch\?v=(?<id>[A-Za-z0-9\-_]+)}, | |
%r{https?://youtu.be/(?<id>[A-Za-z0-9\-_]+)} | |
], | |
facebook: %r{https?://(www\.)?facebook.com/(?<username>[A-Za-z0-9\-_\.]+)/videos/(?<id>\d+).*}, | |
vimeo: %r{https?://(www\.)?vimeo.com/(?<id>[0-9]+)} | |
} | |
types.each_with_object(VideoMatch.new(:unknown, nil)) do |kv, _unknown| | |
key, patterns = kv | |
matches = Array(patterns).reduce(nil) do |_, pattern| | |
if (hit = url.match(pattern)) | |
break hit | |
end | |
nil | |
end | |
break VideoMatch.new(key, matches[:id], matches) if matches | |
end | |
end | |
# rubocop:enable Metrics/LineLength, Metrics/MethodLength | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# typed: strict | |
# frozen_string_literal: true | |
require 'sorbet-runtime' | |
class VideoUrlParser | |
extend T::Sig | |
class VideoMatch < T::Struct | |
extend T::Sig | |
prop :type, Symbol | |
prop :video_id, T.nilable(String) | |
prop :matches, T.nilable(MatchData) | |
sig do | |
params( | |
type: Symbol, | |
video_id: T.nilable(String), | |
matches: T.nilable(MatchData) | |
).void | |
end | |
def initialize(type = :unknown, video_id: nil, matches: nil) | |
@type = T.let(type, Symbol) | |
@video_id = T.let(video_id, T.nilable(String)) | |
@matches = T.let(matches, T.nilable(MatchData)) | |
end | |
end | |
# rubocop:disable Metrics/LineLength | |
TYPE_PATTERNS = T.let({ | |
youtube: [ | |
%r{https?://(www\.)?youtube.com/watch\?v=(?<id>[A-Za-z0-9\-_]+)}, | |
%r{https?://youtu.be/(?<id>[A-Za-z0-9\-_]+)} | |
], | |
facebook: [%r{https?://(www\.)?facebook.com/(?<username>[A-Za-z0-9\-_\.]+)/videos/(?<id>\d+).*}], | |
vimeo: [%r{https?://(www\.)?vimeo.com/(?<id>[0-9]+)}] | |
}.freeze, T::Hash[Symbol, T::Array[Regexp]]) | |
# rubocop:enable Metrics/LineLength | |
sig { params(url: String).void } | |
def initialize(url) | |
@url = T.let(url, String) | |
@match = T.let(match_url, VideoMatch) | |
end | |
sig { returns(T.nilable(String)) } | |
def still_image_url | |
case type | |
when :youtube | |
"https://img.youtube.com/vi/#{video_id}/hqdefault.jpg" | |
when :facebook | |
"https://graph.facebook.com/#{video_id}/picture?type=normal" | |
end | |
end | |
# rubocop:disable Metrics/LineLength, Metrics/MethodLength | |
sig { returns(String) } | |
def embed_html | |
case type | |
when :youtube | |
%(<iframe class='db' width="320" height="180" src="https://www.youtube.com/embed/#{video_id}?showinfo=0&rel=0" frameborder="0" allowfullscreen></iframe>) | |
when :facebook | |
username = T.let(extras, T.untyped)[:username] | |
%(<div id="fb-root"></div><script>(function(d, s, id) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.3"; fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));</script><div class="fb-video" data-allowfullscreen="1" data-href="/#{username}/videos/#{video_id}/?type=1"></div>) | |
when :vimeo | |
%(<iframe class='db' src="https://player.vimeo.com/video/148740221" width="500" height="281" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>) | |
else | |
"Unrecognized URL type '#{url}'" | |
end | |
end | |
# rubocop:enable Metrics/LineLength, Metrics/MethodLength | |
private | |
# rubocop:disable Metrics/MethodLength | |
sig { returns(VideoMatch) } | |
def match_url | |
TYPE_PATTERNS.each_with_object(VideoMatch.new) do |(key, patterns), _| | |
matches = patterns.reduce(nil) do |_, pattern| | |
if (hit = url.match(pattern)) | |
break hit | |
end | |
nil | |
end | |
if matches | |
break VideoMatch.new(key, video_id: matches[:id], matches: matches) | |
end | |
end | |
end | |
# rubocop:enable Metrics/MethodLength | |
sig { returns(String) } | |
attr_reader :url | |
sig { returns(VideoMatch) } | |
attr_reader :match | |
sig { returns(T.nilable(MatchData)) } | |
def extras | |
@match.matches | |
end | |
sig { returns(T.nilable(Symbol)) } | |
def type | |
@match.type | |
end | |
sig { returns(T.nilable(String)) } | |
def video_id | |
@match.video_id | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# typed: strict | |
# frozen_string_literal: true | |
require 'sorbet-runtime' | |
class VideoUrlParser | |
extend T::Sig | |
class YouTubeType; end | |
class FacebookType; end | |
class VimeoType; end | |
class UnknownType; end | |
Type = T.type_alias(T.any(YouTubeType, FacebookType, VimeoType, UnknownType)) | |
class VideoMatch < T::Struct | |
extend T::Sig | |
prop :type, Type | |
prop :video_id, T.nilable(String) | |
prop :username, T.nilable(String) | |
# rubocop:disable Metrics/LineLength | |
PATTERNS = T.let({ | |
YouTubeType.new => [ | |
%r{https?://(www\.)?youtube.com/watch\?v=(?<id>[A-Za-z0-9\-_]+)}, | |
%r{https?://youtu.be/(?<id>[A-Za-z0-9\-_]+)} | |
], | |
FacebookType.new => [ | |
%r{https?://(www\.)?facebook.com/(?<username>[A-Za-z0-9\-_\.]+)/videos/(?<id>\d+).*} | |
], | |
VimeoType.new => [ | |
%r{https?://(www\.)?vimeo.com/(?<id>[0-9]+)} | |
] | |
}.freeze, T::Hash[Type, T::Array[Regexp]]) | |
# rubocop:enable Metrics/LineLength | |
sig do | |
params( | |
type: Type, | |
video_id: T.nilable(String), | |
username: T.nilable(String) | |
).void | |
end | |
def initialize(type = UnknownType.new, video_id: nil, username: nil) | |
@type = T.let(type, Type) | |
@video_id = T.let(video_id, T.nilable(String)) | |
@username = T.let(username, T.nilable(String)) | |
end | |
sig { params(url: String).returns(VideoMatch) } | |
def self.parse(url) | |
type, match = | |
PATTERNS.each_with_object([]) do |(type, patterns), _not_found| | |
match = patterns.lazy | |
.map { |p| url.match(p) } | |
.find { |m| !m.nil? } | |
break [type, match] if match | |
end | |
return unknown unless match | |
username = match.names.include?('username') ? match['username'] : nil | |
new(type, video_id: match[:id], username: username) | |
end | |
sig { returns(VideoMatch) } | |
def self.unknown | |
new(UnknownType.new) | |
end | |
end | |
sig { params(url: String).void } | |
def initialize(url) | |
@url = T.let(url, String) | |
@match = T.let(VideoMatch.parse(url), VideoMatch) | |
end | |
sig { returns(String) } | |
attr_reader :url | |
sig { returns(VideoMatch) } | |
attr_reader :match | |
sig { returns(Type) } | |
def type | |
match.type | |
end | |
sig { returns(T.nilable(String)) } | |
def still_image_url | |
case match.type | |
when YouTubeType | |
"https://img.youtube.com/vi/#{match.video_id}/hqdefault.jpg" | |
when FacebookType | |
"https://graph.facebook.com/#{match.video_id}/picture?type=normal" | |
end | |
end | |
# rubocop:disable Metrics/LineLength | |
sig { returns(String) } | |
def embed_html | |
case match.type | |
when YouTubeType | |
%(<iframe class='db' width="320" height="180" src="https://www.youtube.com/embed/#{match.video_id}?showinfo=0&rel=0" frameborder="0" allowfullscreen></iframe>) | |
when FacebookType | |
%(<div id="fb-root"></div><script>(function(d, s, id) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.3"; fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));</script><div class="fb-video" data-allowfullscreen="1" data-href="/#{match.username}/videos/#{match.video_id}/?type=1"></div>) | |
when VimeoType | |
%(<iframe class='db' src="https://player.vimeo.com/video/148740221" width="500" height="281" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>) | |
when UnknownType | |
"Unrecognized URL type '#{url}'" | |
end | |
end | |
# rubocop:enable Metrics/LineLength | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment