【Ubuntu】PWAでインストールしたアプリをコマンドラインで呼び出せるようにする【PWA】

# 発端
Google driveとかコマンド一発で呼び出せると良くね？

# 調べてみた！
## PWAとしてインストールするとデスクトップにアイコンが作られるけど……
結論から言うとUbuntuでは `~/.local/share/applications/*.desktop` に色々あります
本筋から外れますが、ここにdesktopファイルを作っておくとお気に入りとしてDockに登録可能になります

## よし、desktopファイルがあるのはわかった！
PWAでインストールしたアプリのdesktopファイルは基本的に以下のようになっているようです

所定の場所 ( `.local/share/appllications` ) に `chrome-[APP-ID]-[PROFILE].desktop` という名前で作られているようです

```ini:~/.local/share/applications/chrome-abnfpfhjmipcnaibcolbacfhgfcmjjbn-Default.desktop
#!/usr/bin/env xdg-open
[Desktop Entry]
Version=1.0
Terminal=false
Type=Application
Name=Microsoft OneDrive
Exec=/opt/google/chrome/google-chrome --profile-directory=Default --app-id=abnfpfhjmipcnaibcolbacfhgfcmjjbn
Icon=chrome-abnfpfhjmipcnaibcolbacfhgfcmjjbn-Default
StartupWMClass=crx_abnfpfhjmipcnaibcolbacfhgfcmjjbn
```

`Name` は manifest.json の `name` 項目の値となっていそうです
`Exec` が実際のブラウザの呼び出しとなります

つまりここを抽出してシェルスクリプトにするなりすればコマンド呼び出しで実行することが可能になりそうです

`app-id` が振られてブラウザが管理してるんでしょうね
この辺は余力があれば調べてみたいです

# コマンド化するためのスクリプトを作るよ！

## 作ったシェルスクリプト
```bash:~/bin/pwa2cmd
#!/usr/bin/bash

CHROME=~/bin/google-chrome

NUM=1

IFS=$'\n'
for LINE in $(grep -lr "app-id" ~/.local/share/applications/ | xargs grep Name); do
  NAME[$NUM]=$(echo $LINE | sed -e 's/.*\.desktop:Name=//')
  FILE[$NUM]="$(echo $LINE | sed -e 's/\(.*.desktop\):.*/\1/')"
  echo $NUM ${NAME[$NUM]}
  NUM=$(( $NUM + 1 ))
done

echo
echo -n "アプリを選択してください> "
read INPUT_NUM

if [ -z "${FILE[$INPUT_NUM]}" ]; then
  echo "有効なアプリが見つかりません"
  exit 1
fi

echo "${NAME[$INPUT_NUM]}"

echo
echo -n "保存するコマンド名を入力してください> ~/bin/"
read INPUT_CMD

if [ -z "${INPUT_CMD}" ]; then
  echo "コマンド名が入力されていません"
  exit 2
fi

INPUT_CMD=~/bin/"${INPUT_CMD}"

if [ -e "${INPUT_CMD}" ]; then
  echo "既に存在するコマンドです"
  exit 3
fi

COMMAND_LINE=$(grep -m1 Exec "${FILE[$INPUT_NUM]}" | sed -e 's/^Exec=//')

if [ ! -z "$CHROME" ]; then
  COMMAND_LINE=$(echo -n "${CHROME} "; echo "${COMMAND_LINE}" | cut -d ' ' -f 2-)
fi

echo "#!/usr/bin/bash

$COMMAND_LINE > /dev/null 2>&1 &" > "${INPUT_CMD}"
chmod 755 "${INPUT_CMD}"

echo ${INPUT_CMD} を作成しました
```

## 使い方
`pwa2cmd` を実行するとPWAでインストールされているアプリ一覧が表示されます
番号が振られているので、コマンドに落としたい番号を入力します
次に `~/bin` 以下に保存するコマンド名を入力して完了です

これで `~/bin` にパスが通っていれば任意の場所から上記で入力したコマンド名を打つことでPWAのアプリを立ち上げることが可能になりました

## スクリプトの解説
```bash
CHROME=~/bin/google-chrome
```
ここは僕の環境ではchromeの呼び出しをラッパーのスクリプト経由で行っているためなので、特別な理由がなければ空で問題ないです

```bash
NUM=1
```
変数の初期化

```bash
IFS=$'\n'
for LINE in $(grep -lr "app-id" ~/.local/share/applications/ | xargs grep Name); do
  NAME[$NUM]=$(echo $LINE | sed -e 's/.*\.desktop:Name=//')
  FILE[$NUM]="$(echo $LINE | sed -e 's/\(.*.desktop\):.*/\1/')"
  echo $NUM ${NAME[$NUM]}
  NUM=$(( $NUM + 1 ))
done
```
最初パイプでwhileに食わせたらサブシェル立ち上がるのでwhile内でセットした変数取り出せない罠にはまりました
`IFS=$'\n'` で区切り文字を改行文字としてforで1行ずつ処理するようにしてあります
これがないとスペースが区切り文字として扱われるので1行ずつの処理が出来ません

`grep -lr "app-id" ~/.local/share/applications/` で `~/.local/share/applications/` 以下にある `app-id` を含むファイル名を列挙します
これを xargs に渡し、そこで各ファイルの `Name` 項目の行を抽出します

ループの中を見ていきましょう
```bash
  NAME[$NUM]=$(echo $LINE | sed -e 's/.*\.desktop:Name=//')
```
ここは後で数値を入力した際にNameを表示するために配列にNameの値を格納しています
```bash
FILE[$NUM]="$(echo $LINE | sed -e 's/\(.*.desktop\):.*/\1/')"
```
ここはファイルパスを保存していきます
あとでこのパスからExecの項目を抽出することになります
```bash
echo $NUM ${NAME[$NUM]}
```
コンソールに番号と対応するNameの値を表示します
```bash
  NUM=$(( $NUM + 1 ))
```
インクリメントします

```bash
echo
echo -n "アプリを選択してください> "
read INPUT_NUM

if [ -z "${FILE[$INPUT_NUM]}" ]; then
  echo "有効なアプリが見つかりません"
  exit 1
fi

echo "${NAME[$INPUT_NUM]}"
```
`read INPUT_NUM` で標準入力から読み取った値をINPUT_NUMに保存します
FILE配列からINPUT_NUMに該当する項目が存在しない場合はエラーメッセージを表示して終了します
項目があれば入力が間違っていないか確認のために選択したNameの値を表示します
```bash
echo
echo -n "保存するコマンド名を入力してください> ~/bin/"
read INPUT_CMD

if [ -z "${INPUT_CMD}" ]; then
  echo "コマンド名が入力されていません"
  exit 2
fi

INPUT_CMD=~/bin/"${INPUT_CMD}"

if [ -e "${INPUT_CMD}" ]; then
  echo "既に存在するコマンドです"
  exit 3
fi
```
`read INPUT_CMD` で標準入力から保存するコマンド名をINPUT_CMDに保存します
コマンドが入力されない場合はエラーメッセージを表示して終了します
すでに存在するコマンド名の場合はエラーメッセージを表示して終了します

雑に保存先は `~/bin` 以下に固定しています

```bash
COMMAND_LINE=$(grep -m1 Exec "${FILE[$INPUT_NUM]}" | sed -e 's/^Exec=//')

if [ ! -z "$CHROME" ]; then
  COMMAND_LINE=$(echo -n "${CHROME} "; echo "${COMMAND_LINE}" | cut -d ' ' -f 2-)
fi
```
Execの値からコマンドラインを抽出します
冒頭のCHROME変数がセットされている場合はchromeコマンドの差し替えをします

なお、YouTubeのPWAなどは複数のExecがありますが、最初の物だけ拾うようにしています

```bash
echo "#!/usr/bin/bash

$COMMAND_LINE > /dev/null 2>&1 &" > "${INPUT_CMD}"
chmod 755 "${INPUT_CMD}"

echo ${INPUT_CMD} を作成しました
```
シェルスクリトとしてCOMMAND_LINEを実行する形でファイルを生成します
実行権限を付与します

以上

# そもそも
Google driveはPWA化してたか？

次回に続く……！

https://qiita.com/m-m-n/items/8c3a6385627284fa9ee0

---

それでは良いLinuxライフを。