LoginSignup
0
0

Laravel でSpeakerDeck のスライドをアップロードして表示する機能実装

Last updated at Posted at 2024-06-09

はじめに

スライドを表示する機能の実装方法を調べていたところ、SpeakerDeckというサービスを見つけました。このサービスはUIやUXが優れているものの、公式のAPIは提供されていません。それでも、スライドを表示したいと考え、Laravelを使用して実装に挑戦しました。

SpeakerDeck とは

SpeakerDeckとは、PDFをアップロードするだけで、簡単にWeb上にスライドを共有できるサービスです。

実装手段の経緯

peakerDeckにアップロードし、そのスライドのIDをカラムに保存し,iframeに埋め込む

スクリーンショット 2024-06-08 7.24.19.png

ブログで埋め込むときに使用するCopy iframe embed codeを選択します。取得されるiframeのコードは以下のようになっています。

<iframe class="speakerdeck-iframe" frameborder="0" src="https://speakerdeck.com/player/67945f4875504c52a924be0311bcc089" title="itheme-webinar-podcast.pdf" allowfullscreen="true" style="border: 0px; background: padding-box padding-box rgba(0, 0, 0, 0.1); margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 100%; height: auto; aspect-ratio: 560 / 315;" data-ratio="1.7777777777777777"></iframe>

コードのplayyerの直後の箇所がIDです。このIDを置き換えることで任意のスライドを表示できることを見つけました。

src="https://speakerdeck.com/player/67945f4875504c52a924be0311bcc089"

しかし、ユーザーにiframeからIDを取得させるのは適切ではありません。URLを入力してもらうだけでスライドを表示できる方が、ユーザーにとっても手間がかからず良いと考えました。そのためには、SpeakerDeckのoEmbedを利用して、スライドのURLからIDを抽出する必要がありました。

oEmbedとは

oEmbedは、ウェブページに他のサイトのコンテンツ(ビデオ、画像、テキストなど)を埋め込むためのフォーマットです。URLを使って埋め込みたいコンテンツの情報を取得し、自動的にそのコンテンツを表示する方法を提供します。

スライドURLからIDを取得

SpeakerDeckはoEmbed のエンドポイントを提供しています。

https://speakerdeck.com/oembed.json

したがって、oEmbed をリクエストすると次のようになります。

https://speakerdeck.com/oembed.json?url=URL_OF_THE_DECK

実際のURLに合わせると次のようになります。該当のスライドの埋め込みコードがレスポンスされます。

https://speakerdeck.com/oembed.json?url=https://speakerdeck.com/kazu1212star/itheme-webinar-podcast

レスポンスのJSON構造は以下の通りです。この中で特に重要なのは、htmlキーに含まれるiframe情報です。返却されるiframeは、例えばplayer/67945f4875504c52a924be0311bcc089のようなIDをベースにしています

{
  "type": "rich",
  "version": 1.0,
  "provider_name": "Speaker Deck",
  "provider_url": "https://speakerdeck.com/",
  "title": "itheme-webinar-podcast.pdf",
  "author_name": "kazu1212-star",
  "author_url": "https://speakerdeck.com/kazu1212star",
  "html": "<iframe id=\"talk_frame_1196406\" class=\"speakerdeck-iframe\" src=\"//speakerdeck.com/player/67945f4875504c52a924be0311bcc089\" width=\"710\" height=\"399\" style=\"aspect-ratio:710/399; border:0; padding:0; margin:0; background:transparent;\" frameborder=\"0\" allowtransparency=\"true\" allowfullscreen=\"allowfullscreen\"></iframe>",
  "width": 710,
  "height": 399,
  "ratio": 1.7777777777778
}

スライド表示機能を実装

コントローラー作成

スライドのIDを取得方法

1. JSONからhtmlキーを読み取り、含まれているiframeを取得します。
2. iframeのURLからplayer直後に続くIDを抽出し、変数に格納します。

 $htmlContent = $data['html'];
 preg_match('/player\/([a-z0-9]+)"/i', $htmlContent, $matches);
 $slideId = $matches[1] ?? null;

コントローラーのコード説明

UserSlideControllerコントローラーを作成し、storeSlideIdメソッドを作成します。
Usersテーブルにslide_idカラムをstring型で作成し、そこに保存します。

エラー対応

  • URLが正しくなく、取得したいレスポンスではなかったらエラーメッセージを表示
  • スライドのIDが正しく取得できなかったらエラーメッセージを表示
contoroller.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

class UserSlideController extends Controller
{
    public function storeSlideId(Request $request)
    {
        $validatedData = $request->validate([
            'url' => 'required|url'
        ]);

        $url = $validatedData['url'];
        $response = Http::get('https://speakerdeck.com/oembed.json', [
            'url' => $url,
            'format' => 'json'
        ]);

        $data = $response->json();

        // 'html' キーが存在するか確認
        if (!isset($data['html'])) {
            return back()->with('flashError', 'スライド情報を取得できませんでした。URLを確認してください。');
        }

        $htmlContent = $data['html'];
        preg_match('/player\/([a-z0-9]+)"/i', $htmlContent, $matches);
        $slideId = $matches[1] ?? null;

        if (is_null($slideId)) {
            return back()->with('flashError', 'スライド情報を取得できませんでした。URLを確認してください。');
        }

        $company = Auth::user()->company;
        $company->slide_id = $slideId;
        $company->save();

        return redirect()->route('company.base_profile')->with('flashSuccess', 'スライドを保存しました。');
    }
}

ルーティング

route.php
Route::controller(UserSlideController::class)->group(function () {
    Route::post('/store_slide_id', 'storeSlideId')->name('user.store_slide_id');
});

レイアウト

blade.php
        <div class="mt-4 ml-10 w-[734px]">
            <div class="inline-block text-h5">
                説明スライド
            </div>
            <form action="{{ route('user.store_slide_id') }}" method="POST" class="mb-1">
                @csrf
                <label for="url" class="text-l text-gray-900 mb-4 mt-2">Speakerdeck SlideのURLを入力してください</label>
                <div class="flex items-center justify-between space-x-2 mb-3 mt-2">
                    <input type="url" id="url" name="url" class="form-input h-11 w-[550px] border border-gray-300 rounded-lg text-l-w text-gray-900">
                    <button type="submit" class="px-4 py-2.5 bg-white rounded-lg border border-gray-300 flex justify-center items-center w-[112px] text-slate-700 text-button-medium font-bold hover:bg-gray-100">
                            <img src="{{ asset('svg/edit.svg') }}" class="w-[17px] h-[17px] mr-1">
                            更新する
                    </button>
                </div>
            </form>
            <x-input-error :messages="$errors->get('url')" class="mt-2" />
            @if($user->slide_id)
            //ここで表示させます
                <iframe class="speakerdeck-iframe" frameborder="0" src="https://speakerdeck.com/player/{{ $user->slide_id }}" title="itheme-webinar-podcast.pdf" allowfullscreen="true" style="border: 0px; background: padding-box padding-box rgba(0, 0, 0, 0.1); margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 100%; height: auto; aspect-ratio: 560 / 315;" data-ratio="1.7777777777777777"></iframe>
            @endif
        </div>

IDを埋め込んでいる箇所

src="https://speakerdeck.com/player/{{ $user->slide_id }}"

<iframe class="speakerdeck-iframe" frameborder="0" src="https://speakerdeck.com/player/{{ $user->slide_id }}" title="itheme-webinar-podcast.pdf" allowfullscreen="true" style="border: 0px; background: padding-box padding-box rgba(0, 0, 0, 0.1); margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 100%; height: auto; aspect-ratio: 560 / 315;" data-ratio="1.7777777777777777"></iframe>

以下のようなレイアウトになります。
スクリーンショット 2024-06-07 22.47.44.png

スライド表示するまでのステップのまとめ

  1. SpeakerDeckのURLを取得
スクリーンショット 2024-06-08 22.00.35.png
  1. 入力フォームに1で取得したURLを入力します。
  2. SpeakerDeckのoEmbed から埋め込みコードがレスポンスとして返されます。
  3. JSONからhtmlキーを読み取りIDをカラムに保存します。
  4. iframeに取得したIDを埋め込んで表示します。

参考サイト

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0