sonos icon indicating copy to clipboard operation
sonos copied to clipboard

Accessing Sonos Favorites

Open Nibbler73 opened this issue 9 years ago • 6 comments

Hello,

I'm experimenting by building a simple and child-proof controller for the sonos box. Based on a RPi with the Touchscreen and as I'm developing this in PHP, your sonos library seems to be the awesome tool to talk to Sonos.

I'd like to list the Sonos Favorites in a cover-flow style and start playing the selected Spotify/Radio/Whatever if tapped on.

I can fetch the Playlists from the Network which works great including the Album-Art.

Is there a way to fetch the Sonos Favorites, as only these are able to include Radio Stations (that is, internet radio, Spotify Radio, Amazon Prime Radio, ...).

Thanks

Nibbler73 avatar May 04 '16 22:05 Nibbler73

Hi, the library doesn't support Sonos Favourites at the moment. I'll take a look at adding this when I get some time

duncan3dc avatar May 05 '16 19:05 duncan3dc

I've done a bit of work on this (on the favourites branch), but as these lists can contain tracks, streams, and collections of tracks. It's not simple to handle them, eg:

$controller = $sonos->getControllerByRoom("The Hall");
$queue = $controller->getQueue();

$favourites = new Favourites($controller);

foreach ($favourites->getTracks() as $track) {
    if (isset($track->title)) {
        echo $track->title . "\n";
    } else {
        echo $track->getName() . "\n";
    }

    if ($track instanceof Stream) {
        echo "\tIgnoring Stream\n";
        continue;
    }

    if ($track instanceof \Countable) {
        if (count($track) < 1) {
            echo "\tIgnoring empty countable\n";
            continue;
        }
    }

    $queue->addTrack($track);
}

I'll continue to think about it, but it might require changing some existing classes and therefore need to be part of 2.0

duncan3dc avatar May 08 '16 19:05 duncan3dc

This looks promising, thanks.

From the Controller-App on mobile devices, I would assume the Collection or Countable returned is most probably a Playlist from the Favourites.

Should fetching the favorites work like this?

$favourites = $sonos->getFavourites();

I'll give it a try and see if I can start working with the new Favourites() object.

Thanks for the quick reaction.

Nibbler73 avatar May 09 '16 17:05 Nibbler73

Yeh a countable would be a playlist, it could be a Spotify playlist, or a Sonos playlist, or anything else though. I've not added a $sonos->getFavourites() method yet, but that would probably make it in once I've figured everything else out

duncan3dc avatar May 09 '16 17:05 duncan3dc

Hi, I test this on 2.0 version. I can get list of favourites but I can't find how to add it in queue...

zoic21 avatar Jan 14 '18 09:01 zoic21

I have done this from my code with the following methods and a SonosFavorite class. Maybe this can help...

class SonosFavorite implements UriInterface 
{
    protected $title;    
    protected $uri;    
    protected $metadata;
    
    public function __construct($title, $uri, $metadata) {
        $this->title = $title;
        $this->uri = $uri;
        $this->metadata = $metadata;
    }
    
    public function getTitle() {
        return $this->title;
    }
    
    public function getUri(): string {
        return $this->uri;
    }
    
    public function getMetaData(): string {
        return $this->metadata;
    }
    
    public function isRadio() {
        return (strpos($this->uri, 'x-sonosapi-stream:') !== false
            || strpos($this->uri, 'x-sonosapi-radio:') !== false
            || strpos($this->uri, 'pndrradio:') !== false
            || strpos($this->uri, 'x-sonosapi-hls:') !== false
            || strpos($this->uri, 'x-sonosprog-http:') !== false
            || strpos($this->uri, 'x-rincon-mp3radio:') !== false);
    }
    
    public function isLineIn() {
        return (strpos($this->uri, 'x-rincon-stream:') !== false 
            || strpos($this->uri, 'x-sonos-htastream:') !== false);
    }
}
private function getFavorites() 
    {
        // Get favorites
        if ($this->setController())
        {
            $data = $this->controller->soap("ContentDirectory", "Browse", [
                "ObjectID"          =>  "FV:2",
                "BrowseFlag"        =>  "BrowseDirectChildren",
                "Filter"            =>  "*",
                "StartingIndex"     =>  0,
                "RequestedCount"    =>  100,
                "SortCriteria"      =>  "",
            ]);
            $parser = new XmlParser($data["Result"]);
            $favorites = [];
            foreach ($parser->getTags("item") as $item) {
                $id = $item->getAttribute("id");
                $title = $item->getTag("title")->nodeValue;
                $uri = $item->getTag("res")->nodeValue;
                $metadata = $item->getTag("resMD")->nodeValue;
                $fav = new SonosFavorite($title, $uri, $metadata);
                $favorites[] = $fav;
            }
            return $favorites;
        }
        return array();
    }

private function playFavorite($fav) 
    {
        if ($this->setController())
        {
            if ($fav->isRadio() || $fav->isLineIn()) {
                // Playing radio station favorite works!
                $stream = new Stream($fav->getUri());
                $this->controller->useStream($stream)->play();
            }
            else {
                $queue = $this->controller->getQueue();
                $queue->clear();
                $this->controller->soap("AVTransport", "AddURIToQueue", [
                    "InstanceID"                        =>  0,
                    "EnqueuedURI"                       =>  $fav->getUri(),
                    "EnqueuedURIMetaData"               =>  $fav->getMetaData(),
                    "DesiredFirstTrackNumberEnqueued"   =>  0,
                    "EnqueueAsNext"                     =>  0,
                ]);                
                $this->controller->useQueue();
                $this->controller->setShuffle(true); // Always play lists in Shuffle mode
                $this->controller->play();
            }
        }
    }

kvanisterdael avatar Mar 18 '19 07:03 kvanisterdael