どくぴーの備忘録

真面目なことを書こうとするクソメガネのブログ。いつ投げ捨てられるのかは不明

いい写真を最速で共有する技術 〜DroidKaigi 2024本番運用編〜

どーも、どくぴーです。

2024/9/11〜2024/9/13にDroidKaigi 2024が開催されました。今年もスタッフとしてお手伝いをさせていただきました。

2024.droidkaigi.jp

今年も車を運転して物を運んだり、いろんなことをスタッフとしてもやってたなぁと思うんですが、当日会期中はカメラをもって会場内をあっちこっち歩き回っていました。
もっているカメラにやたらとデカいsomethingがひっついていたり、謎の様相を呈していたので見かけて不思議に思った方もいるのかな〜、とか思っていました。
スキマ時間を縫って以前から試していた写真共有フローも新しく開発し直し、「写真爆速上げるくんV3」が完成したのでその本番運用の機会でもありました。

そんなわけでこの記事は参加レポートの体をした下記記事の続編となります。

e10dokup.hateblo.jp

前提:写真爆速上げるくんV1について

上記記事でも言及しているtry! Swift Tokyo 2024でお手伝いに参加した際に運用した写真を高速にアップロードするシステムのことです。
ビューワとしてPHPを多少書いた程度で、実際はほとんどなにか手を加えることなくソニー製のアプリを使って写真を打ち上げる技術検証的な要素を多分に含んだものでした。

技術検証として運用した結果、やりたいフローを実現できはしたものの以下の問題が残っている状態でした。

  • スマホWi-Fiテザリングで運用している以上、以下の課題がある
    • カメラからスマホに送る時点で遅く、エラーによる欠損が発生する。送信時の画素数を小さくしていても耐えきれない場合もある
    • 常時Wi-Fiテザリングをしている以上、スマホ側のバッテリーが最後まで持たない
    • 参加者のWi-Fiテザリングと重なったり、会場Wi-Fiが強すぎるとそもそも通信が成り立たなくなる
  • 最大1000枚オーバーの写真から必要な写真を選ぶ運営サイドの負荷がある
    • 広報で使う写真を選ぶ、幕間のスライドショーに使うなど
    • フロントエンドがページング付きとはいえ単純な写真一覧だと、時系列で並んでいるだけでは満足ではない

というわけでこれらを解決するには…作るしかねえな!ということでDroidKaigi 2024での写真爆速上げるくんV3に繋がります。

余談:V2はどこに行ったのか

V2はKotlin Fest 2024でカメラマンとしてお手伝いしていたときのものです。
システムとしては何も変化していないんですが、アップロード用の機材がPixel 8から Sony PDT-FP1 のレンタル品に切り替わっています。

これにより、渋谷ならタイミングさえ良ければpovo 2.0との組み合わせで下り1Gbpsオーバーの5G回線と有線LAN接続による端末側への転送が可能になったことでV1での問題点であったWi-Fiテザリングによる課題が解決しました。

ちなみに、このタイミングで一緒にカメラマンをしていた @KeithYokoma さんにCanon EOS 5D Mark IVからSony Transfer & Tagging経由でのアップロードを試してもらったところ、メタデータを見ているのかエラーを出したので現状のシステムはSony専用であることが発覚しています。一応直接JPGファイルをアップロードすれば関係はないんですが、それをするとストレージとビューワへの負荷が大きいのであんまり取りたい策ではないという感じです。

写真爆速上げるくんV3、つくるぞ

機材方面を整える

毎年DroidKaigi直前に同じくスタッフの @satsukies と機材を増やす(謎の)文化があるのですが、今年はPDT-FP1になりました。V2での検証の結果、行けると判断したうえでの購入です。これが僕にとってのPixel 9です(?)
べ、別にα9IIIが値上げで更に買いにくくなった腹いせじゃないんだからね!(ちなみに @satsukies もなにか色々と買っていました)

カメラについてもいつもはα9IIとα7RIVを2台持ちし、登壇者のアップや遠景を撮り分けられるようにしていました。しかしPDT-FP1の有線接続が1台にしかできないこと、Sony Transfer & Taggingの転送待ち受けが有線接続 + Wi-Fiテザリングのような併用ができなさそうなことから今年はα9IIのみでの運用に変更し、レンズを付け替えるためにPeak Designのスリングでレンズを詰め込むことにしました。PCとかも持てるじゃんと言いながらあれこれ突っ込んだ結果、ほぼ使わなかったくせに開催2日後も右肩が激痛に苛まれているので反省しています。

ちなみにカメラ自体にはどうやってつけていたのかというと、PDT-FP1には背面に三脚用のネジ穴があるので、同じく三脚用のネジ穴があるSmallRig製のL字プレートを装着し、ネジで結合する形で装着しています。

システム方面を再開発する

設計が完了したタイミングでは8月も半ばに来ており、ここからFTPサーバのアップロードとかを調べる余裕がないし、サービスデプロイも学生の頃試した程度で調べながらになります。フロントエンドも新しく作るとなると2018年頃の知識しかないので調べながらです。ということで一旦FTPアップロードに関してはV1時代のものを流用することを決定しました。それにより、システム全体を眺めると以下のような構成になります。

これで見れる

なお、「写真爆速上げるくん」と英語で名前につけるのはシュールだったので、ここでプロジェクト名を考えました。Photospeedwayって名前をつけたんですが、これはDroidKaigi 2024の2日後に富士スピードウェイ世界耐久選手権というレースを見に行く予定があったので、それにちなんでつけています。実際スピードがほしいのもあるのでちょうどいいかなと。略称は元ネタにちなんでPSWとかPISCOとかですかね?

バックエンド編

せっかくAndroidアプリ作ってるんだし、Kotlin Multiplatformでサーバサイドを作るかぁと思ったんですが、ドキュメントもある程度は揃っていて、調べながらで進められるだろうとJVMでKtor + Exposedを使い開発することになりました。サーバーサイドKtor、エンドポイント定義のDSLがわかりやすくてだいぶとっつきやすいですね。

ktor.io

バックエンドとしては、とりあえずFTPサーバの情報を登録してイベントアルバムとしてDBに登録する機能、イベントアルバムDBのアクセス情報から写真一覧を返す機能、お気に入りに登録した写真を別のアルバムとして返却する機能を実装しました。お気に入り登録はV1の問題点である写真を選ぶ運営サイドの負荷削減を目的としたもので、イベントアルバムレベルで保持されることでそのアルバムを見ることになる人全員が同じお気に入りを確認することができます。なお、お気に入りから消す機能を作るのを忘れました。

また、Firebase Authenticationによる認証をイベントの登録機能にはかけており、指定された人だけがイベントの登録を行うことができます。時間の都合、新規登録画面などはなく、Firebaseのコンソール上で裏で登録をすることになりますが、今のところ広く公開されるサービスではないので多分大丈夫でしょう。

デプロイ先としてはGCPAWS…ではなく、依然使ったことのあるさくらのVPSを選択しました。ローカルと同じ感じで環境を立ち上げられたらいいなと思い、KtorのプロジェクトでビルドしたJARファイルやクレデンシャルをSCPなりでアップロードしたあと、Docker Composeを使って立ち上げるという感じです。Gitのプロジェクトクローンからのコマンドによるビルドがいいのかな〜とも思っていたのですが、実際に借りたVPSが2 Core/1GB RAMのものだったのでビルドを始めた瞬間にターミナルがうんともすんとも言わなくなってしまったので諦めました。さくらのVPSの管理画面で確認したらCPU使用率が100%にぺったりと1時間位張り付いていて「ごめんな…」と思わず声が出たのをよく覚えています。

なお、CORSのことを全く認識しておらず、このあとのフロントエンド開発中にひたすらKtorのCORS周りのドキュメントを読み漁ることになります。この辺はネイティブアプリメインだと認識しないので難しいですね。

ktor.io

フロントエンド編

(さっきと同じ書き出し)せっかくAndroidアプリ作ってるんだし、Kotlin Multiplatform(Kotlin/Wasm)でフロントエンドを作るかぁと思ったんですが、調べてみるとKotlin/WasmはSafari上ではまだサポートが怪しい(Wasm GCをサポートしていないみたい?)ので諦めました。いろんなフレームワークを調べてみたところ、Vue.jsがチュートリアルもわかりやすく、とっつきやすかったのでこれを使って先程のバックエンドにaxiosでAPIアクセスをしながら実装することを採用しました。ちょうど知り合いにVue.jsを推している人もいたので、わからなくなったら質問してみようかな〜と考えたのもあります。

実際にできたもの。ページングの動作確認を擬似的に10枚単位で行っていたのが災いし、運用当日に酷いバグに気づくことに

最終的にはGitHub Pagesでデプロイすることになるのですが、Vue.jsによる実装は先述のCORSの件に時間を割いた以外は比較的簡単に進められました。あんまりデザインに気を使ってる余裕がないのでVuetifyを使ってMaterial Designな感じで進めることができたのも大きいですね。Androidアプリと違ってViteによるオートリロードなどですぐ実装したものが確認できたりしたのが特に楽ちんでした。

vuetifyjs.com

Androidアプリ編

ここまで作ったらもう十分だったんですが、Androidアプリも作ってみようということで急遽クライアントアプリを開発することにしました。会場を歩きながらXアカウントで告知する、みたいなケースを想定すると、アプリから直接写真がダウンロードできるとすごく都合がいいな?と思ったので一旦作ってみた次第です。

実際にできたもの

設計的にはNavigation Compose、Material 3、ViewModel、Kotlin Flow、Dagger Hiltといった「今から新規にアプリを作るならどういう構成で作る?」みたいな面接っぽい質問に自分で回答するような気持ちで考えました。規模感的にマルチモジュールは採用しなかったんですが、ある程度馴染みのある構成だったこと、バックエンド、フロントエンドで慣れないものを触り続けてきたあとだと異様にスピード感をもって開発できました。やはりひとつある程度技術的に慣れのあるものをもっておくというのは良いですね。

いずれはスライドショー表示にも対応したいなと思い、このタイミングでAPIにもExifを解析して撮影情報を返すエンドポイントを増設し、全画面表示を出来るようにしてみました。意外とそれっぽいものができて嬉しかったです。

実際に動いたものの出来には満足だったんですが、画像の読み込みが少し不安定でリロードとか再起動をひたすらに繰り返していました。多分Coilのキャッシュ設定がミスっていたので、改善するならそこだったり、時間表示をkotlinx-datetimeのInstantで担っているので時間レベルでのフィルタリングを実装して読み込み数を減らす必要がありそうです。

このアプリは別の場所でとある形で再利用されることになったのですが、それについてはまた別のお話ということで。

最後に:DroidKaigi 2024でのV3本番運用を経て

基本的にはシステムは満足に動いてくれていました。幕間のスライドショーにも、Xの投稿にも「え、今の写真じゃんこれ」となる写真が沢山出せたので、カンファレンスカメラマンは良い写真を撮ってくれるけどすぐ出せないのでスマホによる撮影が結局必要、みたいな課題を解決できる良いものができたと僕も満足しています。自分が使って「便利じゃねえの」と思うものを仕事じゃない部分で作れて嬉しかったですね。

実際に起きた不具合や写真絡みのイベントもいくつかあったので、それは箇条書きにしておきます。

  • 初日の夜にシステムが最新100枚までしか表示してくれない不具合に気づいた
    • FTPアップロード側を流用したのにそっちがデフォルトで100枚ずつしか返さない仕様だったことを忘れていた
    • ページングの動作確認を擬似的に10枚単位で行っていたので気づいていなかった
    • FTPアップロード側のファイル数制限処理を消して再デプロイし直したら解決した
  • 4部屋のセッションを撮って、Xに投稿できる準備をして、会場を撮り歩いて…とやっていると時間がギリギリだった
  • とあるタイミングで写真がアップロードされないな?と思ったら、JPG側のSDカードが不調になってJPGが全部こわれていた
    • RAWは別のSDカードに保存していたので致命傷ではないが、SDカードのフォーマットを現地ですることになった。SDカードはちまちま買い替えよう!
  • 知り合いを含め参加者の方に「その…なんだ?その…、スマホ…?」と不思議な顔をされる。Sony PDT-FP1がXPERIAベースの端末なので、とにかくでかい

また、現状のシステムの改善点もいくつかあり、以下の改善をしてどこかでV4を運用したいですね。

  • 1イベントで大量にアップロードするとシステムがうんともすんとも言わなくなる
  • FTPアップロード自体をAPIサーバ側に統合する
    • FTPアップロード先を外部にする設計は柔軟だが、正直少し大きめなサーバを借りてそこで管理してしまう方が安上がりだと思った
    • なぜかアプリに至ってはAPIサーバをホストとして選べるようにしていたので、RetrofitのAPI記述が全部おかしなことになっている
      • APIサーバ自体はワンショットで立ち上げられるので誰が立ち上げたサーバでも使えるように…みたいな気の利かせをしたけど、よく考えたら使わなさそう
  • スライドショー表示を作る
    • 幕間などのスライドショーに載せるために、例えば現状ダウンロード -> Google Slidesなどに手で配置 -> 更新といった作業が発生している
    • お気に入りに入れた画像をベースにランダムにスライドショーをさせて、会場内での連絡事項なども画像で入稿してもらいつつ、別途で載せれるAPIを作れたら多分幕間としては完全なものが用意できそう
  • お気に入りのカテゴリを分けれるようにする
    • 「あのシーンの写真、ある?」という要望が出るとお気に入りに入れたかどうかすら不明でずっと探していたので、ユースケースとして漏れていたっぽい
    • というか撮っている側も「あのシーンあったっけ」って大体覚えていないので、チェックリストとして機能しそう
  • FTPアップロードアプリを作る
    • AndroidアプリにFTPサーバを立ち上げる方法は調べたらでてきそう。Play Storeを見ていると実際にそれをやっているアプリも存在はしている。
    • Sony Transfer & Taggingで出来ることを他メーカー製のアプリでも出来るように再実装すれば、「FTPアップロード機能があるカメラをもっている人」に対象範囲を広げられる。
    • なんならサービスに打ち上げなくてもそのアプリ内で処理できるだけで嬉しいかも

DroidKaigi 2024のスタッフや会社のお仕事も忙しい時期で大変でしたが、余暇(?)に久々に面白い個人開発ができました。とっても楽しかったです。 しばらくは積んでいたゲームなどを消化しながら、ゆっくり過ごそうと思います。ありがとうございました ( ˘ω˘)スヤァ