はじめに
スライドを表示する機能の実装方法を調べていたところ、SpeakerDeckというサービスを見つけました。このサービスはUIやUXが優れているものの、公式のAPIは提供されていません。それでも、スライドを表示したいと考え、Laravelを使用して実装に挑戦しました。
SpeakerDeck とは
SpeakerDeckとは、PDFをアップロードするだけで、簡単にWeb上にスライドを共有できるサービスです。
実装手段の経緯
peakerDeckにアップロードし、そのスライドのIDをカラムに保存し,iframeに埋め込む
ブログで埋め込むときに使用する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が正しく取得できなかったらエラーメッセージを表示
<?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::controller(UserSlideController::class)->group(function () {
Route::post('/store_slide_id', 'storeSlideId')->name('user.store_slide_id');
});
レイアウト
<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>
スライド表示するまでのステップのまとめ
- SpeakerDeckのURLを取得
- 入力フォームに1で取得したURLを入力します。
- SpeakerDeckのoEmbed から埋め込みコードがレスポンスとして返されます。
- JSONからhtmlキーを読み取りIDをカラムに保存します。
-
iframe
に取得したIDを埋め込んで表示します。
参考サイト