func Ping(res http.ResponseWriter, req *http.Request) {
	r := context.Get(req, api.CtxRender).(*render.Render)
	r.XML(res, 200, newContainer())
}
Ping is used in Subsonic to check server connectivity
package subsonic
import (
	"encoding/xml"
	"fmt"
	"net/http"
	"path"
	"strconv"
	"time"
	"github.com/mdlayher/wavepipe/api"
	"github.com/mdlayher/wavepipe/data"
	"github.com/gorilla/context"
	"github.com/unrolled/render"
)
const (
	XMLName = "subsonic-response"
	XMLNS = "http://subsonic.org/restapi"
	Version = "1.8.0"
)
var (
	ErrBadCredentials = func() *Container {
		c := newContainer()
		c.Status = "failed"
		c.SubError = &Error{Code: 40, Message: "Wrong username or password."}
		return c
	}()
	ErrGeneric = func() *Container {
		c := newContainer()
		c.Status = "failed"
		c.SubError = &Error{Code: 0, Message: "An error occurred."}
		return c
	}()
	ErrMissingParameter = func() *Container {
		c := newContainer()
		c.Status = "failed"
		c.SubError = &Error{Code: 10, Message: "Required parameter is missing."}
		return c
	}()
)
func newContainer() *Container {
	return &Container{
		XMLNS:   XMLNS,
		Status:  "ok",
		Version: Version,
	}
}
type Container struct {
	XMLName xml.Name `xml:"subsonic-response"`
	XMLNS   string `xml:"xmlns,attr"`
	Status  string `xml:"status,attr"`
	Version string `xml:"version,attr"`
	SubError *Error
	Album []Album `xml:"album"`
	AlbumList2 *AlbumList2Container
	Indexes *IndexesContainer
	License *License `xml:"license"`
	MusicDirectory *MusicDirectoryContainer
	MusicFolders *MusicFoldersContainer
	Playlists *Playlists `xml:"playlists"`
	RandomSongs *RandomSongsContainer
	Starred *Starred `xml:"starred"`
}
func (c Container) Error() string {
	return fmt.Sprintf("%d: %s", c.SubError.Code, c.SubError.Message)
}
type Error struct {
	XMLName xml.Name `xml:"error,omitempty"`
	Code    int    `xml:"code,attr"`
	Message string `xml:"message,attr"`
}
type Artist struct {
	XMLName xml.Name `xml:"artist,omitempty"`
	Name string `xml:"name,attr"`
	ID   string `xml:"id,attr"`
}
type Album struct {
	ID        int    `xml:"id,attr"`
	Name      string `xml:"name,attr"`
	Artist    string `xml:"artist,attr"`
	ArtistID  int    `xml:"artistId,attr"`
	CoverArt  string `xml:"coverArt,attr"`
	SongCount int    `xml:"songCount,attr"`
	Duration  int    `xml:"duration,attr"`
	Created   string `xml:"created,attr"`
	Songs []Song `xml:"song"`
}
func subAlbum(album data.Album, songs data.SongSlice) Album {
	return Album{
		ID:        album.ID,
		Name:      album.Title,
		Artist:    album.Artist,
		ArtistID:  album.ArtistID,
		CoverArt:  strconv.Itoa(songs[0].ArtID),
		SongCount: len(songs),
		Duration:  songs.Length(),
		Created:   subTime(songs[0].LastModified),
	}
}
type Song struct {
	ID          int    `xml:"id,attr"`
	Parent      int    `xml:"parent,attr"`
	Title       string `xml:"title,attr"`
	Album       string `xml:"album,attr"`
	Artist      string `xml:"artist,attr"`
	IsDir       bool   `xml:"isDir,attr"`
	CoverArt    string `xml:"coverArt,attr"`
	Created     string `xml:"created,attr"`
	Duration    int    `xml:"duration,attr"`
	BitRate     int    `xml:"bitRate,attr"`
	Track       int    `xml:"track,attr"`
	DiscNumber  int    `xml:"discNumber,attr"`
	Year        int    `xml:"year,attr"`
	Genre       string `xml:"genre,attr"`
	Size        int64  `xml:"size,attr"`
	Suffix      string `xml:"suffix,attr"`
	ContentType string `xml:"contentType,attr"`
	IsVideo     bool   `xml:"isVideo,attr"`
	Path        string `xml:"path,attr"`
	AlbumID     int    `xml:"albumId,attr"`
	ArtistID    int    `xml:"artistId,attr"`
	Type        string `xml:"type,attr"`
}
func subSong(song data.Song) Song {
	return Song{
		ID: song.ID,
		Parent:   0,
		Title:    song.Title,
		Album:    song.Album,
		Artist:   song.Artist,
		IsDir:    false,
		CoverArt: strconv.Itoa(song.ArtID),
		Created:  subTime(song.LastModified),
		Duration: song.Length,
		BitRate:  song.Bitrate,
		Track:    song.Track,
		DiscNumber:  1,
		Year:        song.Year,
		Genre:       song.Genre,
		Size:        song.FileSize,
		Suffix:      path.Ext(song.FileName)[1:],
		ContentType: data.MIMEMap[song.FileTypeID],
		IsVideo:     false,
		Path:        song.FileName,
		AlbumID:     song.AlbumID,
		ArtistID:    song.ArtistID,
		Type:        "music",
	}
}