Extract & reuse multiple arrays from JSON output

Hey everyone,



tl;dr
Any ideas, how to archieve a dynamic approach to manipulate a local variable based on an unknown amount of arrays in a second JSON file?



What I would like to do?
I use the Twitch API (a tech/gaming live streaming service) in my setup to extract informations about channels and their current streaming status. I reuse these informations to start kodi-plugins etc.
Everything works fine in a more or less rigid setup.

I´d like to extend this with a more flexible approach, by checking my twitch-follows (also possible via one of their API endpoints) from time to time - without calling the API too often. Currently I´m following two channels (as you see in the output of the JSON examples below), but it can be 5, 10 or up to 200.

In their newest API revision (v5) you need to send a get request to multiple endpoints to get all the informations you need.


and what the heck is your problem?
I would like to avoid calling the “channel” API-endpoint for each data-array in the “follows” output, but I can´t get it managed to add and convert the right amount or arrays from the first API request:

  1. ../users/follows?from_id=123456 - Requesting all followers for id 123456
  2. ../users?id=123456&id=78901234&id=56789012... - Requesting detailed informations about all followed channels

I´m pretty sure that this is possible with some kind of loop or REGEX transformation, but after a long night out yesterday my search skills seems drained and I´m kinda stuck.

Someone willed to kick my butt and point me in the right direction?


follows JSON output

{
"total": 2,
"data": [
  {
"from_id": "123456789",
"to_id": "35987962",
"followed_at": "2018-05-16T18:54:35Z"
},
  {
"from_id": "123456789",
"to_id": "12875057",
"followed_at": "2018-04-30T23:04:55Z"
}
],
"pagination": {
"cursor": "eyJiIjpudWxsLCJhIjoiMTUyNTEyOTQ5NTc0MTAxNDc2OSJ9"
}
}

channel JSON output (Multiple values in request allowed)

{"data": [
  {
"id": "35987962",
"login": "linustech",
"display_name": "LinusTech",
"type": "",
"broadcaster_type": "partner",
"description": "We broadcast WAN Show, gaming hardware builds and Q&A's, and more through this channel. Check our the rest of what we do at http://www.youtube.com/LinusTechTips",
"profile_image_url": "https://static-cdn.jtvnw.net/jtv_user_pictures/linustech-profile_image-38d527cc424347f5-300x300.jpeg",
"offline_image_url": "https://static-cdn.jtvnw.net/jtv_user_pictures/97e024d6311cca7d-channel_offline_image-1920x1080.jpeg",
"view_count": 7070482
},
  {
"id": "12875057",
"login": "gronkh",
"display_name": "GRONKH",
"type": "",
"broadcaster_type": "partner",
"description": "Zart im Schmelz und süffig im Abgang. Ungebremster Spieltrieb seit 1896.",
"profile_image_url": "https://static-cdn.jtvnw.net/jtv_user_pictures/gronkh-profile_image-76b34139eaa46bb5-300x300.png",
"offline_image_url": "https://static-cdn.jtvnw.net/jtv_user_pictures/gronkh-channel_offline_image-eb70f551d9327737-1920x1080.jpeg",
"view_count": 50098542
}
],
}

twitch.rules

rule "Getting twitch data periodically"
when
    Item Twitch_StreamerRefresh received command //Testing switch
then
    if (clientId!==true || twitchUserId!==true) {
        //Twitch Helix API #1 - grabbing follows of user
        var rawMessageFollows = executeCommandLine('curl -X GET --silent --header “accept:application/json” --header "client-id:' + clientId + '" "https://api.twitch.tv/helix/users/follows?from_id=' + twitchUserId + '"', 5000)
        Twitch_FollowsAPI.postUpdate(rawMessageFollows) //Store API response
        
        // Twitch Helix API #2 - grabbing user info
        Thread::sleep(500) //Wait for the script to catch up
        var rawMessageUsers = executeCommandLine('curl -X GET --silent --header “accept:application/json” --header "client-id:' + clientId + '" "https://api.twitch.tv/helix/users?id=' + twitchUserId + '"', 5000)
        Twitch_UsersAPI.postUpdate(rawMessageUsers) //Store API response
        logInfo("Twitch.TV", "Helix API (users): "+rawMessageUsers) //Send stuff to log
    }
    else {
        logInfo("Twitch.TV", "ERROR: No client-/user-ID found in *.rules. Please provide valid ID(s)!")
    }
end

Thank you!

If you apply the JSONPATH "$..to_id" it will return an array of the two (or more) to_id
You can then iterate through the array to build your http request string

1 Like

Ty for the hint with the "$..to_id"- I´ll try to find out how to loop through the array and building the request string now :slight_smile:


@vzorglub I tried you approach and get this in log:

JsonPath expressions with more than one result are not allowed, please adapt your selector. Result: ["217003761","37402112"]

I called it outside of any loop for testing - but that makes no difference, right?

var test = transform("JSONPATH", "$..to_id", Twitch_FollowsAPI.state.toString)

I guess that the JSONPATH implemented for OH doesn’t accept this expression
You will have to do this with a javascript transform

For everyone who´s interested in the javascript transform soloution for my problem:

(function(json) {
    var clean = JSON.parse(json);
    var link="";
    for (var i=0; i < clean.data.length; i++) {
        link += "&id=" + clean.data[i].to_id;
    }
    return link;
})(input)

That’s probably not the best solution, but I´m kinda happy, that I got it working without any JS knowledge. :slight_smile:

Thx again to @vzorglub for the kick!

1 Like

That’s the best solution.
Your could do

for (var i = 0, i < clean.data.length; i++) {

and get rid of the line var i;

Well done

1 Like

Can you explain how you do it:
the script you store it in the transform section?
how do you name it?
how do you use the values in the tables?
and the exact syntax used in JSONPATH?

exemple for “switches” array in my JSON:

{
“status”: “ok”,
“version”: “3.403”,
“request”: {
“route”: “/get-status”
},
“response”: {

    "switches": [
        {
            "id": 0,
            "status": "off"
        },
        {
            "id": 1,
            "status": "off"
        }
     ]
 }

}

thank you in advance