有馬総一郎のブログ

(彼氏の事情)

2020年09月24日 10:25:55 JST - 7 minute read - Subsonic

SubsonicからJpsonicに乗り換えてみる

OwncloudからNextcloudが派生したように、 Subsonic から派生した Jpsonic なるものがある。

以下は開発者サイトからの引用。

Jpsonicはフリーのミュージックストリーミングサーバです。

JpsonicはSubsonicの子孫にあたり、基本的な機能も使い方もほぼ同じの日本人向け対応が行われたサーバです。 日本語を適正にブラウジングするための機能修正や、日本人がよく使う機能の強化が行われています。

確かに Subsonic はいつの間にかソースを公開しなくなっていた。また、私は初期の内にライセンスを購入したので、永久に無料のままだが、今だと一月1$、永久ライセンスだと99$払わなきゃいけない。正直、どういう機能制限があるのか、よく分からない。

日本語の機能が強化されていることに加えて、そういったライセンス料を払いたくない人は Jpsonic は最適解になるかも知れない。ということでインストール。

wget https://github.com/jpsonic/jpsonic/releases/download/v109.2.0/jpsonic.war
sudo mv ~/jpsonic.war /var/lib/tomcat8/webapps/jpsonic.war
sudo mkdir /var/jpsonic
sudo mkdir /var/jpsonic/playlists
sudo mkdir /var/jpsonic/transcode
sudo ln -s /usr/bin/ffmpeg /var/jpsonic/transcode/ffmpeg
sudo ln -s /usr/bin/lame /var/jpsonic/transcode/lame
sudo chown -R tomcat8:tomcat8 /var/jpsonic
sudo chown -R tomcat8:tomcat8 /var/lib/tomcat8/webapps/jpsonic.war
sudo vi /etc/apache2/conf-available/jpsonic.conf
<Location /jpsonic/>
SSLRequireSSL
ProxyPass ajp://localhost:8009/jpsonic/
</Location>
sudo a2enconf jpsonic
sudo service apache2 restart
sudo service tomcat8 restart

しかし、アクセスしてみると、エラーとなっている…

Jpsonic

どういうことだと思って、単独で起動してみる。

$ java -Dserver.port=10000 -Dservlet.contextPath=/jssonic -jar /var/lib/tomcat8/webapps/jpsonic.war
Exception in thread "main" java.lang.UnsupportedClassVersionError: org/airsonic/player/Application has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:348)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:46)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:109)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
        at org.springframework.boot.loader.WarLauncher.main(WarLauncher.java:59)

Jpsonic のクラスバージョンが55(Java11)なのに対して、実行バージョンが52(Java8)なので、エラーを吐いている。確認するとOracle Java8を使っていた。

$ java -version
java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)

Open JDK11をインストールする。そして、デフォルトに設定する。

sudo apt install openjdk-11-jdk
sudo update-alternatives --config java
alternative java (/usr/bin/java を提供) には 2 個の選択肢があります。

  選択肢    パス                                       優先度  状態
------------------------------------------------------------
  0            /usr/lib/jvm/java-11-openjdk-amd64/bin/java   1111      自動モード
  1            /usr/lib/jvm/java-11-openjdk-amd64/bin/java   1111      手動モード
* 2            /usr/lib/jvm/java-8-oracle/jre/bin/java       1081      手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 1
update-alternatives: /usr/bin/java (java) を提供するためにマニュアルモードで /usr/lib/jvm/java-11-openjdk-amd64/bin/java を使います

確認。

$ java -version
openjdk version "11.0.8" 2020-07-14
OpenJDK Runtime Environment (build 11.0.8+10-post-Ubuntu-0ubuntu118.04.1)
OpenJDK 64-Bit Server VM (build 11.0.8+10-post-Ubuntu-0ubuntu118.04.1, mixed mode, sharing)

そして、$JAVA_HOMEを再設定する。

sudo vi /etc/default/tomcat8

/etc/default/tomcat8

#JAVA_HOME=/usr/lib/jvm/java-8-openjdk
JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64

ちなみに自分の環境だと、$PATH$JAVA_HOMEにOralce Java8を設定してあった。

  • /etc/environment
  • /etc/profile
  • /etc/bash.bashrc
  • /root/.profile
  • ~/.bashrc
  • ~/.profile

上記ファイルを確認したが、どこで$PATH$JAVA_HOMEにOracle Java8の設定をしているのか分からなかったのでsudo apt purge oracle-java8-*で設定ファイルごと削除した。すると、$PATH$JAVA_HOMEからOralce Java8の設定が消えた。

ともあれ、この状態で Jpsonic を起動。

$ java -Dserver.port=10000 -Dservlet.contextPath=/jssonic -jar /var/lib/tomcat8/webapps/jpsonic.war
LOGBACK: No context given for c.q.l.core.rolling.SizeAndTimeBasedRollingPolicy@1582071873


   dMMMMMP dMMMMb  .dMMMb  .aMMMb  dMMMMb  dMP .aMMMb
      dMP dMP.dMP dMP" VP dMP"dMP dMP dMP amr dMP"VMP
     dMP dMMMMP"  VMMMb  dMP dMP dMP dMP dMP dMP
dK .dMP dMP     dP .dMP dMP.aMP dMP dMP dMP dMP.aMP
VMMMP" dMP      VMMMP"  VMMMP" dMP dMP dMP  VMMMP"
                Powered by Airsonic 11.0.0-SNAPSHOT

Jpsonic
Jpsonic

成功。

そして、ファイルをスキャンしてみる。

しかし、索引などに検索された音楽ファイルが表示されない…

Jpsonic

Empty artists list and home page · Issue #681 · airsonic/airsonic · GitHub

多少、手順は違うものの、同じstand alone(war)形式による起動。そして、メディアファイルがマウントされた所にある点は同じだ。自分の場合は、元のパス/var/musicを変更して/mnt/hdd1/Public/Public_Musicに変更しただけなのだが…

改善方法としては、一旦今の設定してあるパスを削除して、再度、追加しなおせば、元に戻る…

削除

Jpsonic

追加

Jpsonic

一応、 ArisonicJpsonic の名誉のために言っておくと、このバグは Subsonic の時からあったものと同じだと思う。数年振りに出喰わしたので、どうやって直したのか忘れて、再度ググりはしたが。でも、もしかしたら、 Subsonic の特定バージョンからは直っていたかもしれない。

これでめでたし、と思ったら、おかしい…最近追加した曲が少ない。索引から辿っても表示されないアーティストがいる。1

Jpsonic

初めは Mary`s Blood松本孝弘といった名前のためかと思ったら、どうもそうでもない。上記バグのせいかと思って、sudo rm /var/jpsonic/db/*をしてDBを削除して、最初から設定しなおしたが、さっきと表示されないファイルが変わった(変わるのも意味不明だ)だけで、やはり表示(スキャン)されないファイルがある…

2020-09-23 19:35:00.525  WARN --- o.a.p.s.m.JaudiotaggerParser             : Error when parsing tags in /mnt/hdd1/Public/Public_Music/Aldious/ALL BROSE/01_Monster.m4a

org.jaudiotagger.audio.exceptions.CannotReadException: /mnt/hdd1/Public/Public_Music/Aldious/ALL BROSE/01_Monster.m4a:null
        at org.jaudiotagger.audio.generic.AudioFileReader.read(AudioFileReader.java:117) ~[jaudiotagger-2.2.5.jar:na]
        at org.jaudiotagger.audio.AudioFileIO.readFile(AudioFileIO.java:355) ~[jaudiotagger-2.2.5.jar:na]
        at org.jaudiotagger.audio.AudioFileIO.read(AudioFileIO.java:198) ~[jaudiotagger-2.2.5.jar:na]
        at org.airsonic.player.service.metadata.JaudiotaggerParser.getRawMetaData(JaudiotaggerParser.java:87) ~[classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.metadata.MetaDataParser.getMetaData(MetaDataParser.java:47) [classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.MediaFileService.createMediaFile(MediaFileService.java:499) [classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.MediaFileService.getMediaFile(MediaFileService.java:115) [classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.MediaFileService.getMediaFile(MediaFileService.java:81) [classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.MediaFileService.findCoverArt(MediaFileService.java:649) [classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.MediaFileService.createMediaFile(MediaFileService.java:563) [classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.MediaFileService.updateChildren(MediaFileService.java:400) [classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.MediaFileService.getChildrenOf(MediaFileService.java:197) [classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.MediaScannerService.scanFile(MediaScannerService.java:282) [classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.MediaScannerService.scanFile(MediaScannerService.java:286) [classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.MediaScannerService.doScanLibrary(MediaScannerService.java:207) [classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.MediaScannerService.access$000(MediaScannerService.java:63) [classes/:11.0.0-SNAPSHOT]
        at org.airsonic.player.service.MediaScannerService$1.run(MediaScannerService.java:172) [classes/:11.0.0-SNAPSHOT]

/var/jpsonic/jpsonic.logを見ると上記のようなエラーが出ているが、かといって表示されないファイルがmp4, m4aなどエンコード方式に拠っているわけでもない。兎も角、原因が分からないので、 Subsonic に戻すことにした。

しかし、 Subsonic を起動させると

23-Sep-2020 16:58:09.574 情報 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Webアプリケーションアーカイブ [/var/lib/tomcat8/webapps/subsonic.war] を配備します
23-Sep-2020 16:58:16.098 情報 [localhost-startStop-1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
[2020-09-23 16:58:16,753] ERROR org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/applicationContext-sonos.xml]; nested exception is org.springframework.beans.FatalBeanException: Invalid NamespaceHandler class [org.apache.cxf.jaxws.spring.NamespaceHandler] for namespace [http://cxf.apache.org/jaxws]: problem with handler class file or dependent class; nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:420)

とエラーが出ている。どうも Subsonic はJava11に対応していないっぽい。

Javaといえば後方互換性があるのがウリなんだけどな…しかも8より前と8以降なら納得もできるが、むむむ…と思いつつ、ググると JEP 320の悪夢 – JDK 11は史上最悪のJDKかもしれない – My Noteといったページが見つかったりする。

色々あるんだね…

となれば、OpenJava8をインストールして、 Jpsonic の方をダウングレードするしかない。

sudo apt install openjdk-8-jdk
sudo update-alternatives --config java
java -version
openjdk version "1.8.0_265"
OpenJDK Runtime Environment (build 1.8.0_265-8u265-b01-0ubuntu2~18.04-b01)
OpenJDK 64-Bit Server VM (build 25.265-b01, mixed mode)

sudo vi /etc/default/tomcat8

/etc/default/tomcat82

#JAVA_HOME=/usr/lib/jvm/java-8-openjdk
JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/jre

Jpsonicv109.0.0をダウンロードしてきた。

とりあえずこれで SubsonicJpsonic が共存できるようになった。それで、 Jpsonic で新たにファイルスキャンしたところ、今度はちゃんと全てのファイルがスキャンされるようになった。原因はJavaなのか?それとも jpsonic-109.2.0のバグなのか?

アーティスト数、アルバム数、曲目数、ファイルサイズなど一致

Jpsonic
Jpsonic

折角直ったことだし、Androidアプリ、HTML5プレイヤーでも問題なく動くので、当分はこのまま Jpsonic を使い続けることにする。

日本人向け改修が行われてるというだけあって、ソートがかなり正確に行われる。さすがに一部特殊な読み方するアーティストについてはそのままでは駄目だけど、9割方は大丈夫の様子。

アーティスト名 正しい読み方 Jpsonic
×ジャパリ団 バッテンジャパリダン カケルジャパリダン
屍忌蛇 シイジャ カバネキヘビ
聖闘士星矢 セイントセイヤ キヨシトウボシヤ
聖飢魔II セイキマツ キヨシキマツ

あと、#に振り分けられてしまった。やはり、iTune、Sonyのミュージック系アプリのように、アーティスト読み方のタグを設定した方が良いんだろなぁ。個人的に余り好きではないんだけど。

また、韓国語についても同様に#に振り分けされる。

A B C D E F G H I J K L M N O P Q R S T U V W X-Z(XYZ) NUMBER(0123456789) あ(アイウエオ) か(カ稼キクケコ兀) さ(サシスセソ) た(タチツテト) な(ナニヌネノ) は(ハヒフヘホ) ま(マミムメモ) や(ヤユ侑ヨ) ら(ラリルレロ) わ(ワヲン) 김-하(김미박백서소신아양엄에옥이조채최코하)

김-하(김미박백서소신아양엄에옥이조채최코하)このように韓国語のソートグループを作った。 Subsonic ではソートグループを作ればちゃんと振り分けされたが、 Jpsonic では効かず#に振り分けられてしまったのは残念だ。

Jpsonic

Jpsonic

Subsonic

Jpsonic

あと、フォントの問題なのかヘルプ画面のログが小さすぎる。ともあれ、正しくファイルスキャンされるようになれば、将来的にはこのまま乗り換えたい。


  1. 音楽ファイルが表示されてないとして表示している 画像のデータベース詳細を見るとアーティスト数、アルバム数、曲目数も足りてない ↩︎

  2. JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64にしてもtomcat起動のログをみると/usr/lib/jvm/java-8-openjdk-amd64/jreと表示される。 ↩︎