TrueNAS で Jpsonic を動かしてみた

# はじめに

TrueNAS (旧：FreeNAS) に Jpsonic を導入するだけの記事です。
参考にしたこちらの記事から日が経っていることで結構方法変えなきゃ行けなかったので記事にしてみました。
[Qiita:FreeNAS 11.2でJpsonicを使ってみた](https://qiita.com/cs133/items/f344f33017397dc5353e)

# 手順

リンク先の記事にもありますがJpsonicはプラグインがないため手動でJailを作成する必要があります。手順としては以下の通りとなります。
※Jailの作成やMountpointの設定は変わりないのでここでは説明しません。

1. Jpsonicの導入
2. Jpsonicのサービス登録

## Jpsonicの導入

[公式サイト](https://tesshu.com/) ではairsonicと同じ手順でできるそうだけど、tomcatベースのセットアップだとうまく行かなかったので、Standaloneモードでセットアップする。

先に明かすと下記のサイトの説明通りで一部変更するだけで導入できます。
https://danschmid.de/en/blog/install-airsonic-on-freebsd
変更点は次の通り

- 使用するJpsonicは"jetty-embed"版を用いる
- すべての"airsonic"を"jpsonic"に置き換え（"Airsonic"と大文字の方も同様に置換）
- rc.confの"LANG"設定は"ja_JP.UTF-8"に変更

これで特に難しいことなくjpsonicをTrueNASで使用できました。

## ソフトウェアの導入

まず、openjdk11とffmpegを導入する。（openjdk8だとバージョンが古く怒られる）

```
root# pkg install openjdk11 ffmpeg sudo
```

## ディレクトリ、ユーザーの作成

### Jpsonic用ディレクトリの作成
先のサイトの手順に則りディレクトリを作成します。

```
root# mkdir /var/jpsonic/
root# mkdir /var/jpsonic/transcode
root# mkdir /usr/local/jpsonic
root# cd /usr/local/jpsonic
```

### Jpsonic用ユーザーの作成
rootでJpsonicを起動すると特権で動作している警告がでるため、アプリケーションユーザーを作成します。

```
root# adduser
Username: jpsonic
Full name: jpsonic
Uid (Leave empty for default):
Login group [jpsonic]:
Login group is jpsonic. Invite jetty into other groups? []:
Login class [default]:
Shell (sh csh tcsh bash rbash nologin) [sh]: 
Home directory [/home/jpsonic]: /usr/local/jpsonic
Home directory permissions (Leave empty for default):
Use password-based authentication? [yes]: no
Username   : jpsonic
Password   : *****
Full Name  : jpsonic
Uid        : 1001
Class      :
Groups     : jpsonic
Home       : /usr/local/jpsonic
Home Mode  :
Shell      : sh
Locked     : no
OK? (yes/no): yes
adduser: INFO: Successfully added (jpsonic) to the user database.
Add another user? (yes/no): no
Goodbye!
```

## Jpsonicの導入

Jpsonicをダウンロードし、jpsonic作業ディレクトリに設置する。

```
root# wget https://github.com/jpsonic/jpsonic/releases/download/v109.5.0/jpsonic-jetty-embed.war
root# mv jpsonic-jetty-embed.war jpsonic.war
```

最新版のダウンロードはGithubのReleaseから確認する。 [Github](https://github.com/jpsonic/jpsonic/releases)
ダウンロードするパッケージは"jetty-embeded"版を落とす。

次に、ffmpegをJpsonicで認識できるようにシンボリックリンクを貼る。

```sh
root# ln -s /usr/local/bin/ffmpeg /var/jpsonic/transcode/ffmpeg
```

ここまできたら、Jpsonicが起動できるかテストする。（http://任意のアドレス:8080でアクセスできるはず）

```sh
root# chown -R jpsonic:jpsonic /var/jpsonic /usr/local/jpsonic
root# sudo -u jpsonic /usr/local/bin/java -jar /usr/local/jpsonic/jpsonic.war
```

うまく起動したらCtrl-Cで停止する。

## 起動スクリプトの作成

最後に[こちら](https://danschmid.de/en/blog/install-airsonic-on-freebsd)のサイトを参考にし次の変更を施した起動スクリプトを作成する。

- airsonic を jpsonic に置換
- ロケールを "en_US.UTF-8" から "ja_JP.UTF-8" に変更
- 起動ユーザーを "root" から "jpsonic" に変更

```sh
root# vi /etc/rc.d/jpsonic
```

```sh
#!/bin/sh
#
# $FreeBSD: jpsonic $
#
# PROVIDE: jpsonic REQUIRE: LOGIN KEYWORD: shutdown
#
# Configuration settings for jpsonic in /etc/rc.conf:
#
# jpsonic_enable (bool):
# Set to "NO" by default. Set it to "YES" to enable jpsonic.
#
# jpsonic_home (str):
# Set to "/var/jpsonic" by default.
#
# jpsonic_host (str):
# Set to "0.0.0.0" by default. Specify which IP address to listen to.
#
# jpsonic_port (int):
# Set to "4040" by default. Specify which port to listen on for HTTP(S).
#
# jpsonic_context_path (str):
# Set to "/" by default. Specify the last part of the jpsonic URL, typically "/" or "/jpsonic".
#
# jpsonic_init_memory (int):
# Set to "192" by default. Specify the memory initial size (Java heap size) in megabytes.
#
# jpsonic_max_memory (int):
# Set to "384" by default. Specify the memory limit (Java heap size) in megabytes.
#

. /etc/rc.subr

export LANG=ja_JP.UTF-8

name=jpsonic

desc="Jpsonic is a free, web-based media streamer, providing ubiquitous access to your music"

rcvar=${name}_enable

pidfile="/var/run/${name}.pid"

load_rc_config "${name}"

: ${jpsonic_enable:="NO"}
: ${jpsonic_user:="jpsonic"} #: ${jpsonic_user:="media"}
: ${jpsonic_group:="wheel"} #: ${jpsonic_group:="media"}
: ${jpsonic_home:="/var/jpsonic"}
: ${jpsonic_address:="0.0.0.0"}
: ${jpsonic_port:="8080"}
: ${jpsonic_ssl:="NO"}
: ${jpsonic_context_path:="/"}
: ${jpsonic_init_memory:="1024"}
: ${jpsonic_max_memory:="2048"}
: ${jpsonic_chdir:="/usr/local/jpsonic"}

start_cmd=jpsonic_start
stop_cmd=jpsonic_stop
restart_cmd=jpsonic_restart
status_cmd=jpsonic_status
start_precmd="export LC_CTYPE='en_US.UTF-8'"

# -Djpsonic.defaultMusicFolder=${jpsonic_home}/artists \
# -Djpsonic.defaultUploadFolder=${jpsonic_home}/incoming \
# -Djpsonic.defaultPodcastFolder=${jpsonic_home}/podcasts \
# -Djpsonic.defaultPlaylistImportFolder=${jpsonic_home}/playlists/import \
# -Djpsonic.defaultPlaylistExportFolder=${jpsonic_home}/playlists/export \
# -Djpsonic.defaultPlaylistBackupFolder=${jpsonic_home}/playlists/backup \

command="/usr/sbin/daemon -p ${pidfile} -f -u ${jpsonic_user}"

procname="/usr/local/bin/java"

command_args="-Djpsonic.home=${jpsonic_home} -Dserver.address=${jpsonic_address} -Dserver.port=${jpsonic_port} -Dserver.context-path=${jpsonic_context_path} -Xms${jpsonic_init_memory}m -Xmx${jpsonic_max_memory}m -Djava.awt.headless=true -jar ${jpsonic_chdir}/jpsonic.war"

command_args1="-Djpsonic.home=${jpsonic_home} -Dserver.port=${jpsonic_port} -jar ${jpsonic_chdir}/jpsonic.war"

jpsonic_start() {
  echo "Starting Jpsonic"
  echo "${command} ${procname} ${command_args}"
  cd ${jpsonic_chdir}
  ${command} ${procname} ${command_args}
}

jpsonic_stop() {
  echo "Stopping Jpsonic"
  kill `cat ${pidfile}`
  rm ${pidfile}
}

jpsonic_restart() {
  jpsonic_stop
  sleep 1
  jpsonic_start
}

jpsonic_status() {
  if jpsonic_check; then
    echo "Jpsonic running"
    return 1
  else
    echo "Jpsonic not running"
    return 0
  fi
}


jpsonic_check() {
  if [ -f ${pidfile} ]; then
    return 0
  else
    return 1
  fi
}

run_rc_command "$1"
```

起動スクリプトを作成したら実行権限をつける。

```
root# chmod a+x /etc/rc.d/jpsonic
```

そしてサービスとして起動する。

```
root# service jpsonic enable
root# service jpsonic start
```

改めてhttp://任意のアドレス:8080/に接続しJpsonicの画面が開けるか確認します。
うまく表示でき再生できれば自分だけの音楽ライフが楽しめます。

## 課題など

### [解決済み]ロケールが英語で日本語ファイルを再生するとロギングができず落ちる。

事象：
はじめ参考サイトの通り起動スクリプトを作成し、jpsonicで再生したら再生できず500エラーが発生した。ログを見ると下記のようなエラーを確認。

```
java.nio.file.InvalidPathException: Malformed input or input contains unmappable characters: /var/music/Jamiroquai/Automaton/06 - ?????????????.flac
```

対処：
ロケールを"en_US.UTF-8" → "ja_JP.UTF-8"に変更すると再生できるようになった。

### 索引がすべての音楽ファイル分作成されない

事象：
ひらがなや漢字始まりの音楽ファイルの索引が一部作られない

未解決：
おそらく初期インデックス作成時のロケールが問題っぽいが一応検索や全体で確認できるので一旦そのまま