導入ガイド
サイトにプレーヤーを設置する
訪問者がサイトを離れずに聴けるようにしましょう。Obboで音声プレーヤーを作成し、ページにコードを貼れば準備完了です。サイトの管理を依頼している場合は、このガイドを担当者にお送りください。
多くのサイトは最初の3ステップだけで完了します。デザイン調整と開発者向け情報は必要な場合だけご覧ください。
01プレーヤーIDを取得する
プレーヤーとは、埋め込む対象そのものです。ポッドキャスト全体、または特定のエピソードを指し示し、HTMLに貼り付ける公開IDを持ちます。
- 「アカウント」から「音声プレーヤー」を開きます。
- プレーヤーを作成し、自分でわかる名前を付けて、再生する内容を追加します。ポッドキャスト全体、1エピソード、または任意の順序で複数のエピソードを指定できます。
- プレーヤーIDをコピーします。
- 変更を公開し、プレーヤーを有効にしておきます。下書きの変更は訪問者には表示されません。
IDは公開される前提のものです。ページのソースに書かれ、誰でも読める状態になりますが、問題ありません。このIDが許可するのは1つだけ、そのプレーヤーに入れたエピソードを再生することです。APIキーではなく、アカウント内の他の情報には一切届きません。プレーヤーを無効にすれば、すべての場所で同時に無効になります。
番組全体を選んだプレーヤーには、新しく完成したエピソードが自動表示されます。選択したエピソードや設定を変更したら、その変更を公開してください。埋め込みコードの貼り直しは不要です。
022行貼り付ける
YOUR_WIDGET_IDをご自身のプレーヤーIDに置き換えてください。scriptをページに、divを表示したい場所に置きます。サイト作成ツールでは、スクリプトを許可するカスタムHTMLまたは埋め込みブロックを使ってください。
<script src="https://www.obbo.me/player/obboplayer.js" async></script>
<div data-obbo-player="YOUR_WIDGET_ID"></div>これで導入は完了です。スクリプトは data-obbo-player 属性を持つ要素をすべて見つけて描画します。ページ上のプレーヤーが1つでも10個でも同じです。スクリプトを2回読み込んでも問題ありません。
音声は再生を押した後にダウンロードされます。エピソード一覧とカバー画像はページと一緒に読み込みますが、音声は訪問者が再生を始めた後に要求されます。ページの表示だけでは再生に数えられません。
03公開ページを確認する
サイトを保存・公開し、訪問者と同じようにページを開いてください。編集画面のプレビューではスクリプトを実行しないツールもあります。
- Obboにログインしなくても番組名と完成したエピソードが表示されることを確認します。
- 再生、シーク、一時停止を試します。操作する前に音声が始まらないことも確認してください。
- スマートフォンと広い画面の両方で確認します。表示されない場合は、サイトの編集ツールがカスタムHTMLと外部スクリプトを許可しているか確認してください。
設置完了です。ここで終了して構いません。別のレイアウトや独自デザイン、カスタム開発が必要な場合だけ、以下をお読みください。
04レイアウトを選ぶ
6つの表示レイアウトとautoがあります。data-obbo-uiで指定してください。省略またはautoなら、公開済みのコンパクト・一覧設定に従います。
| 値 | 内容 |
|---|---|
list | 操作部の下にエピソード一覧が並びます。ポッドキャスト全体を見せたいときや、最新以外のエピソードも聴かれそうなときに。 |
bar | 操作部のみ。ひとつのエピソードを中心にした記事や製品ページに。 |
card | カバーアートを大きく見せ、ボタンをその縁に置きます。サイドバーや一覧など、横長のバーでは取ってつけたように見える場所に。 |
inline | 再生ボタンと時間表示だけ。文章を分断せず、文の中に収まる大きさです。 |
dock | 再生を押すと画面下部に固定されるので、スクロールしても操作部が流れていきません。閉じることもできます。 |
transcript | エピソードを、音声に追従する読めるテキストとして表示します。話している行がハイライトされ、任意の行をクリックするとその位置へ移動します。 |
auto | 既定値。プレーヤーに保存されたレイアウトに従います。 |
<script src="https://www.obbo.me/player/obboplayer.js" async></script>
<div
data-obbo-player="YOUR_WIDGET_ID"
data-obbo-ui="list"
data-obbo-theme="dark"
></div>すべての属性
| 設定・識別子 | 役割 |
|---|---|
data-obbo-player | 必須。プレーヤーIDです。 |
data-obbo-ui | list、bar、card、inline、dock、transcript、または auto。 |
data-obbo-theme | light または dark。 |
data-obbo-episode | 特定のエピソードから始めます。選択されるだけで、再生はされません。 |
data-obbo-isolate | shadow root の中に描画し、ページのCSSから切り離します。 |
data-obbo-locale | プレーヤーの操作部分の言語です。en、es、da、ja。エピソードのタイトルはいずれの場合もポッドキャストの内容が使われます。 |
data-obbo-language | 音声言語:en、es、da、ja、de、fr、it、nl、sv、no、pl。既定ではページのlang属性を使い、該当する録音がない場合は元の言語で再生します。 |
data-obbo-autoadvance | エピソードが終わったら次を再生します。 |
1ページに複数のプレーヤーを置いても問題ありません。エピソード一覧の取得は1回にまとめられ、ひとつを再生すると他は一時停止します。訪問者が2つの音声を同時に聞くことはありません。
05サイトになじませる
プレーヤーはiframeではなくページ内に描画されます。以下の変数で色、角丸、フォントを合わせられます。例にはHTMLとCSSをつなぐクラスも含まれています。
手早く: 9つの変数
| CSS変数 | 既定値 |
|---|---|
--obbo-player-bg | #ffffff |
--obbo-player-fg | #1c2733 |
--obbo-player-muted | #66768a |
--obbo-player-accent | #2f6fed |
--obbo-player-accent-fg | #ffffff |
--obbo-player-border | #e3e8ef |
--obbo-player-row-hover | #f4f6f9 |
--obbo-player-radius | 12px |
--obbo-player-font | システムフォント |
<div class="my-player" data-obbo-player="YOUR_WIDGET_ID"></div>
<style>
.my-player {
--obbo-player-accent: #a1482e;
--obbo-player-radius: 8px;
--obbo-player-font: system-ui, sans-serif;
}
</style>しっかり: クラス名
安定したobbo-クラスで操作部を指定できます。ブランド調整には変数、詳細な変更にはクラスを使ってください。data-obbo-stateで読み込みやエラー時の表示を調整できます。再生できないことが伝わるよう、エラーメッセージは隠さないでください。
| 設定・識別子 | 役割 |
|---|---|
.obbo-p | プレーヤーのルート。data-obbo-state が付きます。 |
.obbo-play | 再生・一時停止ボタン。 |
.obbo-seek | シークバー。type が range の input です。 |
.obbo-title / .obbo-sub | エピソードのタイトルとポッドキャスト名。 |
.obbo-art | カバー画像。ポッドキャストに画像がない場合は非表示になります。 |
.obbo-list / .obbo-row | エピソード一覧とその行。再生中の行には aria-current が付きます。 |
.obbo-note | 読み込み中・エピソードなし・エラーのメッセージ。 |
.obbo-p[data-obbo-state="loading"] { opacity: 0.6; }
.obbo-p[data-obbo-state="error"] .obbo-note { font-weight: 700; }CSSの影響が強い場合は切り離してください。ページ内レイアウトにdata-obbo-isolateを追加すると、サイトのCSSから保護できます。9つの変数は有効ですが、クラスによる内部の変更はできなくなります。dockはドキュメントに直接追加され、shadow分離には対応しません。
06独自のプレーヤーを作る
用意されたレイアウトを一切使わない方法です。createPlayer がエピソード情報、再生、再生位置を渡すので、マークアップはご自身で書けます。試聴の記録も、期限切れになった音声リンクの復帰も、そのまま働き続けます。下にある操作部は、その下のコードが実際に動いているものです。
Momentoの実際のサンプルです。独自の操作部も、用意されたレイアウトと同じ再生エンジンを使います。
サンプルを読み込み中…
<script src="https://www.obbo.me/player/obboplayer.js" async></script>
<button id="play" type="button" disabled>Play</button>
<span id="time">0:00</span>
<script>
addEventListener('load', function () {
var player = Obbo.createPlayer({ widgetId: 'YOUR_WIDGET_ID' });
var button = document.getElementById('play');
var time = document.getElementById('time');
player.subscribe(function (state) {
button.disabled = state.status !== 'ready' || !state.playable;
button.textContent = state.playing ? 'Pause' : 'Play';
time.textContent = Obbo.formatTime(state.position);
});
button.onclick = function () { player.toggle(); };
});
</script>status が ready になるまでボタンは無効にしてください。iOSでは、音声を再生する許可はそれを求めたタップに結び付いています。プレーヤーがまだ応じられないタップは無駄になり、訪問者はもう一度タップすることになります。
07音声に追従する文字起こし
文字起こしレイアウトは、エピソード全体をテキストとしてページに置き、音声と歩調を合わせます。Obboのエピソードは制作の一環として文単位のタイムスタンプ付きで書き起こされるため、準備は不要です。
- 話している行がハイライトされ、自動で見える位置までスクロールします。読者が自分でスクロールすると追従を止め、戻るためのボタンを出します。スクロールを奪い合うことはありません。
- 任意の行をクリックするとそこから再生されるので、エピソードが引用可能になります。読者は目当ての一文を見つけて、それが語られるのを聴けます。
- 文字起こしは選択できるテキストで、読み込み後は支援技術で読めます。検索での表示が重要な文章はページ自身のHTMLにも置いてください。JavaScriptで描画した文章の索引化は保証されません。
<script src="https://www.obbo.me/player/obboplayer.js" async></script>
<div data-obbo-player="YOUR_WIDGET_ID" data-obbo-ui="transcript"></div>各エピソードで利用できる文字起こしを表示します。完成した文字起こしは埋め込みAPIから配信されます。存在しない場合も音声は再生でき、その旨が表示されます。プレーヤーの試用ページで読み合わせを体験できます。
08APIリファレンス
Obbo.createPlayer(options)
| 設定・識別子 | 役割 |
|---|---|
widgetId | 必須。プレーヤーIDです。 |
locale | 組み込みラベルの言語。既定は en。 |
language | 要求する音声の言語。ページの言語を指定します。該当する録音がない場合は元の言語で再生します。 |
apiBase | 公開APIのオリジン。既定はhttps://app.obbo.me。別のObboサーバーを使う場合だけ変更します。 |
autoAdvance | 次のエピソードへ続けます。既定はオフ。 |
exclusive | 再生開始時にページ上の他のプレーヤーを一時停止します。既定はオン。 |
プレーヤー
| 設定・識別子 | 役割 |
|---|---|
subscribe(fn) | 状態が変わるたびに全体の状態とともに呼ばれ、登録直後にも一度呼ばれます。解除用の関数を返します。 |
getState() | 現在の状態。購読ではなく都度取得したい場合に。 |
play(episodeId?) | 再生を開始します。先にエピソードを切り替えることもできます。 |
pause() / toggle() | 見たままの動作です。 |
select(episodeId) | 再生せずにエピソードを切り替えます。通信は発生しません。 |
seek(seconds) | 指定した位置(秒)へ移動します。 |
setRate(rate) | 再生速度。0.75 から 2 まで。 |
next() / previous() | エピソード一覧を前後に移動します。 |
reload() | エピソード一覧を取得し直します。 |
destroy() | 停止して切り離します。コンポーネントのアンマウント時に呼んでください。 |
media | 内部の audio 要素です。想定外の用途が必要になった場合に。 |
状態
| 設定・識別子 | 役割 |
|---|---|
status | loading、ready、empty、error のいずれか。 |
error | 空、またはタップなしでブラウザが拒否した blocked、load_failed、IDが誤っているか失効している unavailable。 |
episodes | プレーヤー内のすべてのエピソード。タイトル、説明、番号、日付、長さ。 |
episode | 選択中のエピソード。選択は再生を意味しません。 |
podcast | タイトル、会社名、カバー画像。 |
playing | 現在音声が流れているかどうか。 |
position / duration | いずれも秒単位。 |
playable | 選択中のエピソードが再生可能かどうか。 |
Obbo のその他
| 設定・識別子 | 役割 |
|---|---|
Obbo.formatTime(s) | 65 を 1:05 に変換します。組み込みレイアウトと同じ形式です。 |
Obbo.ui.list(el, player, opts) | 組み込みレイアウトを自分で設置します。destroy を持つオブジェクトを返します。 |
Obbo.mount(root?) | プレーヤー要素を探して設置します。マークアップを動的に追加した場合に呼んでください。 |
Obbo.unmountElement(el) | ひとつを取り外します。 |
Obbo.version | 不具合の報告時に添えてください。 |
09React、Vue など
自動スキャンに頼らないでください。コンテナを再描画するフレームワークはプレーヤーのマークアップを消し去り、イベントリスナーだけを残します。自分で設置し、アンマウント時に破棄してください。設置先の要素には自分で何も描画しないでください。
import { useEffect, useRef, useState } from 'react';
let sdkPromise;
function loadPlayer() {
if (window.Obbo) return Promise.resolve(window.Obbo);
if (sdkPromise) return sdkPromise;
sdkPromise = new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = 'https://www.obbo.me/player/obboplayer.js';
script.async = true;
script.onload = () => {
if (window.Obbo) resolve(window.Obbo);
else {
sdkPromise = null;
script.remove();
reject(new Error('Player SDK unavailable'));
}
};
script.onerror = () => {
sdkPromise = null;
script.remove();
reject(new Error('Player SDK could not load'));
};
document.head.appendChild(script);
});
return sdkPromise;
}
export function Player({ widgetId, locale = 'en' }) {
const host = useRef(null);
const [failed, setFailed] = useState(false);
const [attempt, setAttempt] = useState(0);
useEffect(() => {
let cancelled = false;
let cleanup;
loadPlayer().then((Obbo) => {
if (cancelled) return;
const player = Obbo.createPlayer({ widgetId, locale, language: locale });
const ui = Obbo.ui.list(host.current, player, { locale });
cleanup = () => { ui.destroy(); player.destroy(); };
}).catch((error) => {
if (!cancelled) {
console.error('Player failed to load', error);
setFailed(true);
}
});
return () => { cancelled = true; cleanup?.(); };
}, [widgetId, locale, attempt]);
return <>
<div ref={host} />
{failed && <p role="alert">
The player could not load.
<button type="button" onClick={() => {
setFailed(false);
setAttempt((value) => value + 1);
}}>Try again</button>
</p>}
</>;
}この例はSDKの読み込みを待ち、遅れたマウントを中止し、終了時に表示とプレーヤーを破棄します。サイトの言語をlocaleに渡してください。VueやSvelteでも同じライフサイクルを使います。インライン例にはCSP nonceや外部JavaScriptファイルが必要な場合があります。
10Content-Security-Policy
Content-Security-Policyを使うサイトでは、開発者と以下を確認してください。既存のポリシーに必要なホストを追加します。この表はそのまま貼れる完全なポリシーではありません。
| 設定・識別子 | 役割 |
|---|---|
script-src https://www.obbo.me | プレーヤーの読み込みに必要です。 |
connect-src https://app.obbo.me | エピソード一覧の取得に必要です。 |
media-src https://app.obbo.me https://*.amazonaws.com | 音声そのものの配信に必要です。 |
style-src | SDKはインラインのスタイルシートを挿入します。ポリシーで許可する必要があり、現在のバンドルはスタイルシートnonceに対応しません。CSPを無効にせず、開発者と要件を確認してください。 |
img-src | カバー画像のホスト(通常はS3)を許可してください。実際の画像URLから必要最小限のホストを判断します。 |
見落とされるのは media-src です。音声はAPIとは別のホストのストレージから配信されます。これを省くと、プレーヤーは一見まったく正常に見えたまま、誰かが再生を押した瞬間に失敗します。
11記録される内容
サイトでの試聴は Obbo の分析に表示されます。プレーヤーが読み込まれた回数、再生が始まった回数、そして実際に聴かれた量です。
- 訪問者が特定されることはありません。アカウントもログインも不要で、プレーヤーはCookieを設定しません。レポートは所有者であるあなたに紐づき、聴いている人には紐づきません。
- ページの表示は再生ではありません。音声が実際に始まるまで、再生としては数えられません。
- 試聴時間は推測ではなく計測です。early飛ばした部分は聴いたことになりません。
12うまくいかないとき
何も表示されない
要素に data-obbo-player とご自身のIDが指定されているか、スクリプトタグがページにあるかを確認してください。ページ読み込み後にマークアップを追加した場合は、そのあとで Obbo.mount() を一度呼んでください。
プレーヤーを利用できないと表示される
IDが誤っているか、アカウントでプレーヤーが無効化されています。どちらの場合も意図的に同じメッセージを返します。
エピソードがないと表示される
プレーヤーが空か、エピソードがまだ制作中です。完成したエピソードだけが配信されます。
見た目は正常なのに再生されない
ほとんどの場合、Content-Security-Policy に media-src がありません。それ以外の場合は state.error を確認してください。blocked は、ブラウザが実際のタップを先に求めたという意味で、クリック以外の操作で再生を開始したときに起こります。
見た目が崩れる
ページのCSSがプレーヤーに届いています。通常はそれが狙いですが、そうでない場合は data-obbo-isolate を追加して切り離してください。
それでも解決しない場合ページのアドレス、プレーヤーID、Obbo.version の値を添えてご連絡ください: hello@obbo.me