0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

(AIの無駄遣い?)スライドにニコニコ動画風の流れるコメントを乗せるWebアプリを作った(PowerPoint対応・OIDCキーレス)

0
Posted at

はじめに

LTスライドの上を、ニコニコ動画みたいにコメントが流れたら盛り上がる ── そんな思いつきから、既存の .pptx にコメントを乗せるWebアプリを作りました。

メイン画面

何ができるか

  1. .pptx をアップロード
  2. コメントを流すスライドを番号で指定(all / 1,3,5-7
  3. コメントを色付きで入力、流れる速さなどを調整
  4. 「生成」を押すと、コメント入りの .pptx がダウンロードできる

PowerPoint / Keynote のスライドショーで再生すると、コメントが右から左へ流れます。

最初の難関:PowerPointでアニメをどう実現するか

最初はPowerPointの**ネイティブのアニメーション(モーションパス)**で実現しようとしました。テキストボックスを右から左へ動かすXMLを python-pptx で直接書き込む方法です。

しかしこれは3回続けて失敗しました。

  • 1回目:全コメントが中央に重なって表示されただけ(初期位置の設定ミス)
  • 2回目:スライドショーで何も流れずフリーズ
  • 3回目:PowerPointが「コンテンツに問題があります」と表示し、修復=アニメ部分を削除

原因は、手書きしたアニメーションXMLがPowerPointのスキーマに合っていなかったこと。そして何より、自分の環境ではアニメの再生を検証できないまま渡していたことでした。検証できないものを「動くはず」で出してはいけない、という当たり前の教訓です。

解決策:透過アニメGIFを重ねる

方針を変えて、コメントが流れる透過アニメGIFを生成し、スライドの上に全面で重ねることにしました。

  • PowerPoint / Keynote は、スライドショー時にアニメGIFを自動再生する(標準機能)
  • GIFなら自分でフレームを抽出して動作確認できる(検証できる)
  • アニメーションXMLのスキーマ問題から解放される

GIFの生成は Pillow で、1フレームずつコメントを描画していくだけです。

for f in range(n_frames):
    t = f / fps
    img = Image.new("RGBA", (width, height), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    for it in items:
        x = width - speed * (t - it["start"])  # 右→左へ
        d.text((x, it["y"]), it["text"], font=font,
               fill=it["color"], stroke_width=stroke, stroke_fill=(0,0,0,255))
    # 透過パレット化してフレーム追加

あとは python-pptxadd_picture で、各スライドの全面にGIFを置くだけでした。
pptxへの変更は
「Content_Types へのGIF登録」
「media にGIF追加」
「rels に関連付け」
「slideXML に <p:pic> 追加」
の4箇所だけと判明。
ブラウザでもサーバーでも再現できます。

Webアプリ化と構成

CLIツールをWebアプリにするにあたり、こんな構成にしました。

構成図

  • フロント(Next.js / Vercel)
     pptxの解析(JSZip)とライブプレビュー(Canvas)はブラウザ内で完結。スライドの中身を外部に送らずにプレビューできる
  • バックエンド(AWS Lambda・東京リージョン)
     重いGIF生成は Pillow + python-pptx のコンテナLambdaで。日本語フォントは Noto Sans JP を同梱
  • ストレージ(S3)
     アップロードは署名付きPUTで直接S3へ。Vercel/Lambdaのペイロード制限を回避し、大きめのpptxにも対応。
    入出力は24時間で自動削除

キーレス:Vercel OIDC Federation

当初は Lambda Function URL を公開してフロントから直接叩く予定でしたが、利用環境のガードレールで公開アクセスがブロックされていました。

そこで Vercel OIDC Federation に切り替えました。
これは、Vercelの関数に発行されるOIDCトークンで、AWSのIAMロールを AssumeRoleWithWebIdentity し、短期間の認証情報でLambdaを呼びます。
「長期的なアクセスキーをどこにも保存しない」のが利点です。

import { awsCredentialsProvider } from "@vercel/oidc-aws-credentials-provider";

const lambda = new LambdaClient({
  region: "ap-northeast-1",
  credentials: awsCredentialsProvider({ roleArn: process.env.AWS_ROLE_ARN }),
});

AWS側には、Vercelの発行者URL(https://oidc.vercel.com/<team>)をOIDCプロバイダとして登録し、IAMロールの信頼ポリシーで「特定プロジェクトの本番環境」だけに絞ります。

権利への配慮

ニコニコ動画の「コメントが動画上を流れる機能(コメント配信システム)」については、運営会社が特許を保有しているとされています。

本ツールがしているのは、
スライドにあらかじめ用意したコメントを演出として流すこと
であり、各コメントは透過GIFとしてスライドに埋め込まれ、ネットワークを介さずローカルで完結します。
「不特定多数がネット経由で投稿し、サーバーを経由してリアルタイムに同期して流れる配信システム」
とは構成が異なります。

ただし用途によって判断は変わるため、商用・配信用途では各自で権利関係を確認すべきですし、
生配信などでリアルタイムに届いたコメントを同期表示する用途は想定していません
アプリ内にもこの注記ページを置いています。

まとめ

  • PowerPointでアニメを「確実に」動かすなら、ネイティブアニメよりアニメGIFを重ねる方が堅実だった
  • 「自分で検証できる方式」を選ぶのが結局いちばん速い
  • Vercel OIDCでキーレスにAWSへつなげるのは、個人開発でも嬉しい

最後まで読んでいただきありがとうございました。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?