Help needed with a Pandora Plugin

Wow, nice job! I’ll download the code and take a look today or tomorrow to see if I have any insight. Maybe you can ping Marco somehow and have him look at updating the state and why that line is crashing.

Maybe related, maybe not: I was writing a completely different type of plugin for Phish.in, but I had a really hard time getting MPD to play nice with playback commands and changes with “consume” or “volatile” modes. I’m not sure if the implementation of these modes is incomplete, if it is designed to only work with “webradio,” or if I was just doing it wrong. Instead, for playback controls and updating the state, I used the example in the YouTube plugin. That basically means taking full control of MPD and adding listeners to get state info directly from MPD when MPD changes tracks, etc, instead of setting the consume update service to MPD and letting the MPD plugin listeners do the job. But that’s a big hammer for this, especially if you can get consume mode to work.

Hey truckershitch – this is super rad!

AND getting the state info to display is a really easy fix! You’ve set the plugin to consume mode with MPD as the consume service on line 332:

self.commandRouter.stateMachine.setConsumeUpdateService('mpd');

What this does is tells Volumio to ingore any push state info from your plugin and listen to MPD instead. Since the mp3s that Pandora sends have no metadata, MPD pushes url garbage on state updates. All you need to do is delete that line and uncomment the code in your pushSongState method and the UI should update the state correctly!

I got this working by deleting line 332 and lines 622-632, then uncommenting lines 634-682.

I’d also change line 661 to something that describes that this queue item is a Pandora station. As is, it can update the queue item in the UI Queue tab to only display the track name and artist instead of the Pandora station name (if you add another queue item while it is playing this will happen). This makes it look like this is a single track in the queue instead of a Pandora station. You could change it to something like:

queueItem.name = 'Pandora Station: '+queueItem.name;

And this will display something like “Pandora Station: Steely Dan and DMX mix” with the currently playing track below.

I think you know this, but seek and the playback controls don’t currently work (next would be really nice to have because… Pandora). But this is sooooo close to ready for release! I’m excited to add this (now if we can figure out a way to add UI elements to get ban track and like buttons).

Yeah, I woke up early this morning and figured out about disabling the consume mode before I saw your post. You had mentioned something about it earlier and that fixed it. :slight_smile: I’m psyched that the metadata/artwork is showing! I was getting pretty mad about it but I knew one of us would figure it out. And it turned out that we both did! Heheheh…

I’ve been working on the Playback controls. Pause works as long as you don’t leave it too long. I left it for about an hour, and when I came back, the song played for about 30 seconds and then stopped. Playing the station again worked, so the Pandora login seemed to be intact, but perhaps the web token expired? Further investigation is required. Maybe this can be renewed or pinged somehow periodically…

Next goes to the next station, if there are multiple stations in the Playback Queue. This is not what I want. Pause and resume call the code from my plugin, but next isn’t working. I may It seems like clicking the button uses the MPD behavior. Perhaps this can be changed. Below is a log from the console:

info: CoreCommandRouter::volumioNext info: CoreStateMachine::next info: CoreStateMachine::stop info: CoreStateMachine::setConsumeUpdateService undefined UNSET VOLATILE info: CoreStateMachine::play index undefined info: CoreStateMachine::setConsumeUpdateService undefined info: CorePlayQueue::getTrack 1 info: CoreCommandRouter::volumioNext info: CoreStateMachine::next info: CoreStateMachine::stop info: CoreStateMachine::setConsumeUpdateService undefined UNSET VOLATILE info: CoreStateMachine::play index undefined info: CoreStateMachine::setConsumeUpdateService undefined info: CorePlayQueue::getTrack 1
Reading your posts gives me the idea that this is going to be the next hurdle. You seem to have a better handle on things than I do. Any advice you have for me will be gladly taken.

Marco, if you’re reading this: Many thanks for your code! I borrowed heavily from it. I feel like I understand most of what I used (I’m still a little confused about the .bind call in playNextTrack). Without your work and the work of the other developers, I would have had a much harder time doing this. I’m definitely a novice and having better example code helped tremendously.

I’m not sure about the queueItem.name change. It takes away the title of the song. But, as you say, it changes the information for the Queue item and does not show the Pandora station name. What about a combo of the station name and the title? I’m going with that for the time being. That’s something that can be easily tweaked.

I pushed my current changes and I’ll keep at the playback controls.

Hi lostmyshape! Thanks so much for taking an interest. I’m glad you’re on the team.

Disabling the Pandora plugin and then trying to delete an item from the Queue gives:

info: CoreCommandRouter::volumioRemoveQueueItem info: CoreStateMachine::removeQueueItem info: CoreStateMachine::stop info: CoreStateMachine::setConsumeUpdateService undefined UNSET VOLATILE info: CoreStateMachine::stPlaybackTimer info: CoreStateMachine::updateTrackBlock info: CorePlayQueue::getTrackBlock info: CoreStateMachine::pushState info: CoreStateMachine::getState info: CorePlayQueue::getTrack 0 info: CoreCommandRouter::volumioPushState info: CoreCommandRouter::executeOnPlugin: volumiodiscovery , saveDeviceInfo info: interfaceApi::pushState info: CoreStateMachine::serviceStop info: CorePlayQueue::getTrack 0 info: CoreCommandRouter::serviceStop error: WARNING: No stop method for service pandora |||||||||||||||||||||||| WARNING: FATAL ERROR ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TypeError: Cannot read property 'then' of undefined at CoreStateMachine.removeQueueItem (/volumio/app/statemachine.js:1400:4) at CoreCommandRouter.volumioRemoveQueueItem (/volumio/app/index.js:130:27) at Socket.<anonymous> (/volumio/app/plugins/user_interface/websocket/index.js:146:43) at emitTwo (events.js:126:13) at Socket.emit (events.js:214:7) at /volumio/node_modules/socket.io/lib/socket.js:503:12 at _combinedTickCallback (internal/process/next_tick.js:131:7) at process._tickCallback (internal/process/next_tick.js:180:9) ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| Waiting for the debugger to disconnect...
Should those items be removed when the plugin ends? I saw a method to clear the queue…

I do feel it’s pretty close to release. If anyone has any issues, do not hesitate to list them here and I’ll do my best to fix them. I don’t know what to do about the Next button. lostmyshape, do you have an idea? From reading your posts on your own plugin, it looks like that might be tricky.

The funny thing is that I don’t even listen to Pandora often. I just thought it might be a good thing to do for this project and I’d learn a little bit about Node JS. I try to make clean code but sometimes I break out the duct tape and the sledgehammer. :laughing: I’m going to see if I can refactor the code as I go to make things look more by the book, or as close to it as I can.

I think things are pretty stable though. I let the music play for two hours (watched some television in the other room).

Anyway, I think this version is much better than the Pianobar version. Pianode was set up with events and they were tricky for me to coordinate. Everything was coming out in stdout and there was a lot of grepping. It works, but having to incorporate a binary, a different one for each platform, would be a hassle. This node.js API is so much cleaner, and there is a serious ton of information that could be used. The objects that are retrieved are voluminous. It has the potential to make a powerfully functional Pandora client.

I fixed the problem with deleting items from the Queue. It was another issue with pushing the state. I think my solution is slightly overdone but I’ll look at that in the next few days.

Hi lostmyshape!

I can get the Next button to work if I set the Volatile mode. It would require updating the state every second (I think), but I had to do that with the other version of this plugin. Since Marco used the nanotimer library and it worked so well for me as well (again, I shamelessly used his code there), I could easily set up a timer to update the state as there is adequate sample code given on their website to do a very similar thing (countdown timer with setInterval-like behavior).

I’m trying to think if there are any downsides to doing this but I can’t think of any offhand. It would take care of the progress meter clicking problem (right now it resets to zero seconds on a click – that might be fixed by updating the seek time on the state every second). It would enable the Previous button as well but I’d probably leave that disabled as the mpd queue is being cleared as it goes (mpd is in consume mode). Also, I don’t know if a previous track could be played – it might expire after playing.

Anyway, to switch to Volatile mode would be a day or two’s coding and it might be worth it to be able to skip tracks, because… as you said, Pandora. :stuck_out_tongue:

I got Volatile mode working. I made an interval timer with Nanotimer similar to the one Marco made for his song timer. It just updates the state every second. There may be a way to update this less frequently. It seems that Volatile mode has to be continually set or Volumio goes back to non-Volatile mode. It may be happening when an mpd command is sent. I tried wrapping the sendMpdCommand function with a setVolatile function I wrote, but I didn’t get that working quite right, so at the moment, I set Volatile mode every second just before updating the state. This is working so far. I’ll see if I can turn down the frequency of updates as I keep working on it.

Next now works, so Pandora tracks can be skipped. This is probably the best benefit to this method. Also, the song title can be something like, “Comfortably Numb”, while the Queue name (title?) field can be “Pink Floyd Radio”. That’s a small benefit but it works.

I fed the mp3 tags directly into mpd and that took care of the missing track information when Volumio was paused. I haven’t seen this done by anyone else. Maybe some other developer will find that method useful. Apparently that trick only works for streaming media, and the tags are impermanent. I had the title set to the song URL and everything else was blank, and adding the tags worked very well.

I’m thinking about putting in radio station thumbnail images for the Queue items. I’m also thinking that leaving a default Pandora icon image might be best. It could be a configuration switch I suppose. It’s pretty trivial to add it since an URL is provided in the extensive object returned for each Pandora station. Thoughts?

Anyway, I’m just playing a station here at the moment. It’s gone through about 6 or 7 songs. Every time the songArray drops to 2 songs or less (providing for a Next button press), the array gets replenished by 4 more songs. I think it’s pretty stable, but I’m going to let it run for a while and see what happens. I think this plugin is getting ready for the big time.

Okay, just for whoever is listening: the pianode version is on its own “pianode” branch now, and I merged the “develop” branch to master.

I made a slight change to the mpd mp3 tagging to make things more bulletproof this morning. Next Track works, Previous Track is disabled, Pause works, the timers seem to work fairly well. I have tested on the Pi 2 and the Pi 1B (not the plus).

So far so good.

Hey truckershitch,

Tested the latest code in develop and everything works great! I think this is ready to go. Package and make a PR!

Only oddity, the album art is disappearing on pause. This isn’t really important enough to not to publish it, but it’s strange. Maybe you could also add toast messages for seek & previous – “not available in Pandora,” or something like that. That’s all cosmetic, though.

Hey, thanks for writing this. Gonna use it this weekend!

Noah

Hey lostmyshape! Thanks for trying it out.

I was trying to do the counter in a “smarter” way and I broke the plugin. I think I’m going to leave it alone for now. I have another working solution but I think it will add overhead and complication to a simple counter. Does everything have to be complicated to work better? Maybe the simple, “global” variable is best? This is one structure I could change it to:

function SimpleCounter() {
    var i = 0;
    return {
        count: function () { return i++; },
        reset: function () { i = 0; }
    };
}
var self.c = SimpleCounter();
self.c.count();
self.c.count();
self.c.reset(); // new song
self.c.count(); // etc.

It still would be a global counter but would be “safer”. I also toyed with putting the counter in the interval timer (logical place), but I’m unsure on passing the counter value to the pushSongState function. The counter would (could) be called with:

var stateTimer = new StateCounter(pushSongState, [songArray[0]], duration);

In the timer the argument would have to be appended with the counter variable maintained in the timer instance. That is, pushState would then have two arguments, the song argument and the counter argument.

I like thinking about good solutions but maybe it’s just an academic point? I wasn’t a developer by trade; I converted databases (which was never pretty). I would never waste time with this stuff – my applications only supported me and most of them could not be reused again. But trying to do things the right way is never a bad thing.

What seems to be happening is that the control goes to MPD when the player is paused. Before I was force-feeding tags to MPD for album, title and artist, there was only the URL of the song that was playing. No other track information was shown.

Looking at the Volumio code, I see this line and this line but I’m not sure if they apply.

There doesn’t seem to be a tag for the album artwork listed on the mpd website so I can’t force-feed that information like I did for the other data.

To my eyes, it looks like the artwork is not being read from the state. But that would not explain why the album, title, and artist are not read from the state, either (and why I have to force-feed their tags with an mpd command). I took a look at getAlbumArt() but I’m not sure that applies here.

I tried doing the QueueItem hack that Marco used in his plugin but that isn’t working, either. I’ll keep trying things. I have some other stuff going on this weekend but I’ll take another look after that.

I fixed the album artwork not displaying during pause by pushing the state twice after pausing. I’m not really sure why that fixed it, but it seems to be fixed.

I fiddled with the song position counter again. It’s still “global” but it’s a “safer” counter now, done with a closure. It’s definitely overkill but I learned something.

So my master branch has the most current version. I’m not sure why I didn’t catch the error in master the other day. I have been doing “volumio plugin refresh” after making changes. I won’t trust that method any more although I’m not sure why. “volumio plugin install” takes about the same amount of time. Live and learn. I may have missed a step.

Great work, truckershitch!
Is there any possibility to enter a proxy address to use the plugin from outside the USA?

If you can give me an idea of how to implement that, I’d be happy to add that to the plugin. I have never tried to access Pandora outside of the USA so I’m not sure what is involved.

That might not be very hard to do. I haven’t done much with proxies but I’m willing to learn.

Would you need a working static proxy address to do this, or would you just need a form entry like “Proxy Server: xxx.yyy.zzz”? What I mean to say is, do you have one in mind to use already?

Sorry for the late reply, I am not getting message notifications for this forum.

Hi, no problem at all, thanks for the answer!
I didn’t install your plugin so I don’t know if this is already implemented. When I use Pandora via pianobar, I enter the address for the control proxy (tor in my case) in the pianobar config file. For example: control_proxy = 127.0.0.1:8123/
If this is not already implemented in your plugin, this would be a great addition :slight_smile: