🎥

入力されたURLを元に、動画を自動で埋め込む方法

2020/09/18に公開

背景

生配信のURLをFormに入力した際に、自動で動画が埋め込まれるようにする必要があり、実装方法を検討しました。
今回は Twitch, Youtube, niconico に対応しました。

概要

入力されたURLを正規表現でうまく切り貼りして<iframe>に入れます。
<iframe>についてはこちら。
https://developer.mozilla.org/ja/docs/Web/HTML/Element/iframe

各動画コンテンツの埋め込み仕様

Twitch

Youtube

niconico

  • 公式document: これ?
    • 詳しく記載されたページが見当たらない
<script type="text/javascript" src="http://ext.nicovideo.jp/thumb_watch/1453178722?w=490&h=307"></script>

公式的には↑だが、実際はiframeを表示しているので

<iframe src="http://embed.nicovideo.jp/watch/1453178722"></iframe>

とする。

対応させるURL

http://twitch.tv/********
https://www.twitch.tv/********
https://go.twitch.tv/********
https://m.twitch.tv/********

https://youtu.be/********
https://www.youtube.com/watch?v=********
https://gaming.youtube.com/watch?v=********

https://nico.ms/sm********
https://www.nicovideo.jp/watch/sm********

「********」はID

実装方法

function embedVideo(url: string) {
    const hostname = urlParser(url).hostname

    const matchesTwitch = url.match(/twitch\.tv\/([^#?/]+)/)
    if (/twitch\.tv$/.test(hostname) && matchesTwitch) {
        return 'https://player.twitch.tv/?channel=' + matchesTwitch[1] + '&autoplay=false'
    }

    if (/(youtube\.com|youtu\.be)$/.test(hostname) && !/\/user\//.test(url) && !/\/channel\//.test(url)) {
        const matches = url.match(/(\/watch\?v=|youtu\.be\/)([^#&?/]+)/)
        if (!matches) return ''
        return 'https://www.youtube.com/embed/' + matches[2]
    }

    if (/(nicovideo\.jp|nico\.ms)$/.test(hostname) && !/live/.test(hostname)) {
        const matches = url.match(/(\/watch\/|nico\.ms\/)([^#&?/]+)/)
        if (!matches) return ''
        return 'https://embed.nicovideo.jp/watch/' + matches[2]
    }
    return ''
}

Vue.jsの場合

Vue.filtersに追加して、

filters: {
  embedVideo,
},

iframeのsrcでフィルタすると良いです。
<iframe :src="url | embedVideo" allow="fullscreen"></iframe>

レスポンシブ対応

.video
    position relative
    padding-bottom 56.25%

    & > iframe
        position absolute
        size 100% 100%
        border none

<iframe>はそのままだとサイズが変わらないので、position: absolute;で浮かせて親要素に同じ高さのpaddingを取ることで、可変になります。

2021-06-02 追記
aspect-ratio: 16/9;を使うことでも対応できるようです。ただしSafariは未対応。
https://caniuse.com/?search=aspect-ratio

Discussion