チャべログ

チャベス(@ChabesuB)のブログ。Notionのこと、プログラミングのこと、日常のこと。

A W E T I O N で YouTube の埋め込みに対応した

Notion AI
この記事を要約して

【Notion AI の要約】 このブログ記事は、A W E T I O N によるYouTubeの埋め込み対応について紹介しています。URLからYouTubeのIDを抜き出し、iframeで埋め込んでいます。また、レスポンシブ対応も行っています。今後も他のブロックの対応も進めていく予定です。 【記事の文字数】957 文字

A W E T I O N で YouTube の埋め込みに対応しました。

YouTubeを埋め込んだ場合のレスポンス

YouTube の埋め込みで何が返ってくるかを確認してみます。

utils\notion.tsxrenderBlocks

  • console.log(value);
  • console.log(type);

を確認します。

utils\notion.tsx

const renderBlock = (block: BlockObjectResponse) => {
  const { type, id } = block;
  const value = block[type];

	console.log(type); // eslint-disable-line no-console
  console.log(value); // eslint-disable-line no-console

typeには videoが返ってきました。

//console.log(type);
video

//console.log(value);
{
  caption: [],
  type: 'external',
  external: { url: 'https://www.youtube.com/watch?v=8ptQj7dgwIo' }
}

switch の分岐に case "video”: を追加して、YouTube を埋め込んだ場合の対応を実装します。

case "video”: 内で、console.log(value.external.url); を確認すると、埋め込んだ YouTube の URL が返ってきます。

utils\notion.tsx

case "video": {
      console.log(value.external.url); // eslint-disable-line no-console
YouTube の ID を URL から抜き出す

YouTube の ID は URL の v=****** の ***** の部分です。

下記の URL の場合は、8ptQj7dgwIo がIDとなります。

https://www.youtube.com/watch?v=8ptQj7dgwIo

以下の PR を参考にさせていただきます。

まずは、 utils\notion.tsx 内に以下を追記します。

case "video": {
      let youtubeurl: URL;
      try {
        youtubeurl = new URL(value.external.url);
      } catch {
        return null;
      }

URL オブジェクトを利用すると便利です。

utils\youtube.ts を作成して、以下を実装します。

utils\youtube.ts

export const isYouTubeURL = (url: URL): boolean => {
  if (["www.youtube.com", "youtu.be"].includes(url.hostname)) {
    return true;
  }
  return false;
};

// Supported URL
//
// - http://youtu.be/0zM3nApSvMg
// - http://www.youtube.com/watch?v=0zM3nApSvMg&feature=feedrec_grec_index
// - http://www.youtube.com/watch?v=0zM3nApSvMg#t=0m10s
// - http://www.youtube.com/watch?v=0zM3nApSvMg
// - http://www.youtube.com/v/0zM3nApSvMg?fs=1&hl=en_US&rel=0
// - http://www.youtube.com/embed/0zM3nApSvMg?rel=0
export const parseYouTubeVideoId = (url: URL): string => {
  if (!isYouTubeURL(url)) return "";

  if (url.hostname === "youtu.be") {
    return url.pathname.split("/")[1];
  }
  if (url.pathname === "/watch") {
    return url.searchParams.get("v");
  }
  const elements = url.pathname.split("/");

  if (elements.length < 2) return "";

  if (elements[1] === "v" || elements[1] === "embed") {
    return elements[2];
  }

  return "";
};

これで YouTube の ID を抜き出す関数の準備はできたので、utils\notion.tsx で ID を受け取ります。

const videoId = parseYouTubeVideoId(youtubeurl);
      if (videoId === "") {
        return null;
      }
iframe で埋め込む

初めは react-youtube というライブラリを利用しようとしましたが、なぜか動画が表示されず、うまくいかなかったので iframe で埋め込むことにしました。

utils\notion.tsx

import { parseYouTubeVideoId } from "@/utils/youtube";

const renderBlock = (block: BlockObjectResponse) => {
  const { type, id } = block;
  const value = block[type];

  switch (type) {
		・
		・
		・
    case "video": {
      let youtubeurl: URL;
      try {
        youtubeurl = new URL(value.external.url);
      } catch {
        return null;
      }

      const videoId = parseYouTubeVideoId(youtubeurl);
      if (videoId === "") {
        return null;
      }

      return (
        <div className="video">
          <iframe
            src={`https://www.youtube.com/embed/${videoId}`}
            title="YouTube video player"
            frameBorder="0"
            allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
            allowFullScreen
            key={videoId}
          />
        </div>
      );
    }
  }
};
utils\notion.tsx
レスポンシブ対応

YouTube の埋め込みをレスポンシブ対応するために、 components\content.tsx に以下を追加します。

:global(.video) {
  position: relative;
  width: 100%;
  height: 0;
  padding-top: 56.25%;
  margin-top: 2rem;
  margin-bottom: 2rem;
}
:global(.video iframe) {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

これで完成です。

終わりに

今回は YouTube の動画の埋め込みを実装しましたが、ツイッターの埋め込みなど対応できていないブロックもあるので、随時対応していく予定です。