はじめに
FiiO JM21 はコストパフォーマンスに優れたDAPですが、内蔵プレーヤーアプリの FiiO MUSIC の使い勝手に難があります。特にプレイリストについては独特な仕様が複数あり、PC の音楽管理ソフトからのプレイリスト転送が困難です。
本記事では、内蔵SDカードに対して、SONY が提供していた音楽管理ソフト Media Go からプレイリストを転送して、Fiio MUSIC で読み込めるように加工する方法を提供します。
FiiO MUSIC の仕様
先述した通り、FiiO MUSIC には独特な仕様が複数あります。今回関わってくるのは以下の仕様です。
- プレイリストファイルは、
/storage/emulated/0/Android/data/com.fiio.music/files/playlist
配下しか読まない - ファイル名は
{playlist_title}.playlist.m3u(8)
しか読まない - m3u(8) ファイルで指定するパスは、絶対パスで指定する
それに対して、Media Go からFiiO JM21にプレイリストを転送する際は以下の挙動をします。
- プレイリストファイルは、
/storage/external_sd/Music
配下に出力される - ファイル名は
{playlist_title}.m3u
- m3u ファイル内で指定されるパスは、相対パス
以上の差異を埋めれば読み込めるということです。一つずつ解決していきます。
ファイル配置場所
/storage/emulated/0/Android/data/com.fiio.music/files/playlist
を、 /storage/external_sd/Music
へのシンボリックリンクにします。
Windows マシンからシンボリックリンクを貼るために、Fiio JM21 を USB デバッグモードにして、Windows マシンにはadbをインストールしておきます。(やり方は各自調べてください)
以下コマンドを実行すればシンボリックリンクになります。
$ adb shell
$ cd /storage/emulated/0/Android/data/com.fiio.music/files
$ rm -rf playlist
$ ln -s /storage/external_sd/Playlists playlist
参考: https://www2.filewo.net/wordpress/2025/02/01/3989/#USB
ファイル名
ふつうにリネームすればよいです。Windows の .bat を使うのが一番シンプルなはずですが、私は弱いので Python で実装します。
import subprocess
m3u_list = [path.replace(" ", "\\ ") for path in str(subprocess.check_output("adb shell ls /storage/external_sd/Music/*.m3u"))[2:].split("\\r\\n")[:-1]]
for path in m3u_list:
# すでに .playlist.m3u になっているファイルはスキップする
if 'playlist' in path:
continue
rep_path = path.replace(".m3u", ".playlist.m3u")
print(f'adb shell cp \"{path}\" \"{rep_path}\"')
subprocess.check_output(f'adb shell cp \"{path}\" \"{rep_path}\"')
m3u のパス
.playlist.m3u
ファイルの中身を読み込んで、パス指定部分に /storage/external_sd/Music/
のプレフィックスを加えます。そのままだと区切り文字がバックスラッシュ \
になっているので、ついでに置き換えます。
# .playlist.m3u のファイルだけをリストアップ
path_list2 = [path.replace(" ", "\\ ")for path in str(subprocess.check_output("adb shell ls /storage/external_sd/Music/*playlist.m3u"))[2:].split("\\r\\n")[:-1]]
for m3u_path in path_list2:
# .m3u を Windows 側に adb pull
m3u_path = m3u_path.replace("\ ", " ")
local_file = './temp.m3u'
subprocess.check_output(f"adb pull \"{m3u_path}\" \"{local_file}\"")
# BOM付きなので utf-8-sig で読む
with open(local_file, "r", encoding="utf-8-sig") as f:
content = f.read()
prefix = '/storage/external_sd/Music/'
modified_lines = [
# パスが書かれている行は 0 始まりでカウントして 2, 4, 6, ...(偶数インデックス)
prefix + line.replace('\\', '/') if i % 2 == 0 and not i == 0 else line
for i, line in enumerate(content.splitlines())
]
# ローカルに出力 → adb push
output = "\n".join(modified_lines)
local_output = "temp_output.m3u"
with open(local_output, "w", encoding="utf-8-sig") as o:
o.write(output)
subprocess.check_output(f"adb push \"{local_output}\" \"{m3u_path}\"")
FiiO MUSIC で読み込む
以上を実行して、FiiO MUSIC の「M3Uプレイリストのインポート」を実行すれば無事にインポートできるはずです。python のコードはファイルにまとめといて .bat から呼び出せるようにすると便利だと思います。
やり残したこと
- ファイル名のエスケープが甘いので、
(
)
とかがあるとエラーになる。各自で改良されたい。 - たぶん .bat で全部できそう