mirror of
https://github.com/Yetangitu/ampache
synced 2025-10-03 01:39:28 +02:00
1435 lines
46 KiB
PHP
1435 lines
46 KiB
PHP
<?php
|
|
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
|
|
/**
|
|
*
|
|
* LICENSE: GNU General Public License, version 2 (GPLv2)
|
|
* Copyright 2001 - 2014 Ampache.org
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; version 2
|
|
* of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* Subsonic Class
|
|
*
|
|
* This class wrap Ampache to Subsonic API functions. See http://www.subsonic.org/pages/api.jsp
|
|
* These are all static calls.
|
|
*
|
|
*/
|
|
class Subsonic_Api
|
|
{
|
|
/**
|
|
* constructor
|
|
* This really isn't anything to do here, so it's private
|
|
*/
|
|
private function __construct()
|
|
{
|
|
}
|
|
|
|
public static function check_version($input, $version = "1.0.0", $addheader = false)
|
|
{
|
|
// We cannot check client version unfortunately. Most Subsonic client sent a dummy client version...
|
|
/*if (version_compare($input['v'], $version) < 0) {
|
|
ob_end_clean();
|
|
if ($addheader) self::setHeader($input['f']);
|
|
self::apiOutput($input, Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_APIVERSION_CLIENT));
|
|
exit;
|
|
}*/
|
|
}
|
|
|
|
public static function check_parameter($input, $parameter, $addheader = false)
|
|
{
|
|
if (empty($input[$parameter])) {
|
|
ob_end_clean();
|
|
if ($addheader) self::setHeader($input['f']);
|
|
self::apiOutput($input, Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_MISSINGPARAM));
|
|
exit;
|
|
}
|
|
|
|
return $input[$parameter];
|
|
}
|
|
|
|
public static function output_body($ch, $data)
|
|
{
|
|
echo $data;
|
|
ob_flush();
|
|
|
|
return strlen($data);
|
|
}
|
|
|
|
public static function output_header($ch, $header)
|
|
{
|
|
$rheader = trim($header);
|
|
$rhpart = explode(':', $rheader);
|
|
if (!empty($rheader) && count($rhpart) > 1) {
|
|
if ($rhpart[0] != "Transfer-Encoding") {
|
|
header($rheader);
|
|
}
|
|
}
|
|
return strlen($header);
|
|
}
|
|
|
|
public static function follow_stream($url)
|
|
{
|
|
set_time_limit(0);
|
|
|
|
if (function_exists('curl_version')) {
|
|
// Curl support, we stream transparently to avoid redirect. Redirect can fail on few clients
|
|
$ch = curl_init($url);
|
|
curl_setopt_array($ch, array(
|
|
CURLOPT_HEADER => false,
|
|
CURLOPT_RETURNTRANSFER => false,
|
|
CURLOPT_FOLLOWLOCATION => true,
|
|
CURLOPT_WRITEFUNCTION => array('Subsonic_Api', 'output_body'),
|
|
CURLOPT_HEADERFUNCTION => array('Subsonic_Api', 'output_header'),
|
|
// Ignore invalid certificate
|
|
// Default trusted chain is crap anyway and currently no custom CA option
|
|
CURLOPT_SSL_VERIFYPEER => false,
|
|
CURLOPT_SSL_VERIFYHOST => false,
|
|
CURLOPT_TIMEOUT => 0
|
|
));
|
|
curl_exec($ch);
|
|
curl_close($ch);
|
|
} else {
|
|
// Stream media using http redirect if no curl support
|
|
|
|
// Bug fix for android clients looking for /rest/ in destination url
|
|
// Warning: external catalogs will not work!
|
|
$url = str_replace('/play/', '/rest/fake/', $url);
|
|
header("Location: " . $url);
|
|
}
|
|
}
|
|
|
|
public static function setHeader($f)
|
|
{
|
|
if (strtolower($f) == "json") {
|
|
header("Content-type: application/json; charset=" . AmpConfig::get('site_charset'));
|
|
} else if (strtolower($f) == "jsonp") {
|
|
header("Content-type: text/javascript; charset=" . AmpConfig::get('site_charset'));
|
|
} else {
|
|
header("Content-type: text/xml; charset=" . AmpConfig::get('site_charset'));
|
|
}
|
|
}
|
|
|
|
public static function apiOutput($input, $xml)
|
|
{
|
|
$f = $input['f'];
|
|
$callback = $input['callback'];
|
|
self::apiOutput2(strtolower($f), $xml, $callback);
|
|
}
|
|
|
|
public static function apiOutput2($f, $xml, $callback='')
|
|
{
|
|
if ($f == "json") {
|
|
echo json_encode(self::xml2json($xml), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK);
|
|
} else if ($f == "jsonp") {
|
|
echo $callback . '(' . json_encode(self::xml2json($xml), JSON_PRETTY_PRINT) . ')';
|
|
} else {
|
|
$xmlstr = $xml->asXml();
|
|
// Format xml output
|
|
$dom = new DOMDocument();
|
|
$dom->loadXML($xmlstr);
|
|
$dom->formatOutput = true;
|
|
echo $dom->saveXML();
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* xml2json based from http://outlandish.com/blog/xml-to-json/
|
|
* Because we cannot use only json_encode to respect JSON Subsonic API
|
|
*/
|
|
private static function xml2json($xml, $options = array())
|
|
{
|
|
$defaults = array(
|
|
'namespaceSeparator' => ':',//you may want this to be something other than a colon
|
|
'attributePrefix' => '', //to distinguish between attributes and nodes with the same name
|
|
'alwaysArray' => array(), //array of xml tag names which should always become arrays
|
|
'autoArray' => true, //only create arrays for tags which appear more than once
|
|
'textContent' => '$', //key used for the text content of elements
|
|
'autoText' => true, //skip textContent key if node has no attributes or child nodes
|
|
'keySearch' => false, //optional search and replace on tag and attribute names
|
|
'keyReplace' => false, //replace values for above search values (as passed to str_replace())
|
|
'boolean' => true //replace true and false string with boolean values
|
|
);
|
|
$options = array_merge($defaults, $options);
|
|
$namespaces = $xml->getDocNamespaces();
|
|
$namespaces[''] = null; //add base (empty) namespace
|
|
|
|
//get attributes from all namespaces
|
|
$attributesArray = array();
|
|
foreach ($namespaces as $prefix => $namespace) {
|
|
foreach ($xml->attributes($namespace) as $attributeName => $attribute) {
|
|
//replace characters in attribute name
|
|
if ($options['keySearch']) $attributeName =
|
|
str_replace($options['keySearch'], $options['keyReplace'], $attributeName);
|
|
$attributeKey = $options['attributePrefix']
|
|
. ($prefix ? $prefix . $options['namespaceSeparator'] : '')
|
|
. $attributeName;
|
|
$strattr = (string) $attribute;
|
|
if ($options['boolean'] && ($strattr == "true" || $strattr == "false")) {
|
|
$vattr = ($strattr == "true");
|
|
} else {
|
|
$vattr = $strattr;
|
|
}
|
|
$attributesArray[$attributeKey] = $vattr;
|
|
}
|
|
}
|
|
|
|
//get child nodes from all namespaces
|
|
$tagsArray = array();
|
|
foreach ($namespaces as $prefix => $namespace) {
|
|
foreach ($xml->children($namespace) as $childXml) {
|
|
//recurse into child nodes
|
|
$childArray = self::xml2json($childXml, $options);
|
|
list($childTagName, $childProperties) = each($childArray);
|
|
|
|
//replace characters in tag name
|
|
if ($options['keySearch']) $childTagName =
|
|
str_replace($options['keySearch'], $options['keyReplace'], $childTagName);
|
|
//add namespace prefix, if any
|
|
if ($prefix) $childTagName = $prefix . $options['namespaceSeparator'] . $childTagName;
|
|
|
|
if (!isset($tagsArray[$childTagName])) {
|
|
//only entry with this key
|
|
//test if tags of this type should always be arrays, no matter the element count
|
|
$tagsArray[$childTagName] =
|
|
in_array($childTagName, $options['alwaysArray']) || !$options['autoArray']
|
|
? array($childProperties) : $childProperties;
|
|
} elseif (
|
|
is_array($tagsArray[$childTagName]) && array_keys($tagsArray[$childTagName])
|
|
=== range(0, count($tagsArray[$childTagName]) - 1)
|
|
) {
|
|
//key already exists and is integer indexed array
|
|
$tagsArray[$childTagName][] = $childProperties;
|
|
} else {
|
|
//key exists so convert to integer indexed array with previous value in position 0
|
|
$tagsArray[$childTagName] = array($tagsArray[$childTagName], $childProperties);
|
|
}
|
|
}
|
|
}
|
|
|
|
//get text content of node
|
|
$textContentArray = array();
|
|
$plainText = trim((string) $xml);
|
|
if ($plainText !== '') $textContentArray[$options['textContent']] = $plainText;
|
|
|
|
//stick it all together
|
|
$propertiesArray = !$options['autoText'] || $attributesArray || $tagsArray || ($plainText === '')
|
|
? array_merge($attributesArray, $tagsArray, $textContentArray) : $plainText;
|
|
|
|
//return node as array
|
|
return array(
|
|
$xml->getName() => $propertiesArray
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* ping
|
|
* Simple server ping to test connectivity with the server.
|
|
* Takes no parameter.
|
|
*/
|
|
public static function ping($input)
|
|
{
|
|
// Don't check client API version here. Some client give version 0.0.0 for ping command
|
|
|
|
self::apiOutput($input, Subsonic_XML_Data::createSuccessResponse());
|
|
}
|
|
|
|
/**
|
|
* getLicense
|
|
* Get details about the software license. Always return a valid default license.
|
|
* Takes no parameter.
|
|
*/
|
|
public static function getlicense($input)
|
|
{
|
|
self::check_version($input);
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addLicense($r);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getMusicFolders
|
|
* Get all configured top-level music folders (= ampache catalogs).
|
|
* Takes no parameter.
|
|
*/
|
|
public static function getmusicfolders($input)
|
|
{
|
|
self::check_version($input);
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addMusicFolders($r, Catalog::get_catalogs());
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getIndexes
|
|
* Get an indexed structure of all artists.
|
|
* Takes optional musicFolderId and optional ifModifiedSince in parameters.
|
|
*/
|
|
public static function getindexes($input)
|
|
{
|
|
self::check_version($input);
|
|
|
|
$musicFolderId = $input['musicFolderId'];
|
|
$ifModifiedSince = $input['ifModifiedSince'];
|
|
|
|
$catalogs = array();
|
|
if (!empty($musicFolderId)) {
|
|
$catalogs[] = $musicFolderId;
|
|
} else {
|
|
$catalogs = Catalog::get_catalogs();
|
|
}
|
|
|
|
$lastmodified = 0;
|
|
$fcatalogs = array();
|
|
|
|
foreach ($catalogs as $id) {
|
|
$clastmodified = 0;
|
|
$catalog = Catalog::create_from_id($id);
|
|
|
|
if ($catalog->last_update > $clastmodified) $clastmodified = $catalog->last_update;
|
|
if ($catalog->last_add > $clastmodified) $clastmodified = $catalog->last_add;
|
|
if ($catalog->last_clean > $clastmodified) $clastmodified = $catalog->last_clean;
|
|
|
|
if ($clastmodified > $lastmodified) $lastmodified = $clastmodified;
|
|
if (!empty($ifModifiedSince) && $clastmodified > $ifModifiedSince) $fcatalogs[] = $id;
|
|
}
|
|
if (empty($ifModifiedSince)) $fcatalogs = $catalogs;
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
if (count($fcatalogs) > 0) {
|
|
$artists = Catalog::get_artists($fcatalogs);
|
|
Subsonic_XML_Data::addArtistsIndexes($r, $artists, $lastmodified);
|
|
}
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getMusicDirectory
|
|
* Get a list of all files in a music directory.
|
|
* Takes the directory id in parameters.
|
|
*/
|
|
public static function getmusicdirectory($input)
|
|
{
|
|
self::check_version($input);
|
|
|
|
$id = self::check_parameter($input, 'id');
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
if (Subsonic_XML_Data::isArtist($id)) {
|
|
$artist = new Artist(Subsonic_XML_Data::getAmpacheId($id));
|
|
Subsonic_XML_Data::addArtistDirectory($r, $artist);
|
|
} else if (Subsonic_XML_Data::isAlbum($id)) {
|
|
$album = new Album(Subsonic_XML_Data::getAmpacheId($id));
|
|
Subsonic_XML_Data::addAlbumDirectory($r, $album);
|
|
}
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getGenres
|
|
* Get all genres.
|
|
* Takes no parameter.
|
|
*/
|
|
public static function getgenres($input)
|
|
{
|
|
self::check_version($input, "1.9.0");
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addGenres($r, Tag::get_tags());
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getArtists
|
|
* Get all artists.
|
|
* Takes no parameter.
|
|
*/
|
|
public static function getartists($input)
|
|
{
|
|
self::check_version($input, "1.7.0");
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
$artists = Catalog::get_artists(Catalog::get_catalogs());
|
|
Subsonic_XML_Data::addArtistsRoot($r, $artists);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getArtist
|
|
* Get details fro an artist, including a list of albums.
|
|
* Takes the artist id in parameter.
|
|
*/
|
|
public static function getartist($input)
|
|
{
|
|
self::check_version($input, "1.7.0");
|
|
|
|
$artistid = self::check_parameter($input, 'id');
|
|
|
|
$artist = new Artist(Subsonic_XML_Data::getAmpacheId($artistid));
|
|
if (empty($artist->name)) {
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND, "Artist not found.");
|
|
} else {
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addArtist($r, $artist, true, true);
|
|
}
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getAlbum
|
|
* Get details for an album, including a list of songs.
|
|
* Takes the album id in parameter.
|
|
*/
|
|
public static function getalbum($input)
|
|
{
|
|
self::check_version($input, "1.7.0");
|
|
|
|
$albumid = self::check_parameter($input, 'id');
|
|
|
|
$album = new Album(Subsonic_XML_Data::getAmpacheId($albumid));
|
|
if (empty($album->name)) {
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND, "Album not found.");
|
|
} else {
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addAlbum($r, $album, true);
|
|
}
|
|
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getVideos
|
|
* Get all videos.
|
|
* Takes no parameter.
|
|
* Not supported yet.
|
|
*/
|
|
public static function getvideos($input)
|
|
{
|
|
self::check_version($input, "1.7.0");
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addVideos($r);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getAlbumList
|
|
* Get a list of random, newest, highest rated etc. albums.
|
|
* Takes the list type with optional size and offset in parameters.
|
|
*/
|
|
public static function getalbumlist($input, $elementName="albumList")
|
|
{
|
|
self::check_version($input, "1.2.0");
|
|
|
|
$type = self::check_parameter($input, 'type');
|
|
|
|
$size = $input['size'];
|
|
$offset = $input['offset'];
|
|
|
|
$albums = array();
|
|
if ($type == "random") {
|
|
$albums = Album::get_random($size);
|
|
} else if ($type == "newest") {
|
|
$albums = Stats::get_newest("album", $size, $offset);
|
|
} else if ($type == "highest") {
|
|
$albums = Rating::get_highest("album", $size, $offset);
|
|
} else if ($type == "frequent") {
|
|
$albums = Stats::get_top("album", $size, '', $offset);
|
|
} else if ($type == "recent") {
|
|
$albums = Stats::get_recent("album", $size, $offset);
|
|
} else if ($type == "starred") {
|
|
$albums = Userflag::get_latest('album');
|
|
} else if ($type == "alphabeticalByName") {
|
|
$albums = Catalog::get_albums($size, $offset);
|
|
} else if ($type == "alphabeticalByArtist") {
|
|
$albums = Catalog::get_albums_by_artist($size, $offset);
|
|
}
|
|
|
|
if (count($albums)) {
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addAlbumList($r, $albums, $elementName);
|
|
} else {
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
}
|
|
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getAlbumList2
|
|
* See getAlbumList.
|
|
*/
|
|
public static function getalbumlist2($input)
|
|
{
|
|
self::check_version($input, "1.7.0");
|
|
self::getAlbumList($input, "albumList2");
|
|
}
|
|
|
|
/**
|
|
* getRandomSongs
|
|
* Get random songs matching the given criteria.
|
|
* Takes the optional size, genre, fromYear, toYear and music folder id in parameters.
|
|
*/
|
|
public static function getrandomsongs($input)
|
|
{
|
|
self::check_version($input, "1.2.0");
|
|
|
|
$size = $input['size'];
|
|
if (!$size) $size = 10;
|
|
$genre = $input['genre'];
|
|
$fromYear = $input['fromYear'];
|
|
$toYear = $input['toYear'];
|
|
$musicFolderId = $input['musicFolderId'];
|
|
|
|
$search = array();
|
|
$search['limit'] = $size;
|
|
$search['random'] = $size;
|
|
$search['type'] = "song";
|
|
$i = 0;
|
|
if ($genre) {
|
|
$search['rule_'.$i.'_input'] = $genre;
|
|
$search['rule_'.$i.'_operator'] = 0;
|
|
$search['rule_'.$i.''] = "tag";
|
|
++$i;
|
|
}
|
|
if ($fromYear) {
|
|
$search['rule_'.$i.'_input'] = $fromYear;
|
|
$search['rule_'.$i.'_operator'] = 0;
|
|
$search['rule_'.$i.''] = "year";
|
|
++$i;
|
|
}
|
|
if ($toYear) {
|
|
$search['rule_'.$i.'_input'] = $toYear;
|
|
$search['rule_'.$i.'_operator'] = 1;
|
|
$search['rule_'.$i.''] = "year";
|
|
++$i;
|
|
}
|
|
if ($musicFolderId) {
|
|
if (Subsonic_XML_Data::isArtist($musicFolderId)) {
|
|
$artist = new Artist(Subsonic_XML_Data::getAmpacheId($musicFolderId));
|
|
$finput = $artist->name;
|
|
$ftype = "artist";
|
|
} else if (Subsonic_XML_Data::isAlbum($musicFolderId)) {
|
|
$album = new Album(Subsonic_XML_Data::getAmpacheId($musicFolderId));
|
|
$finput = $album->name;
|
|
$ftype = "artist";
|
|
}
|
|
$search['rule_'.$i.'_input'] = $finput;
|
|
$search['rule_'.$i.'_operator'] = 4;
|
|
$search['rule_'.$i.''] = $ftype;
|
|
++$i;
|
|
}
|
|
if ($i > 0) {
|
|
$songs = Random::advanced("song", $search);
|
|
} else {
|
|
$songs = Random::get_default($size);
|
|
}
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addRandomSongs($r, $songs);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getSong
|
|
* Get details for a song
|
|
* Takes the song id in parameter.
|
|
*/
|
|
public static function getsong($input)
|
|
{
|
|
self::check_version($input, "1.7.0");
|
|
|
|
$songid = self::check_parameter($input, 'id');
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
$song = new Song(Subsonic_XML_Data::getAmpacheId($songid));
|
|
Subsonic_XML_Data::addSong($r, $song);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getSongsByGenre
|
|
* Get songs in a given genre.
|
|
* Takes the genre with optional count and offset in parameters.
|
|
*/
|
|
public static function getsongsbygenre($input)
|
|
{
|
|
self::check_version($input, "1.9.0");
|
|
|
|
$genre = self::check_parameter($input, 'genre');
|
|
$count = $input['count'];
|
|
$offset = $input['offset'];
|
|
|
|
$tag = Tag::construct_from_name($genre);
|
|
if ($tag->id) {
|
|
$songs = Tag::get_tag_objects("song", $tag->id, $count, $offset);
|
|
}
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addSongsByGenre($r, $songs);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getNowPlaying
|
|
* Get what is currently being played by all users.
|
|
* Takes no parameter.
|
|
*/
|
|
public static function getnowplaying($input)
|
|
{
|
|
self::check_version($input);
|
|
|
|
$data = Stream::get_now_playing();
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addNowPlaying($r, $data);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* search2
|
|
* Get albums, artists and songs matching the given criteria.
|
|
* Takes query with optional artist count, artist offset, album count, album offset, song count and song offset in parameters.
|
|
*/
|
|
public static function search2($input, $elementName="searchResult2")
|
|
{
|
|
self::check_version($input, "1.2.0");
|
|
|
|
$query = self::check_parameter($input, 'query');
|
|
|
|
$artistCount = $input['artistCount'];
|
|
$artistOffset = $input['artistOffset'];
|
|
$albumCount = $input['albumCount'];
|
|
$albumOffset = $input['albumOffset'];
|
|
$songCount = $input['songCount'];
|
|
$songOffset = $input['songOffset'];
|
|
|
|
$sartist = array();
|
|
$sartist['limit'] = $artistCount;
|
|
if ($artistOffset) $sartist['offset'] = $artistOffset;
|
|
$sartist['rule_1_input'] = $query;
|
|
$sartist['rule_1_operator'] = 0;
|
|
$sartist['rule_1'] = "name";
|
|
$sartist['type'] = "artist";
|
|
$artists = Search::run($sartist);
|
|
|
|
$salbum = array();
|
|
$salbum['limit'] = $albumCount;
|
|
if ($albumOffset) $salbum['offset'] = $albumOffset;
|
|
$salbum['rule_1_input'] = $query;
|
|
$salbum['rule_1_operator'] = 0;
|
|
$salbum['rule_1'] = "title";
|
|
$salbum['type'] = "album";
|
|
$albums = Search::run($salbum);
|
|
|
|
$ssong = array();
|
|
$ssong['limit'] = $songCount;
|
|
if ($songOffset) $ssong['offset'] = $songOffset;
|
|
$ssong['rule_1_input'] = $query;
|
|
$ssong['rule_1_operator'] = 0;
|
|
$ssong['rule_1'] = "anywhere";
|
|
$ssong['type'] = "song";
|
|
$songs = Search::run($ssong);
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addSearchResult($r, $artists, $albums, $songs, $elementName);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* search3
|
|
* See search2.
|
|
*/
|
|
public static function search3($input)
|
|
{
|
|
self::check_version($input, "1.7.0");
|
|
self::search2($input, "searchResult3");
|
|
}
|
|
|
|
/**
|
|
* getPlaylists
|
|
* Get all playlists a user is allowed to play.
|
|
* Takes optional user in parameter.
|
|
*/
|
|
public static function getplaylists($input)
|
|
{
|
|
self::check_version($input);
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
$username = $input['username'];
|
|
|
|
// Don't allow playlist listing for another user
|
|
if (empty($username) || $username == $GLOBALS['user']->username) {
|
|
Subsonic_XML_Data::addPlaylists($r, Playlist::get_playlists());
|
|
} else {
|
|
$user = User::get_from_username($username);
|
|
if ($user->id) {
|
|
Subsonic_XML_Data::addPlaylists($r, Playlist::get_users($user->id));
|
|
} else {
|
|
Subsonic_XML_Data::addPlaylists($r, array());
|
|
}
|
|
}
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getPlaylist
|
|
* Get the list of files in a saved playlist.
|
|
* Takes the playlist id in parameters.
|
|
*/
|
|
public static function getplaylist($input)
|
|
{
|
|
self::check_version($input);
|
|
|
|
$playlistid = self::check_parameter($input, 'id');
|
|
|
|
$playlist = new Playlist($playlistid);
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addPlaylist($r, $playlist, true);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* createPlaylist
|
|
* Create (or updates) a playlist.
|
|
* Takes playlist id in parameter if updating, name in parameter if creating and a list of song id for the playlist.
|
|
*/
|
|
public static function createplaylist($input)
|
|
{
|
|
self::check_version($input, "1.2.0");
|
|
|
|
$playlistId = $input['playlistId'];
|
|
$name = $input['name'];
|
|
$songId = $input['songId'];
|
|
|
|
if ($playlistId) {
|
|
self::_updatePlaylist($playlistId, $name, $songId);
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
} else if (!empty($name)) {
|
|
$playlistId = Playlist::create($name, 'public');
|
|
if (count($songId) > 0) {
|
|
self::_updatePlaylist($playlistId, "", $songId);
|
|
}
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
} else {
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_MISSINGPARAM);
|
|
}
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
private static function _updatePlaylist($id, $name, $songsIdToAdd = array(), $songIndexToRemove = array(), $public = true)
|
|
{
|
|
$playlist = new Playlist($id);
|
|
|
|
$newdata = array();
|
|
$newdata['name'] = (!empty($name)) ? $name : $playlist->name;
|
|
$newdata['pl_type'] = ($public) ? "public" : "private";
|
|
$playlist->update($newdata);
|
|
|
|
if (!is_array($songsIdToAdd)) {
|
|
$songsIdToAdd = array($songsIdToAdd);
|
|
}
|
|
if (count($songsIdToAdd) > 0) {
|
|
$playlist->add_songs(Subsonic_XML_Data::getAmpacheIds($songsIdToAdd));
|
|
}
|
|
|
|
if (!is_array($songIndexToRemove)) {
|
|
$songIndexToRemove = array($songIndexToRemove);
|
|
}
|
|
if (is_array($songIndexToRemove) && count($songIndexToRemove) > 0) {
|
|
$tracks = Subsonic_XML_Data::getAmpacheIds($songIndexToRemove);
|
|
foreach ($tracks as $track) {
|
|
$playlist->delete_track_number($track);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* updatePlaylist
|
|
* Update a playlist.
|
|
* Takes playlist id in parameter with optional name, comment, public level and a list of song id to add/remove.
|
|
*/
|
|
public static function updateplaylist($input)
|
|
{
|
|
self::check_version($input, "1.7.0");
|
|
|
|
$playlistId = self::check_parameter($input, 'playlistId');
|
|
|
|
$name = $input['name'];
|
|
$comment = $input['comment']; // Not supported.
|
|
$public = boolean($input['public']);
|
|
echo $public;
|
|
$songIdToAdd = $input['songIdToAdd'];
|
|
$songIndexToRemove = $input['songIndexToRemove'];
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* deletePlaylist
|
|
* Delete a saved playlist.
|
|
* Takes playlist id in parameter.
|
|
*/
|
|
public static function deleteplaylist($input)
|
|
{
|
|
self::check_version($input, "1.2.0");
|
|
|
|
$playlistId = self::check_parameter($input, 'playlistId');
|
|
|
|
$playlist = new Playlist($playlistId);
|
|
$playlist->delete();
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* stream
|
|
* Streams a given media file.
|
|
* Takes the file id in parameter with optional max bit rate, file format, time offset, size and estimate content length option.
|
|
*/
|
|
public static function stream($input)
|
|
{
|
|
self::check_version($input, "1.0.0", true);
|
|
|
|
$fileid = self::check_parameter($input, 'id', true);
|
|
|
|
$maxBitRate = $input['maxBitRate']; // Not supported.
|
|
$format = $input['format']; // mp3, flv or raw. Not supported.
|
|
$timeOffset = $input['timeOffset']; // For video streaming. Not supported.
|
|
$size = $input['size']; // For video streaming. Not supported.
|
|
$maxBitRate = $input['maxBitRate']; // For video streaming. Not supported.
|
|
$estimateContentLength = $input['estimateContentLength']; // Force content-length guessing if transcode
|
|
|
|
$params = '&client=' . $input['c'];
|
|
if ($estimateContentLength == 'true') {
|
|
$params .= '&content_length=required';
|
|
}
|
|
$url = Song::play_url(Subsonic_XML_Data::getAmpacheId($fileid), $params);
|
|
self::follow_stream($url);
|
|
}
|
|
|
|
/**
|
|
* download
|
|
* Downloads a given media file.
|
|
* Takes the file id in parameter.
|
|
*/
|
|
public static function download($input)
|
|
{
|
|
self::check_version($input, "1.0.0", true);
|
|
|
|
$fileid = self::check_parameter($input, 'id', true);
|
|
|
|
$url = Song::play_url(Subsonic_XML_Data::getAmpacheId($fileid), '&action=download' . '&client=' . $input['c']);
|
|
self::follow_stream($url);
|
|
}
|
|
|
|
/**
|
|
* hls
|
|
* Create an HLS playlist.
|
|
* Takes the file id in parameter with optional max bit rate.
|
|
*/
|
|
public static function hls($input)
|
|
{
|
|
self::check_version($input, "1.7.0", true);
|
|
|
|
$fileid = self::check_parameter($input, 'id', true);
|
|
|
|
$bitRate = $input['bitRate']; // Not supported.
|
|
|
|
$media = array();
|
|
$media['object_type'] = 'song';
|
|
$media['object_id'] = Subsonic_XML_Data::getAmpacheId($fileid);
|
|
|
|
$medias = array();
|
|
$medias[] = $media;
|
|
$stream = new Stream_Playlist();
|
|
$stream->add($medias);
|
|
|
|
header('Content-Type: application/vnd.apple.mpegurl;');
|
|
$stream->create_m3u();
|
|
}
|
|
|
|
/**
|
|
* getCoverArt
|
|
* Get a cover art image.
|
|
* Takes the cover art id in parameter.
|
|
*/
|
|
public static function getcoverart($input)
|
|
{
|
|
self::check_version($input, "1.0.0", true);
|
|
|
|
$id = self::check_parameter($input, 'id', true);
|
|
$size = $input['size'];
|
|
|
|
$art = null;
|
|
if (Subsonic_XML_Data::isArtist($id)) {
|
|
$art = new Art(Subsonic_XML_Data::getAmpacheId($id), "artist");
|
|
} else if (Subsonic_XML_Data::isAlbum($id)) {
|
|
$art = new Art(Subsonic_XML_Data::getAmpacheId($id), "album");
|
|
} else if (Subsonic_XML_Data::isSong($id)) {
|
|
$art = new Art(Subsonic_XML_Data::getAmpacheId($id), "song");
|
|
}
|
|
|
|
if ($art != null) {
|
|
$art->get_db();
|
|
if (!$size) {
|
|
header('Content-type: ' . $art->raw_mime);
|
|
header('Content-Length: ' . strlen($art->raw));
|
|
echo $art->raw;
|
|
} else {
|
|
$dim = array();
|
|
$dim['width'] = $size;
|
|
$dim['height'] = $size;
|
|
$thumb = $art->get_thumb($dim);
|
|
header('Content-type: ' . $thumb['thumb_mime']);
|
|
header('Content-Length: ' . strlen($thumb['thumb']));
|
|
echo $thumb['thumb'];
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* setRating
|
|
* Sets the rating for a music file.
|
|
* Takes the file id and rating in parameters.
|
|
*/
|
|
public static function setrating($input)
|
|
{
|
|
self::check_version($input, "1.6.0");
|
|
|
|
$id = self::check_parameter($input, 'id');
|
|
$rating = $input['rating'];
|
|
|
|
$robj = null;
|
|
if (Subsonic_XML_Data::isArtist($id)) {
|
|
$robj = new Rating(Subsonic_XML_Data::getAmpacheId($id), "artist");
|
|
} else if (Subsonic_XML_Data::isAlbum($id)) {
|
|
$robj = new Rating(Subsonic_XML_Data::getAmpacheId($id), "album");
|
|
} else if (Subsonic_XML_Data::isSong($id)) {
|
|
$robj = new Rating(Subsonic_XML_Data::getAmpacheId($id), "song");
|
|
}
|
|
|
|
if ($robj != null) {
|
|
$robj->set_rating($rating);
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
} else {
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND, "Media not found.");
|
|
}
|
|
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getStarred
|
|
* Get starred songs, albums and artists.
|
|
* Takes no parameter.
|
|
* Not supported.
|
|
*/
|
|
public static function getstarred($input, $elementName="starred")
|
|
{
|
|
self::check_version($input, "1.7.0");
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
Subsonic_XML_Data::addStarred($r, Userflag::get_latest('artist'), Userflag::get_latest('album'), Userflag::get_latest('song'), $elementName);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
|
|
/**
|
|
* getStarred2
|
|
* See getStarred.
|
|
*/
|
|
public static function getstarred2($input)
|
|
{
|
|
self::getStarred($input, "starred2");
|
|
}
|
|
|
|
/**
|
|
* star
|
|
* Attaches a star to a song, album or artist.
|
|
* Takes the optional file id, album id or artist id in parameters.
|
|
* Not supported.
|
|
*/
|
|
public static function star($input)
|
|
{
|
|
self::check_version($input, "1.7.0");
|
|
|
|
self::_setStar($input, true);
|
|
}
|
|
|
|
/**
|
|
* unstar
|
|
* Removes the star from a song, album or artist.
|
|
* Takes the optional file id, album id or artist id in parameters.
|
|
* Not supported.
|
|
*/
|
|
public static function unstar($input)
|
|
{
|
|
self::check_version($input, "1.7.0");
|
|
|
|
self::_setStar($input, false);
|
|
}
|
|
|
|
private static function _setStar($input, $star)
|
|
{
|
|
$id = $input['id'];
|
|
$albumId = $input['albumId'];
|
|
$artistId = $input['artistId'];
|
|
|
|
// Normalize all in one array
|
|
$ids = array();
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
if ($id) {
|
|
if (!is_array($id)) {
|
|
$id = array($id);
|
|
}
|
|
foreach ($id as $i) {
|
|
$aid = Subsonic_XML_Data::getAmpacheId($i);
|
|
if (Subsonic_XML_Data::isArtist($i)) {
|
|
$type = 'artist';
|
|
} else if (Subsonic_XML_Data::isAlbum($i)) {
|
|
$type = 'album';
|
|
} else if (Subsonic_XML_Data::isSong($i)) {
|
|
$type = 'song';
|
|
}
|
|
$ids[] = array('id' => $aid, 'type' => $type);
|
|
}
|
|
} else if ($albumId) {
|
|
if (!is_array($albumId)) {
|
|
$albumId = array($albumId);
|
|
}
|
|
foreach ($albumId as $i) {
|
|
$aid = Subsonic_XML_Data::getAmpacheId($i);
|
|
$ids[] = array('id' => $aid, 'album');
|
|
}
|
|
} else if ($artistId) {
|
|
if (!is_array($artistId)) {
|
|
$artistId = array($artistId);
|
|
}
|
|
foreach ($artistId as $i) {
|
|
$aid = Subsonic_XML_Data::getAmpacheId($i);
|
|
$ids[] = array('id' => $aid, 'artist');
|
|
}
|
|
} else {
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_MISSINGPARAM);
|
|
}
|
|
|
|
foreach ($ids as $i) {
|
|
$flag = new Userflag($i['id'], $i['type']);
|
|
$flag->set_flag($star);
|
|
}
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getUser
|
|
* Get details about a given user.
|
|
* Takes the username in parameter.
|
|
* Not supported.
|
|
*/
|
|
public static function getuser($input)
|
|
{
|
|
self::check_version($input, "1.3.0");
|
|
|
|
$username = self::check_parameter($input, 'username');
|
|
|
|
if ($GLOBALS['user']->access >= 100 || $GLOBALS['user']->username == $username) {
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
if ($GLOBALS['user']->username == $username) {
|
|
$user = $GLOBALS['user'];
|
|
} else {
|
|
$user = User::get_from_username($username);
|
|
}
|
|
Subsonic_XML_Data::addUser($r, $user);
|
|
} else {
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_UNAUTHORIZED, $GLOBALS['user']->username . ' is not authorized to get details for other users.');
|
|
}
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getUsers
|
|
* Get details about a given user.
|
|
* Takes no parameter.
|
|
* Not supported.
|
|
*/
|
|
public static function getusers($input)
|
|
{
|
|
self::check_version($input, "1.7.0");
|
|
|
|
if ($GLOBALS['user']->access >= 100) {
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
$users = User::get_valid_users();
|
|
Subsonic_XML_Data::addUsers($r, $users);
|
|
} else {
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_UNAUTHORIZED, $GLOBALS['user']->username . ' is not authorized to get details for other users.');
|
|
}
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getInternetRadioStations
|
|
* Get all internet radio stations
|
|
* Takes no parameter.
|
|
*/
|
|
public static function getinternetradiostations($input)
|
|
{
|
|
self::check_version($input, "1.9.0");
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
$radios = Radio::get_all_radios();
|
|
Subsonic_XML_Data::addRadios($r, $radios);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getShares
|
|
* Get information about shared media this user is allowed to manage.
|
|
* Takes no parameter.
|
|
*/
|
|
public static function getshares($input)
|
|
{
|
|
self::check_version($input, "1.6.0");
|
|
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
$shares = Share::get_share_list();
|
|
Subsonic_XML_Data::addShares($r, $shares);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* createShare
|
|
* Create a public url that can be used by anyone to stream media.
|
|
* Takes the file id with optional description and expires parameters.
|
|
*/
|
|
public static function createshare($input)
|
|
{
|
|
self::check_version($input, "1.6.0");
|
|
|
|
$id = self::check_parameter($input, 'id');
|
|
$description = $input['description'];
|
|
$expires = $input['expires'];
|
|
|
|
if (AmpConfig::get('share')) {
|
|
if ($expires) {
|
|
$expire_days = round((($expires / 1000) - time()) / 86400, 0, PHP_ROUND_HALF_EVEN);
|
|
} else {
|
|
$expire_days = AmpConfig::get('share_expire');
|
|
}
|
|
|
|
$object_id = Subsonic_XML_Data::getAmpacheId($id);
|
|
if (Subsonic_XML_Data::isAlbum($id)) {
|
|
$object_type = 'album';
|
|
} else if (Subsonic_XML_Data::isSong($id)) {
|
|
$object_type = 'song';
|
|
}
|
|
|
|
if (!empty($object_type)) {
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
$shares = array();
|
|
$shares[] = Share::create_share($object_type, $object_id, true, Access::check_function('download'), $expire_days, Share::generate_secret(), 0, $description);
|
|
Subsonic_XML_Data::addShares($r, $shares);
|
|
} else {
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
}
|
|
} else {
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_UNAUTHORIZED);
|
|
}
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* deleteShare
|
|
* Delete an existing share.
|
|
* Takes the share id to delete in parameters.
|
|
*/
|
|
public static function deleteshare($input)
|
|
{
|
|
self::check_version($input, "1.6.0");
|
|
|
|
$id = self::check_parameter($input, 'id');
|
|
|
|
if (AmpConfig::get('share')) {
|
|
if (Share::delete_share($id)) {
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
} else {
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
}
|
|
} else {
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_UNAUTHORIZED);
|
|
}
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**** CURRENT UNSUPPORTED FUNCTIONS ****/
|
|
|
|
/**
|
|
* getLyrics
|
|
* Searches and returns lyrics for a given song.
|
|
* Takes the optional artist and title in parameters.
|
|
*/
|
|
public static function getlyrics($input)
|
|
{
|
|
self::check_version($input, "1.2.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* updateShare
|
|
* Update the description and/or expiration date for an existing share.
|
|
* Takes the share id to update with optional description and expires parameters.
|
|
* Not supported.
|
|
*/
|
|
public static function updateshare($input)
|
|
{
|
|
self::check_version($input, "1.6.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* scrobble
|
|
* Scrobbles a given music file on last.fm.
|
|
* Takes the file id with optional time and submission parameters.
|
|
* Not supported. Already done by Ampache if plugin enabled.
|
|
*/
|
|
public static function scrobble($input)
|
|
{
|
|
self::check_version($input, "1.5.0");
|
|
|
|
// Ignore error to not break clients
|
|
$r = Subsonic_XML_Data::createSuccessResponse();
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* createUser
|
|
* Create a new user.
|
|
* Takes the username, password and email with optional roles in parameters.
|
|
* Not supported.
|
|
*/
|
|
public static function createuser($input)
|
|
{
|
|
self::check_version($input, "1.1.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* deleteUser
|
|
* Delete an existing user.
|
|
* Takes the username in parameter.
|
|
* Not supported.
|
|
*/
|
|
public static function deleteuser($input)
|
|
{
|
|
self::check_version($input, "1.3.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* changePassword
|
|
* Change the password of an existing user.
|
|
* Takes the username with new password in parameters.
|
|
* Not supported.
|
|
*/
|
|
public static function changepassword($input)
|
|
{
|
|
self::check_version($input, "1.1.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getPodcasts
|
|
* Get all podcast channels.
|
|
* Takes the optional includeEpisodes and channel id in parameters
|
|
* Not supported.
|
|
*/
|
|
public static function getpodcasts($input)
|
|
{
|
|
self::check_version($input, "1.6.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* refreshPodcasts
|
|
* Request the server to check for new podcast episodes.
|
|
* Takes no parameters.
|
|
* Not supported.
|
|
*/
|
|
public static function refreshpodcasts($input)
|
|
{
|
|
self::check_version($input, "1.9.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* createPodcastChannel
|
|
* Add a new podcast channel.
|
|
* Takes the podcast url in parameter.
|
|
* Not supported.
|
|
*/
|
|
public static function createpodcastchannel($input)
|
|
{
|
|
self::check_version($input, "1.9.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* deletePodcastChannel
|
|
* Delete an existing podcast channel
|
|
* Takes the podcast id in parameter.
|
|
* Not supported.
|
|
*/
|
|
public static function deletepodcastchannel($input)
|
|
{
|
|
self::check_version($input, "1.9.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* deletePodcastEpisode
|
|
* Delete a podcast episode
|
|
* Takes the podcast episode id in parameter.
|
|
* Not supported.
|
|
*/
|
|
public static function deletepodcastepisode($input)
|
|
{
|
|
self::check_version($input, "1.9.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* downloadPodcastEpisode
|
|
* Request the server to download a podcast episode
|
|
* Takes the podcast episode id in parameter.
|
|
* Not supported.
|
|
*/
|
|
public static function downloadpodcastepisode($input)
|
|
{
|
|
self::check_version($input, "1.9.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* jukeboxControl
|
|
* Control the jukebox.
|
|
* Takes the action with optional index, offset, song id and volume gain in parameters.
|
|
* Not supported.
|
|
*/
|
|
public static function jukeboxcontrol($input)
|
|
{
|
|
self::check_version($input, "1.2.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getChatMessages
|
|
* Get the current chat messages.
|
|
* Takes no parameter.
|
|
* Not supported.
|
|
*/
|
|
public static function getchatmessages($input)
|
|
{
|
|
self::check_version($input, "1.2.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* addChatMessages
|
|
* Add a message to the chat.
|
|
* Takes the message in parameter.
|
|
* Not supported.
|
|
*/
|
|
public static function addchatmessages($input)
|
|
{
|
|
self::check_version($input, "1.2.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* getBookmarks
|
|
* Get all user bookmarks.
|
|
* Takes no parameter.
|
|
* Not supported.
|
|
*/
|
|
public static function getbookmarks($input)
|
|
{
|
|
self::check_version($input, "1.9.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* createBookmark
|
|
* Creates or updates a bookmark.
|
|
* Takes the file id and position with optional comment in parameters.
|
|
* Not supported.
|
|
*/
|
|
public static function createbookmark($input)
|
|
{
|
|
self::check_version($input, "1.9.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
|
|
/**
|
|
* deleteBookmark
|
|
* Delete an existing bookmark.
|
|
* Takes the file id in parameter.
|
|
* Not supported.
|
|
*/
|
|
public static function deletebookmark($input)
|
|
{
|
|
self::check_version($input, "1.9.0");
|
|
|
|
$r = Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND);
|
|
self::apiOutput($input, $r);
|
|
}
|
|
}
|