Gerbera 1.4.0相当までは、旧mediatombのインポートスクリプトがそのまま使えました。
しかし、Gerbera 1.11.0になってから、インポート方法が変わり、インポートそのものは今まで通りaddCdsObject()を使ってインポートするのですが、第二引数であるコンテナツリー指定の形式が変わったようで、今までは単なる配列を指定するだけでしたが、これからはいったんaddContainerTree()を使って変数にコンテナツリーを代入してから、addCdsObject()の第二引数にその変数を指定する方法に変わりました。
面倒そうな話ですが、こうなった理由はとても合理的で、複数値を持ったメタデータに対応するためです。
一番わかりやすいのがジャンル(genre)
音楽のジャンルが多様化しているので、テクノポップなんかはGENRE=["POP","TECNO","TECNO_POP"]みたいな感じになると思うんですが、今までだとこの曲は
Audio - Genre - POP TECNO TECNO_POP
となるか
Audio - Genre - POP
となって、TECNO以下切り捨てみたいになっていたと思います。
(ジャンルを例に出しましたが、それほどジャンル検索をしたことがないです。)
それを、
Audio - Genre - POP
Audio - Genre - TECNO
Audio - Genre - TECNO_POP
どこからでもアクセスできるようにする、という設計思想になっているようです。
理にかなっていますが、配列の中に配列を入れられるよう、コンテナツリーをaddContainerTree()を使って代入することになったようです。
更に、これらのコンテナツリーは、どのようなオブジェクトなのか、オブジェクトタイプを予め定義する必要があるようです。
んで、本題。
うちの音楽ライブラリは4つのフォルダ(ディレクトリ)に分けて格納しています。
gentoolinux.hatenablog.com
今回、HDD交換を機に、ディレクトリがツリー分下がっています。つまり、
/home/files/mp3/Album
/home/files/mp3/Single
/home/files/mp3/SuperEurobeat
/home/files/mp3/Wife
という構造に変えました。
この第4階層をAudioコンテナの次に表示し、DLNA上では
Audio - Album
Audio - Aingle
Audio - SuperEurobeat
Ausio - Wife
と、一つ階層を増やし、膨大な音楽ファイルを選びやすくしたいと思います。
これを実現するため、今まではimport.jsを改変していましたが、Gerbera 1. 11.0からはcommon.jsを改変する必要があります。
import.jsもcommon.jsも、1.11.0デフォルトのスクリプトとし、common.jsを、この1.11.0のデフォルトのものから改変していきます。
まずは、音楽ファイルのフルパスを変数tmpfilelocに格納します。パスが格納されているのはorigオブジェクトのlocationプロパティです。なので、
var tmpfileloc = orig.location;
そこから、/で分割した値をfilelocの変数に配列として代入します。
var fileloc = tmpfileloc.split('/');
最終的にディレクトリの第4階層をコンテナ名の変数u_pathに代入します。
var u_path = fileloc[4];
これらを、できるだけ音楽ファイルが読み込まれるインポートファンクションの前段に記載します。
今回、音楽ファイルのインポートはaddAudio()とaddAudioStructured()がありますが、今回はaddAudio()を使います。
// doc-add-audio-begin
function addAudio(obj)
の直後くらいに記述しました
function addAudio(obj) {
var title = obj.title;
var tmpfileloc = orig.location;
var fileloc = tmpfileloc.split('/');
var u_path = fileloc[4];
続いて、今までにないコンテナとなるわけなので、コンテナ定義を追加します。
コンテナの定義は
const chain = {
という変数代入に続いて、1行づつ定義されています。例えば
audio: { title: 'Audio', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER, metaData: },
という定義は、Audioという固定名称のコンテナです。オブジェクトの内容によって変更されることはありません。
対して、
composer: { title: composer, objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER_MUSIC_COMPOSER, metaData: , res: obj.res, aux: obj.aux, refID: obj.id },
は、作曲家名のコンテナになるので、オブジェクト(=音楽ファイル)によって、コンテナ名は変動します。composer変数に代入されている作曲家名がコンテナ名になります。どのオブジェクト(=音楽ファイル)の作曲家名をコンテナにするのか? を、後半のres: obj.res, aux: obj.aux, refID: obj.idで、定義しています。(多分obj.idが重要なのだと思う・・・。)
なので、先ほどのu_pathに代入されている値をコンテナ名=titleにします。
u_path: { title: u_path, objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
このあたりのコンテナ定義をさらすと
const chain = {
audio: { title: 'Audio', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER, metaData: [] },
allAudio: { title: 'All Audio', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allArtists: { title: 'Artists', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allGenres: { title: 'Genres', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allAlbums: { title: 'Albums', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allYears: { title: 'Year', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allComposers: { title: 'Composers', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allSongs: { title: 'All Songs', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allFull: { title: 'All - full name', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
artist: { searchable: false, title: artist[0], objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER_MUSIC_ARTIST, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
album: { searchable: false, title: album, objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER_MUSIC_ALBUM, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
genre: { title: genre, objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER_MUSIC_GENRE, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
year: { title: date, objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
composer: { title: composer, objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER_MUSIC_COMPOSER, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
u_path: { title: u_path, objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
};
定義したら、いよいよaddContainerTree()にu_pathを定義していきます。順番としてはAll Audioの次に、第4ディレクトリを表示してもらいます。
例として、All Audioにパスのコンテナを追加します。
var container = addContainerTree([chain.audio, chain.u_path, chain.allAudio]);
addCdsObject(obj, container);
このあたりのデータベースを代入数するスクリプトを表示します。
const chain = {
audio: { title: 'Audio', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER, metaData: [] },
allAudio: { title: 'All Audio', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allArtists: { title: 'Artists', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allGenres: { title: 'Genres', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allAlbums: { title: 'Albums', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allYears: { title: 'Year', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allComposers: { title: 'Composers', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allSongs: { title: 'All Songs', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
allFull: { title: 'All - full name', objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER },
artist: { searchable: false, title: artist[0], objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER_MUSIC_ARTIST, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
album: { searchable: false, title: album, objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER_MUSIC_ALBUM, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
genre: { title: genre, objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER_MUSIC_GENRE, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
year: { title: date, objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
composer: { title: composer, objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER_MUSIC_COMPOSER, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
u_path: { title: u_path, objectType: OBJECT_TYPE_CONTAINER, upnpclass: UPNP_CLASS_CONTAINER, metaData: [], res: obj.res, aux: obj.aux, refID: obj.id },
};
chain.audio.metaData[M_CONTENT_CLASS] = [ UPNP_CLASS_AUDIO_ITEM ];
chain.album.metaData[M_ARTIST] = artist;
chain.album.metaData[M_ALBUMARTIST] = artist;
chain.album.metaData[M_GENRE] = [ genre ];
chain.album.metaData[M_DATE] = obj.metaData[M_DATE];
chain.album.metaData[M_UPNP_DATE] = obj.metaData[M_UPNP_DATE];
chain.album.metaData[M_ALBUM] = [ album ];
chain.artist.metaData[M_ARTIST] = artist;
chain.artist.metaData[M_ALBUMARTIST] = artist;
chain.genre.metaData[M_GENRE] = [ genre ];
chain.year.metaData[M_DATE] = [ date ];
chain.year.metaData[M_UPNP_DATE] = [ date ];
chain.composer.metaData[M_COMPOSER] = [ composer ];
var container = addContainerTree([chain.audio, chain.u_path, chain.allAudio]);
addCdsObject(obj, container);
container = addContainerTree([chain.audio, chain.u_path, chain.allArtists, chain.artist, chain.allSongs]);
addCdsObject(obj, container);
var temp = '';
if (artist_full) {
temp = artist_full;
}
if (album_full) {
temp = temp + ' - ' + album_full + ' - ';
} else {
temp = temp + ' - ';
}
obj.title = temp + title;
container = addContainerTree([chain.audio, chain.u_path, chain.allFull]);
addCdsObject(obj, container);
const artCnt = artist.length;
var i;
for (i = 0; i < artCnt; i++) {
chain.artist.title = artist[i];
container = addContainerTree([chain.audio, chain.u_path, chain.allArtists, chain.artist, chain.allFull]);
addCdsObject(obj, container);
}
obj.title = track + title;
for (i = 0; i < artCnt; i++) {
chain.artist.title = artist[i];
chain.artist.searchable = true;
container = addContainerTree([chain.audio, chain.u_path, chain.allArtists, chain.artist, chain.album]);
addCdsObject(obj, container);
}
chain.album.searchable = true;
container = addContainerTree([chain.audio, chain.u_path, chain.allAlbums, chain.album]);
obj.title = track + title;
addCdsObject(obj, container);
chain.genre.searchable = true;
if (obj.metaData[M_GENRE]) {
for (var oneGenre in obj.metaData[M_GENRE]) {
chain.genre.title = obj.metaData[M_GENRE][oneGenre];
chain.genre.metaData[M_GENRE] = [ oneGenre ];
container = addContainerTree([chain.audio, chain.u_path, chain.allGenres, chain.genre]);
addCdsObject(obj, container);
}
}
container = addContainerTree([chain.audio, chain.u_path, chain.allYears, chain.year]);
addCdsObject(obj, container);
container = addContainerTree([chain.audio, chain.u_path, chain.allComposers, chain.composer]);
addCdsObject(obj, container);
}
これで、Audioの下に、フォルダ第4階層が疑似的に表示されるようになります。