rch850 の上澄み

技術的な話題とか、雑談とか。タイトルを上澄みに変えました @ 2020/09/02

生産管理部業務効率課進捗課長で MA 2nd 進出決めました

Mashup Award の福井ハッカソン予選で「生産管理部業務効率課 進捗課長」という作品を作り、最優秀賞を取り、2nd Stage 進出が決まりました。やった!先にソフトバンクロボティクス賞で名前が呼ばれたときは、あ、これ最優秀逃したかなーと思ったのですが、まさかのダブル受賞でした。

イベントの状況は公式のレポートに譲るとして、ここには自分がやったことなどを書いておきます。

自分が担当したのは、Pepper が録画、録音したデータを結合して、ハイライト動画、音声を作るところです。発表スライドの役割分担書く時に「自分は映像クリエイターで」って答えたら、他のメンバーもそれっぽい役割名で書く流れになってしまいました。

Pepper での録画、録音

Record Video ボックスで録画、Record Sound ボックスで録音しました。実際のコーディング、というかコレグラフでのボックスの配置は @pittanko_pta にやってもらいました。

動画と音声の結合

3人分の動画、音声を 1.avi、2.avi、3.avi といった名前で保存したので、それを結合しました。動画、音声の操作といえば ffmpeg。Pepper の内部で ffmpeg を叩けることが分かったので、別サーバに投げたりすることなく処理ができました。動画も音声も、結合には ffmpeg -f concat を使いました。なお出力形式は動画は mp4、音声は wav にしました。

結合した音声には ffmpeg -y -i sound_tmp.wav -i bgm.wav -filter_complex amerge -ac 2 -q:a 4 sound.wav といったコマンドで BGM もつけました。

映像と音声をくっつけず別々にしてる理由はすぐあとで書きます。

Pepper での動画、音声の再生

Play Video ボックスで動画を、Play Sound ボックスで音声を再生しました。最初は音声がついた動画を Play Video で再生するだけでいいと考えたのですが「Pepper 動画 音声」で調べたところ動画に音声を乗せるとノイズが入ることがあるという話を見かけたので、デモでの成功率を考えて個別に扱うことにしました。こちらもボックスの配置は @pittanko_pta の担当だったのですが、中身の調査は自分がやりました。

中身の調査というのは、作成した動画をどうやったら Play Video で再生できるのかという話です。ボックスのコードを読んだところ、ローカルのファイルは "http://%s/apps/%s" % (self.tabletService.robotIp(), subpath.replace(os.path.sep, "/")) といった形の URL で読み込んでいるようで、この apps は一体どこなのかを探す必要がありました。Pepper の中身を ps コマンドで見たところ、http サーバは nginx だったので、/etc/nginx/nginx.conf を見て apps が /opt/aldebaran/www/apps を指していることがわかりました。というわけで再生する動画はそのパスに置くことにしました。たしか nao ユーザーで書き込める場所だったはずです。Pepper の中に ssh できるのは便利ですね。

Play Sound のほうは普通にパスを指定すれば再生できたので、特に困りませんでした。

Play Video と Play Sound を同時に動かすと、Play Video のほうが数秒遅れて再生が始まるので、絶妙なウェイトを入れて同時に再生されるような工夫もしています。

まとめ

以上が映像クリエイターの仕事でした。ハイライト動画にイントロを付けたいとか、テロップを入れたいとか、いろいろやりたいことがあるので、今後もネタに困ることはなさそうです。

Angular の routerLink でクエリパラメータを指定する

Angular 4.2.2 の話です。

<a routerLink="/foo?bar=10">link</a>

のように routerLink にクエリパラメータを直接指定すると Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'foo%3Fbar%3D10' といったエラーが出ます。

RouterLink のリファレンスにあるように [queryParams] にオブジェクトを指定すれば動作するようになります。

<a routerLink="/foo" [queryParams]='{ bar: 10 }'>link</a>

routerLink がダメなら href で……というのも試してみたのですが、これだと遷移するにはするのですが、ページ全体の再読込がかかってしまいました。

<a href="/foo?bar=10">link</a>

基本的にはちゃんと動く書き方をすればいいのですが、ウェブ API から受け取ったリンク先に遷移させたい場合は、API から受け取った文字列をパースして routerLinkqueryParams に設定するといった実装が必要になってきます。これは手間です。このあたりを賢くやってくれる方法があればいいのですが。

Chrome 59 で window.open の挙動が変わった

JavaScript で新しいウィンドウを開くため、このようなコードを書いていたのですが、Chrome 59 になってから新しいタブで開くようになってしまいました。

window.open('http://example.com/', '_blank', 'width=640, height=480, location=yes')

window.open の第3引数 feature から、アドレスバーを表示するためのオプション location=yes を取り除くことで、タブではなくウィンドウで開くようになりました。

window.open('http://example.com/', '_blank', 'width=640, height=480')

こうなった原因を探るため Chrome 59 のコミットログwindow.open で検索したところ window.open() should gate new tab/new popup based on toolbar visibility. (e507bb3) が関係してそうでした。

window.open() should gate new tab/new popup based on toolbar visibility.

Previously, Chrome required that toolbar, menubar, scrollbars, status, resizable were all set to enabled to open a window as a new tab rather than a new popup. However, this causes developer frustration if one of window features is accidentally omitted (as it then defaults to disabled).

Instead, just use toolbar visibility to determine whether or not window.open() creates a new popup or a new tab, which matches Firefox.

なるほど。toolbar についても調べたところ、確かに設定次第でポップアップかどうかが変わりました。

// 新しいタブになる
window.open('http://example.com/', '_blank', 'width=640, height=480, toolbar=yes')

// 新しいウィンドウ(ポップアップ)になる
window.open('http://example.com/', '_blank', 'width=640, height=480, toolbar=no')
window.open('http://example.com/', '_blank', 'width=640, height=480')

Chrome 59 のソースを調べたことのメモ

どこかに location を toolbar として見るコードがあるはずですが、見つけられませんでした。


(6月20日追記)

location=yes の有無でどうなるか、IE 11, Edge, 14, Chrome 59, Firefox 54 で動作確認しました。

codepen.io

結果はリンク先を見ての通りですが、特に挙動が違ったところとして IE 11 だけ location=yes の時にアドレスバーの中身を編集できました。

oEmbed の height null について

きっかけは mastodon の URL 貼り付けを確認してたときにびろーんと伸びてしまうのに気づいたこと。

friends.nico

引用ここまで。めっちゃ改行入れてるわけじゃなくて、ここまでびろーんって伸びちゃってるんです。

逆に、長いトゥートは途切れてしまう。

pawoo.net

なぜこうなるか mastodon のコードを追ってみた。対象はタグ v1.3.2 のもの。

oEmbed の実装は oembed_controller.rb にあって、特別な指定がなければ height が 640 となる。

  def show
    @stream_entry = stream_entry_from_url(params[:url])
    @width        = params[:maxwidth].present?  ? params[:maxwidth].to_i  : 400
    @height       = params[:maxheight].present? ? params[:maxheight].to_i : 600
  end

https://github.com/tootsuite/mastodon/blob/v1.3.2/app/controllers/api/oembed_controller.rb#L9

height というのは oEmbed の仕様にあって rich タイプでは必須となっている。

height (required)

The height in pixels required to display the HTML.

この高さが 640 と固定されているので、びろーんと伸びてしまったり、途切れてしまったりするわけだ。

Twitter がどうしているか調べてみたら、height には null が入っていた。instagram も同様に null だった。

じゃぁ mastodon でも null 返せばいいのか?ってことで、自分の mastodon インスタンスで show メソッドを書き換えて null になるようにしたら、いい感じにフィットするようになった。

mastodon.850mb.net

なるにはなったけど required って明記されているものに対して null を返すのはちょっと抵抗あるなー。本家に PR 出しても苦い顔されそうだし、自分がその立場なら苦い顔しそう。

なお今回の調査では iframely のデバッガにとてもお世話になりました。

(5/9 追記) 出すだけ出してみようってことで PR 出したらすぐマージされましたとさ。ウワサには聞いてたけど対応速かった!

github.com

トゥート!の埋め込み

f:id:rch850:20170421003214p:plain

oEmbed 対応してるみたい。

f:id:rch850:20170421003609p:plain

なんか不格好なのは iframe の height が 600 もあるからかな。

$ curl "https://friends.nico/api/oembed.json?url=https%3A%2F%2Ffriends.nico%2Fusers%2Frch850%2Fupdates%2F48866"
{"type":"rich","version":"1.0","title":"New status by rch850","author_name":"りちゃ","author_url":"https://friends.nico/users/rch850","provider_name":"friends.nico","provider_url":"https://friends.nico/","cache_age":86400,"html":"<iframe src=\"https://friends.nico/users/rch850/updates/48866/embed\" style=\"width: 100%; overflow: hidden\" frameborder=\"0\" width=\"400\" height=\"600\" scrolling=\"no\"></iframe>","width":400,"height":600}

コミットメッセージの Emoji Prefix の虫をやめた話

git とかのコミットメッセージで 👍 ほげを実装しました とか 🆙 ほげパッケージを 1.2.3 にアップデート みたいに書くのあるじゃないですか。

memo.goodpatch.co

好きで結構使ってるんですが、バグの絵文字だけは虫を使ってません。

虫の絵文字って、だいたいは芋虫みたいなやつだと思うんですが、こいつが Gmail に入ってくるとあいつに化けるんです。

f:id:rch850:20170408122603p:plain:w200

大変不愉快なのでモザイクをかけてます。気になる方はご自分の Gmail アドレス宛に虫の絵文字を送りつけてみてください。あと Emojipedia にもあったので、勇気のある方はこちらからどうぞ。拡大してみると Google 以外もなかなか強烈……

虫をやめてどうしたかというと、救急車にしました。

f:id:rch850:20170408122927p:plain:w200

個人的には Gmail 上での虫の表現がぞわぞわしたので、それが無くなってよかったのですが、「実は虫自体が苦手でした」って人もいて、この変更は好評でした。

Happy git life!!

ふくもく会その26

午前中はウェアラブル/VRセミナー&アイデアソンで進行などをして、お昼食べに行って、午後2時半からの参加でした。

何やるか全然決めてなかったんで、若干の圧を発してたら、やること共有の発表順がラストになりました。やったぜ。Python 画像処理の勉強しますとか、webpack プラグインのメンテしますという話を聞いてたら、Python のパッケージ公開でもやってみるかという気分になりました。npm も gem も公開したことはあるんですが、Python はやったことなかったので。

りちゃ on Twitter: "できあがったもの ahg48 0.1.3 : Python Package Index https://t.co/YXWE4492DM #ふくもく会"

Packaging and Distributing Projects がしっかり書いてあるので、これに従えばほぼ大丈夫かと。バージョンが 0.1.3 になってるのは、最初に野良記事を参考にやって long_description を README から読み出すのに失敗したりしていたからです。今後は CI かますなどしようかなと思います。

他には @kotobuki555ing中京テレビハッカソンの報告を聞いたりしてました。コンスタントに受賞しててすごい。ハッカソン中やアイデアソンとハッカソンの間の平日に、たくさんインタビューがあったそうです。テレビ局すごい。

次回はたぶん4月29日です。