Webhooks - option to not send jpeg image

I’ve tried using a webhook to call a webcore piston (samsung smartthings automation)

This works for any request which does not include the jpeg (media added, media play started) but due to suspected issues with webcore, the requests with jpegs fails. Could an option be added for each webhook to not send the jpeg?

The use of webhooks with webcore opens up many automation opportunities e.g setting lights to movie mode when a movie starts etc

For anyone interested, I’ve circumvented the issue with the following node.js code running on a local raspberry pi. It basically replaces the multipart message, removing the jpeg part that causes webcore to fail.
I’ve kept the same JSON format as plex uses, so any piston is compatible with both methods.
To use this, change the code to point address your webcore piston (currently the webhook target), and change the web hook to call this code. Once implemented, the media start & add events are correctly sent to webcore

var http = require('http');
var https = require('https');

http.createServer(function(req, res){
main(req,res);
}).listen(1111);

function main(req, res){
    let data = [];
    req.on('data', (chunk) => {
        data.push(chunk);
    });

    req.on('end', () => {
        data = Buffer.concat(data).toString();
        // at this point, `data` has the entire request body stored in it as a string
       console.log(' ');
       console.log(' ');
       console.log('Processing request');
       header = data.substr(26,43);
       header = "--------------------";
       data = data.substr(data.indexOf("name="));
       data = data.substring(50,data.indexOf(header));
       const data2 = '{"payload":' + data + '}';
       console.log(data2);
       const options = {
           hostname: 'graph-eu01-euwest1.api.smartthings.com',
           path: '/api/token/****/smartapps/installations/****/execute/:****:',
           method: 'GET',
           headers: {
               'Content-Type': 'application/json',
               'Content-Length': data2.length
               }
           }
        //make request
        const req2 = https.request(options, res2 => {
            console.log(`statusCode: ${res2.statusCode}`)

        res2.on('data', d => {
            process.stdout.write(d)
            })
      })

       req2.on('error', error => {
           console.error(error)
       })

       req2.write(data2)
       req2.end()
    });
    res.end();
}

Thank you Paul for creating this script!!
If I can get this working to on my Pi, having just the play variable working within Webcore will make movie time operate so much better. :slight_smile:

Is this correct URL to point Plex to Node server…http://pi-ip-address:1111?

Thanks again

Hi,

Yes thats the correct address for the webhook.

I’ve found a further problem that webcore can not handle some non standard char actors, so I’ve updated the script to remove these. There’s also commented out code to remove some JSON items you may not be interested in, however they do not cause any problems. (I tried these when I thought there may be an issue with the length of the message)

The script works fine for all operations, including play. When you put in the details of your piston in the path variable, ensure you format as the redacted example (start with /api and include everything upto & including the final :

var http = require(‘http’);
var https = require(‘https’);

http.createServer(function(req, res){
main(req,res);
}).listen(1111);

function main(req, res){
let data = ;
req.on(‘data’, (chunk) => {
data.push(chunk);
});

req.on('end', () => {
    data = Buffer.concat(data).toString();
    // at this point, `data` has the entire request body stored in it as a string
   console.log(' ');
   console.log(' ');
   console.log('Processing request');
   header = data.substr(26,43);
   header = "--------------------";
   data = data.substr(data.indexOf("name="));
   data = data.substring(50,data.indexOf(header));
   var data2 = '{"payload":' + data + '}';
   console.log(data2);
   var jsondata2 = JSON.parse(data2);
   // remove unwanted JSON items

// delete jsondata2.payload.Metadata[‘Role’];
// delete jsondata2.payload.Metadata[‘Similar’];
// delete jsondata2.payload.Metadata[‘Location’];
// delete jsondata2.payload.Metadata[‘summary’];
data2 = JSON.stringify(jsondata2);
data2 = data2.replace(/[^\x20-\x7E]/g, ‘’); // Remove non printable chars
console.log(‘tidied data’);
console.log(data2);
const options = {
hostname: ‘graph-eu01-euwest1.api.smartthings.com’,
path: ‘/api/token/**********:’,
method: ‘GET’,
headers: {
‘Content-Type’: ‘application/json’,
‘Content-Length’: data2.length
}
}
//make request
const req2 = https.request(options, res2 => {
console.log(statusCode: ${res2.statusCode})

    res2.on('data', d => {
        process.stdout.write(d)
        })
  })

   req2.on('error', error => {
       console.error(error)
   })

   req2.write(data2)
   req2.end()
});
res.end();

}

Hiya,

Brilliant, Thanks for your help…
Lets hope Plex will allow us to implement changes to webhooks in the future. My Pi is being shared with my son, so lets hope it doesnt get boken. :grimacing:

It might be worth getting a separate Pi zero & hiding it away somewhere!

I hope Plex do further develop the Web hooks. It’s worth looking at the JSON data printed by my script, there appears to be more details than documented. There’s a summary of the show or film, I’m looking to get this read out when you start watching. The “similar” data is interesting too, as this seems to be taken from an external source rather than the related shows you see on the plex interface, where the related shows are ones in your library.

Hi, great idea on buying a Pi Zero, dirt cheap.
Ive only got the one Pi bought recently to experiment with and to teach my boy basic coding, especially now I have time being locked down in the UK…now I have the bug and taking over the Pi.

Interesting…do you mean ‘read out’ via a media player? :slight_smile:

Are you running a single piston to execute commands or executing multiple pistons to get a desired action?

Would you mind sharing examples of what you have created within Webcore to get Plex automations? I would be very grateful.

Hi,

I’ve only written the piston to receive the data so far (below) but its easy to add your own actions. I would try to write everything in one piston, but if you needed more, guess you could add a second webhook calling another copy of the node.js code running on a different port (e.g 1112) calling a second piston.
If you import this piston, set the path parameter in the node.js to point to it, click test and trace in webcore, you will see the values updating as you carry out actions on Plex and the web hook is called.

I intend to read the details of the summary field when a media.play event is sent. I’ll send it either to the sonos or an echo device using echo speaks (info on wecore forums if you need to use these)

I’m using the lockdown to learn node.js, its not the easiest, but has some good scope for home automation and linking webcore to external web services.

Thank you Paul!

Ive got a working single Piston triggering lighting scenes, plays nice when a pre roll video is added (or 2), (executed with event:: media.scrobble - condition:: clip or movie). The pause/resume work really well with hardly any lag.

Really enjoying the setting this up and the results are very rewarding.
I have Sonos system and a working Echo speaks setup, saying something like “Enjoy the playing movie, and dont forget the popcorn!” would be fun.

Ive got the node server added to Pi, just need to setup the script to enable proxy server. Node.js is something I would love to learn, small steps I suppose.
Shame Kids are keeping me busy at the moment :frowning:

Take care.

Hi

Im getting error “TypeError: Assinment to constant variable” in terminal form node.js on these lines when playing media.

data2 = JSON.stringify(jsondata2);
data2 = data2.replace(/[^\x20-\x7E]/g, ‘’); // Remove non printable chars

Any ideas?

The first script kind of worked but failed on pauses and stopping with either “status code 500 or status code 429”. I guess this due to the amount of data sent to Webcore.

Thank you

Hi,

Are you using the full code from the second version or did you add the new lines to the original? I think the error is due to data2 being declared as a const rather than a var. The first script did this, but the second was amended as the data was being updated by the lines you mention.

The problem I found with the first script was an issue where webcore cant handle extended asci codes, I was getting error 500. I initially suspected the length of the data but that turned out to not be the case. (I left the commented out delete commands just in case it later became a problem) The data2.replace(… removed any extended ascii codes. If you look at the media the first version fails with, you’ll probably find one or more of the extended codes, they;re often chars with a circumflex etc

Sorry my bad, you are right made a error ‘const not a var’

Working ok now.

Seeing occasionlly, “error”:true,“type”:“RateLimit”,“message”:“Please try again later”} on pauses/stops though.

No problem, I hit the same error when I changed the code!

Not sure about the other errors, it sounds like it could be webcore is too busy. Does it error on the same media every time or is it just occasional? Maybe if you’re testing and sending too many requests close together, it may cause a problem?

It is intermittant, probably where im constantly testing.
Seems where there is a mass amount of data for Processing request > tidied data feed back.

Looks good now! :+1:

Working nicely…How do you get node.js script to run at startup? add to rc.local?

Thanks

Hi,

I’ve not looked at how to auto run at startup yet on the PI, guess it could be rc.local. I have a few home automation scripts running on it and like to see the terminal windows as a status display while I’m performing extended testing on them.

There does seem to be a lot of data in the webhook requests, I think some of these seem additional to what Plex usually shows e.g the similar shows/films - I have thoughts of building a recommendation system using the data to suggest new shows & films to watch.

If there are any issues with the amount of data, the commented out lines can be included/amended to remove anything you dont need in webcore.

Good Morning,

I am using a program called ‘Forever’ to run script as a background service and keep alive, probably add this to rc.local folder with the path to Java script.

Like the idea of a recommendation action when starting/finishing media, good luck with that. I’d like to see your work.

I did play with the commented out lines to block/enable metadata, actually found script worked smoothly leaving lines blocked/uncommented strangely.

Thanks, I’ll have a look at forever, will also have to consider logfile tidying if its not running in terminal.

I don’t think webcore has any issues with the length of messages sent be plex. I designed the script to keep the same format as the plex webhook, so the same webcore piston can be used directly from the webhook or via my script. If webcore is changed to allow multuplart messages, or plex implement the enhancement request, the webhook can be changed to vall the piston directly with no changes.

I still need to investigate why there is the issue with extended ascii chars, It maybe a webcore issue, or maybe I need to specify the character set being used in the call I make to webcore.

Hi, me again!

Im still struggerling with media.play still :frowning: Very occassionally it works now for some reason. SmartThings have issue in the USA relating to delays, do not think its related, L0L.

With the chars, this line in the script, Ive always had a error (removing the quotes allowed script to work) Is it worth you posting whole script to copy again just to make sure ive copied accross any errors causing syntax problems?

my log::

/home/pi/Desktop/Node_scripts/webcorePlex2.js:33
data2 = data2.replace(/[^\x20-\x7E]/g, ‘’); // Remove non printable chars

SyntaxError: Invalid or unexpected token
at wrapSafe (internal/modules/cjs/loader.js:1039:16)
at Module._compile (internal/modules/cjs/loader.js:1087:27)
at Object.Module._extensions…js (internal/modules/cjs/loader.js:1143:10)
at Module.load (internal/modules/cjs/loader.js:972:32)
at Function.Module._load (internal/modules/cjs/loader.js:872:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47

Thanks

Hi,

Here’s the full script. There are a lot of problems pasting code around & character set conversions. From your post, the line causing issues is showing as a double quote. It should be two single quotes i.e a null string.

var http = require(‘http’);
var https = require(‘https’);

http.createServer(function(req, res){
main(req,res);
}).listen(1111);

function main(req, res){
let data = ;
req.on(‘data’, (chunk) => {
data.push(chunk);
});

req.on('end', () => {
    data = Buffer.concat(data).toString();
    // at this point, `data` has the entire request body stored in it as a string
   console.log(' ');
   console.log(' ');
   console.log('Processing request');
   header = data.substr(26,43);
   header = "--------------------";
   data = data.substr(data.indexOf("name="));
   data = data.substring(50,data.indexOf(header));
   var data2 = '{"payload":' + data + '}';
   console.log(data2);
   var jsondata2 = JSON.parse(data2);
   // remove unwanted JSON items

// delete jsondata2.payload.Metadata[‘Role’];
// delete jsondata2.payload.Metadata[‘Similar’];
// delete jsondata2.payload.Metadata[‘Location’];
// delete jsondata2.payload.Metadata[‘summary’];
data2 = JSON.stringify(jsondata2);
data2 = data2.replace(/[^\x20-\x7E]/g, ‘’); // Remove non printable chars
console.log(‘tidied data’);
console.log(data2);
const options = {
hostname: ‘graph-eu01-euwest1.api.smartthings.com’,
path: ‘/api/token/**********:’,
method: ‘GET’,
headers: {
‘Content-Type’: ‘application/json’,
‘Content-Length’: data2.length
}
}
//make request
const req2 = https.request(options, res2 => {
console.log(statusCode: ${res2.statusCode})

    res2.on('data', d => {
        process.stdout.write(d)
        })
  })

   req2.on('error', error => {
       console.error(error)
   })

   req2.write(data2)
   req2.end()
});
res.end();

}

I’ve had a few issues with Plex not always sending the media.play command, not sure why, but wonder if its if you start playback soon after another command has been sent.

I’ve spent the day trying to work out how to send the extended ascii chars rather than truncating them, but am not there yet!