Macでテスト用のダミー画像やダミー動画を自動作成する

画像や動画を扱うサービスを開発していると、ダミーのテスト画像や動画が大量に必要になることってありますよね!

巷にはダミー画像を生成するサービスは複数あるのですが、動画の方は見当たりませんでした。 調べてみるとimagemagickで静止画を作成して、それをffmpegで動画にできるようなのでBashスクリプトで作ってみました。

スクリプトの紹介

Generate a dummy video or an image on macOS · GitHub

このスクリプトは動画と画像の両方を作成できます。 実際にスクリプトで作成した画像は以下の通りです。キャプションテキストと画像サイズが書き込まれるので、テスト実施時に画面をキャプチャすればエビデンスとして残せるかと思います。

生成した画像

動画の方は静止画を単純にループするようになっています(オプションで音声ファイルを指定すれば音もつけられます)。 また、動画の右上には残り秒数のカウントダウンも表示されます。

スクリプトを実行するにはimagemagickffmpegが必要です。Homebrewを入れていれば以下のコマンドでインストールできます。

brew install imagemagick ffmpeg

インストールできたら、以下のコマンドでスクリプトを試してみてください。

curl -Ls https://gist.github.com/ikoba/2852944738431d82ebffe6d9e407cc32/raw | bash -s -- -s 400x300  -t 10 -c テストケース1-1

カレントディレクトリに、横: 300px, 縦: 400pxで長さ10秒の動画が作成されると思います。

使用可能なオプションは以下の通りです。

options:
  -i, --image             generate an image
  -v, --video             generate a video (default)
  -s, --size <geometry>   specify width and height (default: 600x600)
  -c, --caption <text>    specity caption text (default: Test)
  -f, --font <name>       specify font name (default: "ヒラギノ角ゴシック-W3" or "Hiragino-Sans-W3")
  --list-fonts            list available fonts and exit
  --font-size <number>    specify font point size
                          (default: appropriate value depending on the size)
  --foreground <color>    specify caption text color (default: white)
  --background <color>    specify background color (default: gray)
                          examples of color formats:
                            'lime', '#0f0', '#00ff00', 'rgb(0,255,0)', 'rgb(0,100%,0)'
  --image-type <type>     specify image type (default: png)
  -a, --audio <file>      specify an audio file if you want to merge it with the video
  -t, --time <second>     specify video length in seconds (default: 15)
  -o, --out <directory>   specify output directory (default: working directory)
  -h, --help              show usage and exit

1度に複数のダミー動画を作成する

例えば以下のようにxargsコマンドを組み合わせれば複数の動画を作成できます。

seq 10 | xargs -I SEQ ./dummy -s 400x300 -t 10 -c テストケースSEQ

スクリプトを作ってみた感想

今回はエンジニアでない方も使用するので、RubyPythonなどがインストールされていない環境でも動作するようにBashスクリプトで作成しました(imagemagick, ffmpegはインストールしてもらう必要がありますが)。

書いてみた感想ですが、正直ちょっと辛いなと思いました。特にコマンドのオプションの取り扱いがRuby, Python, Goのように宣言的に書けず、また特殊な処理を必要とするので可読性が悪いです。他にも実行してみないとわからないような落とし穴がいくつかありました。

非エンジニア向けにも配布するという用途では、Go言語で作成したり、ツールを使ってRubyPythonをシングルバイナリにまとめたりした方が良いのかなと思いました。あとはCUIというのも非エンジニアにはハードルが高そうです。PythonGUIアプリを作れるFletを今度試してみたいと思います。

スクリプトを作成する上でVisual Studio Codeの以下の拡張が役に立ちました。未使用の変数や、ifに対するfiの忘れなどの間違い、また非推奨な書き方をした場合に警告してくれます。

marketplace.visualstudio.com

参考にした資料

GoogleのShellのスタイルガイドです。かなり参考になりました。

google.github.io

Bashのgetoptsでロングオプションを扱う方法が詳細に説明されています。

chitoku.jp

fish shellからVSCodeを簡単に開く

VSCodeでカレントディレクトリを開くときに毎回以下のコマンドを打っているが面倒くさい。

code .

c だけで開きたい。

ということでconfig.fishに以下の関数を追加した。

引数なしでcだけ打つとcode .を実行し、引数がある場合はcodeに引数を渡している。

function c
  set arg (string trim -- $argv)

  if string length -q -- $arg
    code $arg
  else
    code .
  end
end

お手軽にRuby Gemのコードを開いて編集し元に戻す

Gemのコードで発生するエラーの原因を調べたり、コードを動かしながら確認したいと思ったりした時にGemのコードを手軽に開いてbinding.bを仕込んでデバッグしたい。

bundle install --path vendor/bundle でGemをインストールしてデバッグするのが一般的なやり方なのかもしれないが、ちょっと面倒。

そんな時に簡単にGemを開いてデバッグできる方法があった。

Gemのコードを開く

bundle open <Gem Name>

このコマンドでGemのコードを開くことができる。 以下のどちらかの環境変数にエディタのパスを設定すれば、そのエディタで開くことができる。

  • EDITOR
  • BUNDLER_EDITOR

EDITORを設定するとGitのコミットメッセージの編集に使用するエディタも変わってしまうので、BUNDLER_EDITORに設定するのがおすすめ。

私はVSCodeを使用しているので、fish shellの設定ファイル config.fish に以下を指定している。

set -gx BUNDLER_EDITOR (which code)

bashを使っている人は .bash_profile に以下を指定すれば良さそう。

export BUNDLER_EDITOR=$(which code)

Bundlerで管理していないGemのコードを開きたい場合は?

gemにもサブコマンドopenがある。

gem open <Gem Name>

Gemのコードを元に戻す

Gemの複数の箇所にbinding.bbinding.pryを仕込んだ場合は元に戻すのが大変。 そんな時に便利なコマンドがある。

bundle pristine <Gem Name>

"pristine"は「手付かずの」という意味らしい。 <Gem Name>を指定しないで実行した場合は、Gemfileに記載のあるすべてのGemを元の状態に戻すことができる。

Bundlerで管理していないGemのコードを元に戻したい場合は?

openと同様にpristineもgemのサブコマンドにある。

gem pristine <Gem Name>

すべてのGemの状態を元に戻す場合は以下のコマンドを実行する。

gem pristine --all

mitmproxyでAndroid Studioのエミュレーター上で動作するアプリの通信内容を確認する

フリーのHTTPSプロキシツールであるmitmproxyでAndroid Studioエミュレーターの通信内容を確認できるようにする。

確認に使用したAndroid Studioのバージョンは以下の通り。

Android Studio Dolphin | 2021.3.1 Patch 1

1. mitmproxyのインストール

MacでHomebrewが入っている場合は以下のコマンドでインストールできる。

brew install mitmproxy

その他の環境でのインストールはこちら

インストールしたら以下のコマンドで起動する。

mitmproxy

2. プロキシ設定

Android StudioのPreferencesの Tools > Emulator で下の赤枠のチェックボックスのチェックを外す(これをしないとエミュレーターでプロキシ設定のメニューが表示されないため)。

次にエミュレーターを起動させ、[...] をクリックする。

Settings > Proxy を開いて以下の設定を行う。

  • Use Android HTTP proxy settings のチェックを外す。
  • Manual proxy configuration を選択して以下の内容を指定する。
項目
Host name PCのIPアドレス
Port number 8080

3. 証明書のインストール

エミュレーターのブラウザでmitm.itにアクセスする。

"If you can see this, traffic is not passing through mitmproxy." のようなメッセージが表示される場合は、プロキシ設定を見直す。

赤枠のAndroidの証明書をクリックする。

クリックすると証明書のインストール画面が表示される。

以下の内容で設定を行い、OKをクリックする(これで証明書がインストールされる)。

項目
Certificate name mitmproxy
Credential Use VPN and apps(デフォルトでOK)

4. コードの変更

Android 7以降はデフォルトではユーザー証明書は使用できない。そのため、アプリ側の設定を変更する。

  • ディレクトapp/src/main/res/xmlを作成する。
  • 上のディレクトリにnetwork_security_config.xmlという名前で以下の内容のXMLファイルを作成する。
<network-security-config>
    <debug-overrides>
        <trust-anchors>
            <!-- Additionally trust user added CAs -->
            <certificates src="user" />
        </trust-anchors>
    </debug-overrides>
</network-security-config>
  • app/manifests/AndroidManifest.xml (debug) のapplicationタグの中に以下のように属性android:networkSecurityConfig="@xml/network_security_config"を追加する。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.cookpad.android.storetv">

    <application android:networkSecurityConfig="@xml/network_security_config">
    <!-- 省略 -->
    </application>
</manifest>

上記の方法だとアプリごとに設定を変更する必要があるが、それを避ける方法もある(ここでは説明しない)。

5. ビルドして確認

ビルドしてエミュレーター上でアプリが立ち上がると、mitmproxyを起動しているターミナルで通信が確認できるようになっている。

サーバーのタイムゾーン設定ではまった話

最近、既存のRailsアプリをカスタマイズして別のインフラに載せ替えるという仕事をしているが、そこでインフラ初心者には解決が困難なタイムゾーン関連の問題が発生した。

なぜか想定より9時間ずれる

APIのレスポンスでdatetime型のカラムのデータが想定より9時間遅れて返ってきた。9時間といえばUTCJSTの時差に一致するので、どこかでタイムゾーンがおかしくなっていることはピンと来た。

コンソールでDBのデータを確認すると想定通りの時間になっているのでデータの問題ではなさそう。 Railsタイムゾーンの設定が間違っているかもしれないので調べてみた。

config.time_zone = 'Tokyo'
config.active_record.default_timezone = :local

うーん、検索したみたらこの設定で問題なさそう。

そうなるとサーバーの設定があやしそう。ということで

Rails.logger.info "⭐️Time.now: #{Time.now}"

みたいなログを仕込んでみると、案の定2022-11-28 14:43:39.893488 +0000 みたいにUTCになっていた。

TZ=Asia/Tokyoを指定してみる

サーバーのタイムゾーンは、TZ=Asia/Tokyoのように環境変数TZで指定するか、指定がなければ/etc/localtimeの設定が参照されるようだ。 TZ=Asia/Tokyoの指定がなかったので追加して再度確認したが状況は変わらず。万策尽きた。

原因はDockerイメージの作り方だった

有識者に相談したところ、Dockerfileでtzdataタイムゾーンデータ)をインストールする記述がないので、これが原因ではないかということだった。 以下のコードを追加したイメージを作成して動かしたところ無事に解決した。

RUN apt-get update \
  && apt-get install -y tzdata

tzdataがないとTZ=Asia/Tokyoと指定してもAsia/TokyoUTCから何時間の時差があるかわからないので、指定の意味が無かったというオチだった。

最低限のイメージをベースにサーバーイメージを構築していく場合は、色々と入っていると思ったものが入っていないので注意していきたい。

Kindleで購入した本をブクログにインポートする(Macユーザー向け)

ブクログは仮想的な本棚を作成したり、本のレビューやメモを残したりできるサービスです。 同様のサービスに読書メーターがありますが、こちらは読書メモを非公開にすることができず、また、1つの本に対して残せるメモの文字数が250文字に制限されるため、個人用に読書記録を残す用途としては「ブクログ」の方が適していそうです(ユーザー数は「読書メーター」の方が多いらしい)。

インポート手順

1. ターミナル.appの起動

アプリケーション > ユーティリティーにあるターミナル.appを起動します。

別のターミナルアプリを使用している方は、そちらで大丈夫です。

2. Kindle for Macの準備

Kindle for Macがインストール済みでない場合は、こちらからインストールしてください。

3. Kindleのキャッシュデータの生成

Kindle for Macを起動し、🔄をクリックしてライブラリを最新の状態に更新します。更新が完了したらアプリを終了します。

アプリを終了すると、Kindleで購入した本のXML形式のキャッシュデータKindleSyncMetadataCache.xmlが生成されます。

4. インポート用CSVファイルの作成

上の手順で生成されたXMLファイルを解析してインポート用のCSVを作成します。

ターミナルに以下のコマンドを貼り付けてEnterキーを押して実行します。

xmllint --xpath '//purchase_date[string-length(text()) > 0]/../ASIN | //purchase_date[string-length(text()) > 0]/../purchase_date' ~/Library/Application\ Support/Kindle/Cache/KindleSyncMetadataCache.xml | sed -E 's/<ASIN>([^<]+)<\/ASIN><purchase_date>([^<]+)<\/purchase_date>/\1 \2\n/g' | sort -k 2 | awk '{print "1," $1 ",,,,,,,,,"}' > ~/Downloads/import.csv

コマンドを実行すると、ダウンロードフォルダにインポート用のCSVファイルimport.csvが作成されます。

このファイルを開き、1列目に1、2列目に10桁のASINコードが出力されていれば正しく作成できています。

1,B009IXLHZ2,,,,,,,,,
1,B009IXKPVY,,,,,,,,,
1,B009IXASIE,,,,,,,,,
1,B009IXJVVO,,,,,,,,,
1,B009KSOWRU,,,,,,,,,

Send to Kindle等でインポートしたAmazonで購入していない書籍は、このCSVには含まれません。 購入した順番に並べ替えているので、インポートすると購入日時が新しいものが本棚の上に並びます。

5. ブクログにインポート

ブクログインポート画面で、上の手順で作成したCSVファイルimport.csvを指定してインポートを実行します。

インポート完了後に本棚画面に移動すると... 綺麗にインポートできました。以上で終了です。

ブクログの本棚