Media Server For Music And Audio-Books

music-7Having updated my mobile  recently (but still staying on Android) to 4G device, I thought that it would be about time to make my audio collection available outside of home network.  At home I use samba share, which is quite fine for most of uses, however enabling access from internet required bit more  effort. In following article I’d like to describe options, I’ve been looking at, and the final solution.

My requirements:

  • Should be able to handle large collections
  • Browse by directory structure (my metadata tags are messy)
  • Clearly separate audio books from music
  • Some search would be nice
  • Preferably open source (at least server part)
  • Linux indeed
  • Reliable playback over Internet on mobile
  • Smart caching on mobile, enabling temporal break-outs in connectivity ( the underground etc.)
  • Possibility to load content for offline playback
  • Should be reasonably secure

Options:

Some Cloud Storage

It was not really option for me.  I do not want cloud service for this.

ASUS AI Cloud

As I’m using ASUS router ASUS AiCloud is one option. If AiCloud is enabled on router, then Android  application can be used to provide access to all LAN shared disks (SMB).  Additionally there is some support for media playback.
I used it for a while, have some issues with android client, which moved me to look for other solution:

  • Unstable – when connection is lost, playback in the client freezes and is not able to continue, when connection is re-established. All application has to be closed and restarted.
  • Just current item is cached, so it can not  get over longer connection drop outs
  • General quality – player interface is ugly,  resumes from paused state after each incoming call etc.

SFTP And ES File Explorer

At home I use excellent ES File Explorer to access shares and it has also SFTP support.
I can access my server via SSH already, so only trick was to enable public/private key use in ES – and it’s very easy – openssh generated key can be used in ES.
However SFTP does not seem to be good for media playback,  it looks like  whole file must be downloaded, before playback starts. Also SFTP seems to be unstable when connection is switched between mobile and WiFi, or it’s unavailable for a short while.

ES also enables WebDAV remote shares, I did not try them yet, maybe they can be better suited for media then SFTP?

ownCloud

ownCloud is PHP application for accessing and synchronizing of  files across different  devices. It is written in PHP. For music streaming it’s using Ampache,  which can be also used as standalone solution, so as media solution ownCloud does not provide anything interesting. See details of Ampache below.

Media Servers

So finally I’ve looked at specialized media servers.   Based on different articles I considered: Emby, Plex, Serviio, UMS, Subsonic/Madsonic/Libresonic /Airsonic and Ampache.

Emby (former Media Explorer) is an open source project. However the music handling does not suite my needs. Music is sorted only by metatags, which causes problems and music and audio-books are messed together.

Plex – is not an open source. It has good references,  but to enable access over Internet one must register it with their Plex service, which meant hard stop for me, because I’d like to have completely independent solution.

Serviio – is not an open source, so I did not try it.

UMS – is focused only on LAN environment (using DLNA), but I need mainly internet access.

Subsonic – is  media server written in Java. It was open source, but turned to closed source some time ago. It focuses on music and it best met my requirements.  It basically sticks to the way how music is organize in the file system, which is absolutely crucial for me, provides super-fast scanning of music directories and also nice Android applications are available (Subsonic, Ultrasonic …), which provide smart caching (you can choose how many songs ahead should be  cached in current play list, so you can easily survive some time without connection) and also it very easy to load content to mobile local storage.  Overall it works quite well, however installation required few tweaks – as described below.

Libresonic – is recent Subsonic clone – (based on KANG 5.3 version of Subsonic). Libresonic is addressing fact that recent versions of Subsonic (from version 6) are not open sourced any more. Currently Libresonic seems to be abandoned – no commit in more that half year – looks like active  development moved to Airsonic – see below.

Airsonic – is another Subsonic clone – actually fork of Libresonic, after some developers decided to follow bit different path. Recently it looks much more active than  Libresonic, new features have been added ( like true HTML player). Community is active, responding to issues while Libresonic project seems to be stalled now.

Madsonic –  is Subsonic clone.  It removes dubious shareware like limitations in the program and adds new functionality.  However the interface looks more confusing and the new functions have not been  of interest to me, so I rather stayed with Subsonic (or to be exact it’s clone which removes the trial limitations – see below).

Booksonic – it’s another subsonic clone – focused on audiobooks –  however last commit is more then a year ago, so it does not seem to have bright future – so for audiobooks I rather followed my own way as explained below (audioserve).

Ampache – open source, PHP server. Installs smoothly to regular LAMP environment. Collection is organized  by metatags, so again no good option for me, it results in messy collection.  Just tried one Android client  Amdroid, which is quite bad – poor interface, alpha quality.

My Choice

For me subsonic was a clear winner,  no other solution gets closer to meet my requirements. Some time ago I replaced subsonic with libresonic (which provides same functionality for me), because of subsonic code going to closed mode, and later  replaced it with  airsonic, because libresonic is development is stalled.
I particularly liked:

  • You can browse media by directory structure (with some enhancements, which do not mind so much)
  • Music and Audiobooks can be in separated collections – so it’s easy to browse them
  • Super fast scanning of music directories
  • Smart caching on Android client

Some issues:

  • Java is bit resources hungry – especially memory.
  • Startup takes several minutes
  • Handling of national chars in file names and tags is problematic
  • Sorting of files within directory, if metadata/tags are not correct (android clients)
  • Using of metadata instead of filename causes sometime problems, if metadata are not correct
  • Security (only issue in recent libresonic,  airsonic has resolved them )
    unauthenticated access to media –  media and cover art is basically accessible to anybody. It’s easy – for unauthenticated  user  (if he knows URL pattern)  to list and download all media
    passwords are stored  in cleartext

As I was not completely happy with any solution – especially for audiobooks (for which airsonic is just too overcomplicated), I also started new project audioserve – to create super simple audiobooks server – check this article. Now I’m using audioserve for audiobooks and airsonic for music – I found that’s it easier to have separate solution for audiobooks, then rely on airsonic for this, especially as audioserve is very light weighted.

Setting Up Libresonic

(airsonic is very similar – just replace libre with air)

  1. Download latest release from here.
  2. I’m using this script to run libresonic (optionally could be deployed in tomcat):
    #!/bin/sh
    
    
    LIBRESONIC_HOME=/data/local/libresonic
    LIBRESONIC_HOST=0.0.0.0
    LIBRESONIC_PORT=4040
    LIBRESONIC_CONTEXT_PATH=/libresonic
    LIBRESONIC_MAX_MEMORY=512
    LIBRESONIC_PIDFILE=/tmp/libresonic.pid
    
    # was need in subsonic to handle unicode file names
    export LC_ALL="en_US.UTF-8"
    export LANG="en_US.UTF-8"
    
    kill=1
    
    usage() {
        echo "Usage: libresonic.sh [options]"
        echo "  --help              Prints help."
        echo "  --kill		Kills running process"
        exit 0
    }
    # Parse arguments.
    while [ $# -ge 1 ]; do
        case $1 in
            --help)
                usage
                ;;
            --kill)
                kill=0
                ;;
            *)
                usage
                ;;
        esac
        shift
    done
    
    if [ $kill = 0 ]; then
    if [ -f $LIBRESONIC_PIDFILE ]; then
    kill `cat $LIBRESONIC_PIDFILE`
    rm -f $LIBRESONIC_PIDFILE
    exit 0
    else
    echo Not running
    exit 0
    fi
    fi
    
    # Use JAVA_HOME if set, otherwise assume java is in the path.
    JAVA=java
    if [ -e "${JAVA_HOME}" ]
        then
        JAVA=${JAVA_HOME}/bin/java
    fi
    
    # Create Libresonic home directory.
    mkdir -p ${LIBRESONIC_HOME}
    LOG=${LIBRESONIC_HOME}/libresonic_sh.log
    rm -f ${LOG}
    
    cd $(dirname $0)
    if [ -L $0 ] && ([ -e /bin/readlink ] || [ -e /usr/bin/readlink ]); then
        cd $(dirname $(readlink $0))
    fi
    
    ${JAVA} -Xmx${LIBRESONIC_MAX_MEMORY}m \
      -Dlibresonic.home=${LIBRESONIC_HOME} \
      -Dserver.host=${LIBRESONIC_HOST} \
      -Dserver.port=${LIBRESONIC_PORT} \
      -Dserver.contextPath=${LIBRESONIC_CONTEXT_PATH} \
      -Djava.awt.headless=true \
      -verbose:gc \
      -jar libresonic.war > ${LOG} 2>&1 &
    
    rc=$?
    if [ $rc = 0 ]; then
    # Write pid to pidfile if it is defined.
    if [ $LIBRESONIC_PIDFILE ]; then
        echo $! > ${LIBRESONIC_PIDFILE}
    fi
    
    echo Started Libresonic [PID $!, ${LOG}]
    
    else
    
    echo Something went wrong - ret. code $rc
    fi 
    
  3. Configure nginx as reverse proxy, assure https support in nginx (from Internet libresonic should be access only via encrypted connection).   For SSL certificate use Let’s Encrypt certification authority, which issues certificates for free – certbot-auto run --nginx work fine for me.
    This is part of nginx configuration relevant for libresonic:

    server {
        location /libresonic {
    	proxy_set_header X-Real-IP         $remote_addr;
          	proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
          	proxy_set_header X-Forwarded-Proto https;
          	proxy_set_header X-Forwarded-Host  $http_host;
          	proxy_set_header Host              $http_host;
          	proxy_max_temp_file_size           0;
          	proxy_pass                         http://127.0.0.1:4040;
          	proxy_redirect                     http:// https://;
    	}
       listen 443 ssl; # managed by Certbot
       # ... more ssl settings managed by Certbot
    }
  4. Open port 443 in you route to access libresonic from Internet

Setting Up Subsonic (outdated)

  1. Install from official site. I prefer stand alone installation, assuming others will be similar.
  2. Replace .war file with one from this fork. This one is patched to remove time limitation of some features.  (It’s not crack – subsonic is Open Source under GPLv3,  so it’s legitimate to create modified version as long as their source is available under compatible license).
  3.  Edit subsonic.sh (or /etc/default/subsonic  appropriately, if you installed package)
    SUBSONIC_HOME=/data/local/subsonic
    SUBSONIC_PORT=0
    SUBSONIC_HTTPS_PORT=4043
    

    Enable https, disable http (but only if you will not use DLNA, it will not work without http port).  Set home directory (if different from default).

  4. Also you need to assure that UTF-8 support is in place.  For this ensure that these  variables are set in subsonic environment:
    export LC_ALL="en_US.UTF-8"
    export LANG="en_US.UTF-8"
    

    Easiest way is to add them to subsonic.sh script ( or /etc/init.d startup script in packaged installation).
    Without these variables subsonic will not recognize files with national characters in file name!

  5. Subsonic comes with pre-packed SSL key and certificate for HTTPS – this is significant security risk, if internet access is enabled. (Anybody can fetch private key from subsonic distribution and then decode your ssl trafic).  Generate new key+certificate and update subsonic-booter-jar-with-dependencies.jar as described here.
    Self-signed certificate would be enough ( just add -x509 -days 3650 to openssl req command).
  6. Enable port forwarding on your home router (either manually or in subsonic network setup enable UPnP NAT PMP
  7. Run subsonic as non-root account

 

Leave a Reply

Your email address will not be published. Required fields are marked *