Home AMX User Forum AMX General Discussion

JSON parsing

Similar to other people, I'm increasingly working with JSON based API's for various devices and services these days and looking for neater ways to parse this. Currently I'm using a pretty rudimentary parser I rolled that enables me to pull out specific items based on a key. It works, but it gets clunky when you're working with larger objects more complex structures.

One option I'm thinking of is a parser that will ingest a JSON string and spit out a string encoded in the NetLinx Binary Marshalling Protocol. This will then allow you to take advantage of the in internal string_to_variable(..) method to load this directly into a variable (including structures) of arbitrary type. From what I can see, the only limitation is that the members of any structure you are decoding into will need to be ordered identically to members of the original JSON. An alternative is to parse into the XML format ingested by xml_to_variable(..). Again, this will enable you to decode into arbitrary types. In exchange for the slightly increased overhead of building that out to XML, the ordering caveat will be removed as the XML marshalling protocol contains reference to members by name.

Has anyone else tried this approach yet, or have another approach that works well for them?

Comments

  • DFrobergDFroberg Posts: 7
    I started off with a parser I swiped from the forums here (search json), it's in a module, and works well for occasional usages. It uses a shared array to get the Json string to the module and send strings to get the individual objects/keys to main program. BUT it seems when I start using it for quick, short messages ( 200 char?), the events can't process the individual objects faster than the incoming strings. I don't know if this is a function of the new processors or my crappy code. The cpu usage sits at 25% but the interpreter buffer can hit the max(4000) and usually sits around 2K. I never saw the buffers get that high on the older units.
    I've never used the string to variable or the XML, but I bet Json implementations are going to vary widely, more flexibility would be better, and I'm assuming you could drop the fields you are not interested in in the xml and just get what you want.

    on a related note, do you see the JSON ID field being used as a sequential identifier, or unique to a particular type of command?
  • JasonSJasonS Posts: 229
    I recently had problems with Variable_to_XML on nested structures, I had to use Variable_To_String instead. The Variable_To_XML function generates invalid XML when converting Structures that contain Structure members.
  • PhreaKPhreaK Posts: 966
    [USER="2751"]JasonS[/USER] cheers for the heads up - this would be going the other way though (xml_to_variable), had any issues there?

    [USER="3082"]DFroberg[/USER] JSONID field? I'm assuming you're talking about something protocol specific.
  • JasonSJasonS Posts: 229
    PhreaK wrote: »
    [USER="2751"]JasonS[/USER] cheers for the heads up - this would be going the other way though (xml_to_variable), had any issues there?

    Not sure, I had a fairly complex committee room customization file I was trying to store. The customer was hoping for a standard file type that would be easy to modify, because the committee members change on a regular basis, and there are multiple committees per room. All the initial data was generated from the touch panel, I moved to Variable_To_String as soon as I figured out what the problem was. It was easy to tell by looking at the raw XML that it was corrupt, but strangely the Master was able to extract more data than I would have thought possible from the corrupt XML. I never tried generating a correct XML file to see if the Master could read it, so I don't know if it works properly in that direction.
  • DFrobergDFroberg Posts: 7
    Oops that's right Json rpc has the id requirement
  • viningvining Posts: 4,368
    IMHO JSON is a real PITA. In my experience you need to wait until the entire message is received before parsing, well I actually parse the header and then use the content length to determine when I've received the complete body. I then find my object opening brace and it's matching closing brace or array to get a complete object, which is why you need a complete message. I then parse the objects for nested objects or arrays. I wrestled with various options to store values and nothing seemed to make sense. I can't even find a good way to explain what I ended up doing. Beside using JSON for this device I also first open a COMETD stream so I can receive unsolicited feedback, basically the server port then maintains the connection, it sends me unsolicited feedback and then when I want to send a JSON string for control I don't have to open the socket, I just send the string. Another problem with JSON is PERL randomization which really only started being randomized recently so you have to parse in a method that doesn't rely on a fixed order of tags.

    I've only tried this on one device but I think the parsing routine would be fairly portable but my function here would have to change to process the specific tags:
    [code]
    DEFINE_FUNCTION fnJSON_Process_FB(_FB iFB)

    {
    STACK_VAR _FB sMyFB;
    STACK_VAR INTEGER i;
    STACK_VAR INTEGER nLVL;
    STACK_VAR INTEGER nFBS;
    STACK_VAR INTEGER nIndx;
    STACK_VAR INTEGER nFBIndx;
    //STACK_VAR INTEGER nLoopRunIndx;
    STACK_VAR INTEGER nPlugin;
    STACK_VAR INTEGER nRecognized;
    STACK_VAR INTEGER nSearchPerformed;

    sMyFB = iFB;

    nLVL = sSBS.sBrowseState.nLevel;
    fnJSON_Debug("'Process_FB, **, START-->'",1);
    fnJSON_Debug("'Process_FB, **, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], TAGCNT-, ORIGINDX-, LVL- :DEBUG<',ITOA(__LINE__),'>'",1);

    sLevel[nLVL].cTypeRet = sMyFB.cTag;

    nPlugin = fnCheck_if_Plugin(sMyFB.cTag);//see if app or radio
    {
    if(nPlugin == 1)
    {
    sMyFB.cTopTag = 'apps';
    sLevel[sSBS.sBrowseState.nLevel].nType = SBS_infoApps;
    }
    else if(nPlugin == 2)//radio
    {
    sMyFB.cTopTag = 'radios';
    sLevel[sSBS.sBrowseState.nLevel].nType = SBS_infoRadios;
    }
    }
    for(i=1;i<=sMyFB.nTagCnt;i++)
    {
    //fnJSON_Debug("'Process_FB, **TOP**, CNT-, FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_VAL[i],' ], FB_INDX-),'] :DEBUG<',ITOA(__LINE__),'>'",1);
    nRecognized = 1;

    if(sMyFB.nFB_Indx)
    {
    nFBIndx = sMyFB.nFB_Indx;
    }
    else if(!nFBIndx)
    {
    nFBIndx = 1;
    }
    SWITCH(sMyFB.cTopTag)
    {
    CASE 'apps':
    CASE 'artists':
    CASE 'genres':
    CASE 'albums':
    CASE 'radios':
    CASE 'playlists':
    //CASE 'loop':
    CASE 'favorites':
    CASE 'titles':
    CASE 'playlisttracks':
    {
    if(nFBIndx && find_string(sMyFB.cObjTag,'_loop',1))
    {
    STACK_VAR CHAR cCopyVal[4096];

    if(i==1 && nFBIndx==1)
    {
    STACK_VAR _sLevelList sZeroLevellist;

    sLevelList[nLVL] = sZeroLevellist;
    }
    SWITCH(sMyFB.cTag)
    {
    CASE 'artists':
    CASE 'albums':
    CASE 'genres':
    CASE 'titles':
    {
    if("sMyFB.cFB_Tag,'s'" == sMyFB.cTag)//sLevel[nLVL].cTypeRet)
    {
    sLevelList[nLVL].cItem[nFBIndx] = sMyFB.cFB_VAL;
    }
    if(sMyFB.cTag == 'titles')
    {
    sLevelList[nLVL].nHasItems[nFBIndx] = 0;
    sLevelList[nLVL].nIsAudio[nFBIndx] = 1;
    }
    else
    {
    sLevelList[nLVL].nHasItems[nFBIndx] = 1;
    sLevelList[nLVL].nIsAudio[nFBIndx] = 1;
    }
    }
    CASE 'playlists':
    {
    if("sMyFB.cFB_Tag,'s'" == sMyFB.cTag)//sLevel[nLVL].cTypeRet)
    {
    sLevelList[nLVL].cItem[nFBIndx] = sMyFB.cFB_VAL;
    }
    else if(sMyFB.cFB_Tag == 'title')
    {
    sLevelList[nLVL].cItem[nFBIndx] = sMyFB.cFB_VAL;
    sLevelList[nLVL].nHasItems[nFBIndx] = 0;
    sLevelList[nLVL].nIsAudio[nFBIndx] = 1;
    }
    }
    //CASE 'pandora':
    // CASE 'apps':
    // CASE 'favorites':
    // CASE 'radios':
    DEFAULT:
    {
    if(sMyFB.cFB_Tag == 'name')
    {
    sLevelList[nLVL].cItem[nFBIndx] = sMyFB.cFB_VAL;
    if(nFBIndx == 1)//copy in case needed later
    {
    cSBS_TxtBox = sMyFB.cFB_VAL;
    }
    }
    }
    //DEFAULT:
    // {
    // nRecognized = 0;
    // fnJSON_Debug("'Process_FB, !!, TAG-[ ',sMyFB.cTag,' ], no value assigned sLevelList.xXXXX, INDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    // }
    }

    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'album' :{sLevelList[nLVL].cAlbum[nFBIndx] = sMyFB.cFB_VAL;}
    CASE 'artist' :{sLevelList[nLVL].cArtist[nFBIndx] = sMyFB.cFB_VAL;}
    CASE 'cmd' :{sLevelList[nLVL].cListCmd[nFBIndx] = sMyFB.cFB_VAL;}
    CASE 'command' :{}//pandora button command arrays
    CASE 'genre' :{sLevelList[nLVL].cGenre[nFBIndx] = sMyFB.cFB_VAL;}
    CASE 'playlist' :{sLevelList[nLVL].cPlaylist[nFBIndx] = sMyFB.cFB_VAL;}
    CASE 'title' :{sLevelList[nLVL].cTitle[nFBIndx] = sMyFB.cFB_VAL;}
    CASE 'id' :
    {//spotify has spaces with %20 for some id's, these are needed in string sent back but the DecodeURL func removes them so we add an escape %--
    //and modified the DecodeURL func to recognize it
    sLevelList[nLVL].cItem_ID[nFBIndx] = fnStrReplace(sMyFB.cFB_VAL,'%20','%--%20');
    }//sLevelList[nLVL].nHasItems[nFBIndx] = 1;
    CASE 'icon' :{sLevelList[nLVL].cIconURL[nFBIndx] = sMyFB.cFB_VAL;}
    CASE 'name' :{sLevelList[nLVL].cName[nFBIndx] = sMyFB.cFB_VAL;}
    CASE 'type' :{sLevelList[nLVL].cType[nFBIndx] = sMyFB.cFB_VAL;}
    CASE 'weight' :{sLevelList[nLVL].cWeight[nFBIndx] = sMyFB.cFB_VAL;}
    CASE 'url' :{sLevelList[nLVL].cURL[nFBIndx] = sMyFB.cFB_VAL;}
    CASE 'isaudio' :{sLevelList[nLVL].nIsAudio[nFBIndx] = atoi(sMyFB.cFB_VAL);}
    CASE 'hasitems' :{sLevelList[nLVL].nHasItems[nFBIndx] = atoi(sMyFB.cFB_VAL);}
    CASE 'duration' :{sLevelList[nLVL].nDuration[nFBIndx] = atoi(sMyFB.cFB_VAL);}
    CASE 'tracknum' :{sLevelList[nLVL].nTrackNum[nFBIndx] = atoi(sMyFB.cFB_VAL);}
    CASE 'remote' :{sLevelList[nLVL].nRemote[nFBIndx] = atoi(sMyFB.cFB_VAL);}
    CASE 'image' :{sLevelList[nLVL].cImageURL[nFBIndx] = sMyFB.cFB_VAL;}//found in radios, pandora
    CASE 'playlist index' :{sLevelList[nLVL].nIndxNum[nFBIndx] = atoi(sMyFB.cFB_VAL);}//playlist tracks zap song
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    else
    {
    SWITCH(sMyFB.cObjTag)
    {
    CASE 'artists':
    CASE 'albums':
    CASE 'genres':
    CASE 'playlists':
    CASE 'titles':
    {
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'networkerror': {fnFB_SendVTMessage(UI_UPDATE_ACTIVE,"'Network Error!, ',sMyFB.cFB_Val",15);CANCEL_WAIT'SBS_PROGRESS_WAIT_DELAYOFF';fnSet_ProgressBar(FALSE);}
    CASE 'command': {}//pandora button command arrays
    CASE 'search': {nSearchPerformed = 1;}
    CASE 'rescan': {fnSBS_SetRescan(atoi(sMyFB.cFB_Val));}
    CASE 'count': {sLevel[nLVL].nMaxCountItem = atoi(sMyFB.cFB_VAL);}
    CASE 'context': {sSBS.sBrowseState.nContextSession = atoi(sMyFB.cFB_VAL);}
    CASE '__playlistTitle':
    CASE '_playlistTitle': {sLevel[nLVL].cTitle = sMyFB.cFB_Val;}
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'favorites':
    {
    LOCAL_VAR INTEGER nExists;
    LOCAL_VAR INTEGER nExists_Indx;

    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'networkerror': {fnFB_SendVTMessage(UI_UPDATE_ACTIVE,"'Network Error!, ',sMyFB.cFB_Val",15);CANCEL_WAIT'SBS_PROGRESS_WAIT_DELAYOFF';fnSet_ProgressBar(FALSE);}
    CASE 'title':{}
    CASE 'count':{sLevel[nLVL].nMaxCountItem = atoi(sMyFB.cFB_VAL);CANCEL_WAIT'SBS_PROGRESS_WAIT_DELAYOFF';fnSet_ProgressBar(FALSE);}
    CASE 'exists':
    {
    if(atoi(sMyFB.cFB_Val))
    {
    nExists = 1;
    if(nExists)
    {
    fnFB_SendVTMessage(UI_UPDATE_ACTIVE,'Item already in favorites',15);
    }
    }
    else
    {
    STACK_VAR CHAR cCopyURL[SBS_LEN_ITEM];

    nExists = 0;
    if(nSBS_Fav_Selected)
    {
    if(length_string(sSBS.sCurQList[nSBS_Fav_Selected].cURL) && length_string(sSBS.sCurQList[nSBS_Fav_Selected].cTitle))
    {
    cCopyURL = sSBS.sCurQList[nSBS_Fav_Selected].cURL;
    if(find_string(cCopyURL,'file://',1))
    {
    REMOVE_STRING(cCopyURL,'file://',1);
    }
    fnQueue_QCmd("'favorites add url:',fnEncodeURL(cCopyURL)(*fnEncodeURL()*),' title:',fnEncodeURL(sSBS.sCurQList[nSBS_Fav_Selected].cTitle)");
    nSBS_Fav_Selected = 0;
    }
    }
    else
    {

    if(length_string(sSBS.sNowPlaying.cURL) && length_string(sSBS.sNowPlaying.cTitle))
    {
    cCopyURL = sSBS.sCurQList[nSBS_Fav_Selected].cURL;
    if(find_string(cCopyURL,'file://',1))
    {
    REMOVE_STRING(cCopyURL,'file://',1);
    }
    fnQueue_QCmd("'favorites add url:',fnEncodeURL(cCopyURL)(*fnEncodeURL()*),' title:',fnEncodeURL(sSBS.sNowPlaying.cTitle)");
    }
    }
    }
    }
    CASE 'add':
    {

    }
    CASE 'index':
    {
    if(nExists)
    {
    nExists_Indx = atoi(sMyFB.cFB_Val);
    fnFB_SendVTMessage(UI_UPDATE_ACTIVE,"'Item already in favorites, index:',itoa(nExists_Indx +1)",15);
    }
    else
    {
    nExists_Indx = 0;
    }
    }
    CASE 'delete':
    {
    STACK_VAR _sLevelList sZeroList;

    sLevelList[nLVL] = sZeroList;
    nIndx = atoi(sMyFB.cFB_Val);
    fnFB_SendVTMessage(UI_UPDATE_ACTIVE,"'Favorite index:',itoa(nIndx+1),', deleted'",15);
    fnQueue_QCmd("'favorites items ',itoa(sLevel[nLVL].nStartItem),' ',itoa(sLevel[nLVL].nCountItem),' want_url:1'");
    }
    CASE 'changed':{}

    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'pandora':
    {
    if(sMyFB.cFB_Val == 'null'){fnFB_SendVTMessage(UI_UPDATE_ACTIVE,sMyFB.cFB_Tag,15);}
    else
    {
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'networkerror': {fnFB_SendVTMessage(UI_UPDATE_ACTIVE,"'Network Error!, ',sMyFB.cFB_Val",15);CANCEL_WAIT'SBS_PROGRESS_WAIT_DELAYOFF';fnSet_ProgressBar(FALSE);}
    CASE 'title': {}
    CASE 'count': {sLevel[nLVL].nMaxCountItem = atoi(sMyFB.cFB_VAL);fnSet_ProgressBar(FALSE);}//CANCEL_WAIT'SBS_PROGRESS_WAIT_DELAYOFF';
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    //CASE 'jazzfm':
    // {
    // SWITCH(sMyFB.cFB_Tag)
    // {
    // CASE 'networkerror': {fnFB_SendVTMessage(UI_UPDATE_ACTIVE,"'Network Error!, ',sMyFB.cFB_Val",15);CANCEL_WAIT'SBS_PROGRESS_WAIT_DELAYOFF';fnSet_ProgressBar(FALSE);}
    // CASE 'count': {sLevel[nLVL].nMaxCountItem = atoi(sMyFB.cFB_VAL);fnSet_ProgressBar(FALSE);}
    // DEFAULT:
    // {
    // nRecognized = 0;
    // fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    // }
    // }
    // }
    DEFAULT://catch all apps, radios, etc
    {
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'networkerror': {fnFB_SendVTMessage(UI_UPDATE_ACTIVE,"'Network Error!, ',sMyFB.cFB_Val",15);CANCEL_WAIT'SBS_PROGRESS_WAIT_DELAYOFF';fnSet_ProgressBar(FALSE);}
    CASE 'title':{}
    CASE 'count':{sLevel[nLVL].nMaxCountItem = atoi(sMyFB.cFB_VAL);CANCEL_WAIT'SBS_PROGRESS_WAIT_DELAYOFF';fnSet_ProgressBar(FALSE);}
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    }
    CASE 'players':
    CASE 'serverstatus':
    {
    STACK_VAR _sServer sServerClear;

    SWITCH(sMyFB.cObjTag)
    {
    CASE 'serverstatus':
    {
    if(i==1)
    {
    sServer = sServerClear;
    }
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'rescan': {sServer.sStats.nRescan = atoi(sMyFB.cFB_Val);}
    CASE 'lastscan': {sServer.sStats.cLastscan = sMyFB.cFB_Val;}
    CASE 'lastscanfailed': {sServer.sStats.nLastscanfailed = atoi(sMyFB.cFB_Val);}
    CASE 'progressname': {sServer.sStats.cProgressName = sMyFB.cFB_Val;}
    CASE 'progressdone': {sServer.sStats.nProgressDone = atoi(sMyFB.cFB_Val);}
    CASE 'progresstotal': {sServer.sStats.nProgressTotal = atoi(sMyFB.cFB_Val);}
    CASE 'version': {sServer.sStats.cVersion = sMyFB.cFB_Val;}
    CASE 'uuid': {sServer.sStats.cUuid = sMyFB.cFB_Val;}
    CASE 'info total albums': {sServer.sStats.nInfo_total_albums = atoi(sMyFB.cFB_Val);}
    CASE 'info total artists': {sServer.sStats.nInfo_total_artists = atoi(sMyFB.cFB_Val);}
    CASE 'info total genres': {sServer.sStats.nInfo_total_genres = atoi(sMyFB.cFB_Val);}
    CASE 'info total songs': {sServer.sStats.nInfo_total_songs = atoi(sMyFB.cFB_Val);}
    CASE 'player count': {sServer.sStats.nPlayers_Count = atoi(sMyFB.cFB_Val);}
    CASE 'sn player count': {sServer.sStats.nSn_Players_Count = atoi(sMyFB.cFB_Val);}
    CASE 'other player count': {sServer.sStats.nOther_Players_Count = atoi(sMyFB.cFB_Val);}
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'players_loop':
    {
    //nIndx = sMyFB.nFB_Indx;

    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'playerid': {sServer.sPlayers[nFBIndx].cPlayer_MAC = LOWER_STRING(sMyFB.cFB_Val);}
    CASE 'uuid': {sServer.sPlayers[nFBIndx].cUuid = LOWER_STRING(sMyFB.cFB_Val);}
    CASE 'ip': {sServer.sPlayers[nFBIndx].cIP = sMyFB.cFB_Val;}
    CASE 'name':
    {
    sServer.sPlayers[nFBIndx].cName = sMyFB.cFB_Val;
    if(sServer.sPlayers[nFBIndx].cPlayer_MAC == sSBS.sPlayer.cStrMAC)
    {
    sSBS.sStatus.cPlayerName = sMyFB.cFB_Val;
    }
    }
    CASE 'seq_no': {sServer.sPlayers[nFBIndx].nSeq_No = atoi(sMyFB.cFB_Val);}
    CASE 'model': {sServer.sPlayers[nFBIndx].cModel = sMyFB.cFB_Val;}
    CASE 'displaytype': {sServer.sPlayers[nFBIndx].cDisplayType = sMyFB.cFB_Val;}
    CASE 'canpoweroff': {sServer.sPlayers[nFBIndx].nCanPowerOff = atoi(sMyFB.cFB_Val);}
    CASE 'connected': {sServer.sPlayers[nFBIndx].nConnected = atoi(sMyFB.cFB_Val);}
    CASE 'isplayer': {sServer.sPlayers[nFBIndx].nIsplayer = atoi(sMyFB.cFB_Val);}
    CASE 'power': {sServer.sPlayers[nFBIndx].nPower = atoi(sMyFB.cFB_Val);}
    CASE 'player_needs_upgrade': {sServer.sPlayers[nFBIndx].nPlayer_needs_upgrade = atoi(sMyFB.cFB_Val);}
    CASE 'player_is_upgrading': {sServer.sPlayers[nFBIndx].nPlayer_is_upgrading = atoi(sMyFB.cFB_Val);}
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'playlist':
    {
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'shuffle' :{sSBS.sStatus.nPlylistShuffle = atoi(sMyFB.cFB_VAL);}//fnFB_Shuffle(UI_UPDATE_ACTIVE,NOFORCE);
    CASE 'repeat' :{sSBS.sStatus.nPlylistRepeat = atoi(sMyFB.cFB_VAL);}//fnFB_Repeat(UI_UPDATE_ACTIVE,NOFORCE);
    CASE 'rew' :{}
    CASE 'fwd' :{}
    CASE 'buttons' :{}//subobj includes shuffle, repeat, take all and process seperately
    CASE 'jiveStyle' :{}
    CASE 'command' :{}
    CASE 'remote' :{}
    CASE 'url' :{sSBS.sNowPlaying.cURL = sMyFB.cFB_VAL;}
    CASE 'duration' :{}
    CASE 'artist' :{}
    CASE 'album' :{}
    //CASE 'playlist_index':{}
    CASE 'playlist index' :{}
    CASE 'id' :{}
    CASE 'title' :{sSBS.sNowPlaying.cTitle = fnStrReplace(sMyFB.cFB_VAL,'|',' * ');}
    CASE '_title' :{sSBS.sNowPlaying.cTitle = fnStrReplace(sMyFB.cFB_VAL,'|',' * ');}//sSongInfo.cTitle = sSBS.sNowPlaying.cTitle;}
    CASE '_path':
    {
    if(sMyFB.cFB_VAL != '?')
    {
    sSBS.sNowPlaying.cURL = sMyFB.cFB_VAL;
    //fnGet_SongInfo(sSBS.sNowPlaying.cURL,'');
    }
    }
    CASE '_index':
    {
    if(fnIsNumber(sMyFB.cFB_VAL[1]))
    {
    if(!sSBS.sStatus.nPlylistTracks)
    {
    //fnGet_PlaylistTracks();
    sSBS.sStatus.nPlylistCurIndx = 0;
    }
    else
    {
    sSBS.sStatus.nPlylistCurIndx = (atoi(sMyFB.cFB_VAL) + 1);
    //fnQueue_QCmd("fnGet_PlayerMAC(),' playlist path ',sMyFB.cFB_VAL,' ?'");
    }
    //fnFB_DoSend_UI_CMD(UI_UPDATE_ACTIVE,"'^SHO-',itoa(SBS_BTN_ZAP_IT),',1'");
    }
    else if(sMyFB.cFB_VAL != '?')//if echo don't respond with the same thing
    {
    //fnQueue_QCmd("fnGet_PlayerMAC(),' playlist path ?'");
    }
    }
    CASE '_duration':
    {
    if(fnIsNumber(sParam.cParam[3][1]) && sParam.cParam[2] == 'duration' && sParam.cParam[1] == 'playlist')
    {
    STACK_VAR LONG nRxIndx;

    nRxIndx = atoi(sParam.cParam[3]);

    if(sSBS.sCurQ.nTrackCounter)
    {
    if(nRxIndx == (sSBS.sCurQ.nTrackCounter))//this is the one we just queried
    {
    if(sSBS.sCurQ.nAddorDelete == SBS_DEL_TRKS)//delete
    {
    sSBS.sCurQ.nTotalDuration = (sSBS.sCurQ.nTotalDuration - atof(sMyFB.cFB_VAL));
    }
    else //0 or 1 = add
    {
    sSBS.sCurQ.nTotalDuration = (sSBS.sCurQ.nTotalDuration + atof(sMyFB.cFB_VAL));
    }
    }
    else
    {
    fnJSON_Debug("'Process_FB, TRACKS ERROR! RX TRK-[ ',itoa(nRxIndx),' ] BUT REQUESTED TRK-[ ',itoa(sSBS.sCurQ.nTrackCounter),' ] :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRxIndx == sSBS.sNowPlaying.nIndx )
    {
    sSBS.sNowPlaying.nDuration = atoi(sMyFB.cFB_VAL);
    }
    }
    }
    CASE '_tracks':
    {
    if(fnIsNumber(sMyFB.cFB_VAL[1]))
    {
    sSBS.sStatus.nPlyListTracks = atoi(sMyFB.cFB_VAL);
    if(!sSBS.sStatus.nPlyListTracks && sSBS.sStatus.nPlyListTracks)
    {//also performed in playlistcontrol cmd:add or delete
    fnBtn_DoCommand(SBS_PlayMode_Play);
    }
    if(sSBS.sStatus.nPlyListTracks)
    {
    //fnGet_PlaylistIndex();
    }
    else
    {
    fnPlayer_ClearPlyList();
    //sSBS.sStatus.nPlylistCurIndx = 0;
    }
    if(sSBS.sCurQ.nTrackCount < sSBS.sStatus.nPlyListTracks)
    {
    //CANCEL_WAIT 'GET_TOTAL_TIME';
    // WAIT 100 'GET_TOTAL_TIME'
    // {
    // fnJSON_Debug("'Process_FB, TRACKS initiating fnGet_TotalPlayTime(',itoa(sSBS.sStatus.nPlyListTracks),') :DEBUG<',ITOA(__LINE__),'>'",1);
    // fnGet_TotalPlayTime(sSBS.sStatus.nPlyListTracks,SBS_ADD_TRKS,TYPE_CAST(sSBS.sStatus.nPlyListTracks - sSBS.sCurQ.nTrackCount));
    // }
    }
    else
    {
    sSBS.sCurQ.nTrackCount = sSBS.sStatus.nPlyListTracks;
    }

    fnFB_CurPlyListIndx(UI_UPDATE_ACTIVE,NOFORCE);
    }
    }
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'data':
    CASE 'status':
    {
    SWITCH(sMyFB.cObjTag)
    {
    CASE 'command':
    {
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'icon'://"pandora","rate",1 or 0
    {
    SWITCH(sObj[sMyFB.nOrigIndx].cTag)
    {
    CASE 'repeat':
    {
    sSBS.sNowPlaying.cBtnRepeatCmdIcon = sMyFB.cFB_Val;
    if(sSBS.sStatus.nPlylistRepeat){fnBtn_DoCommand(SBS_BTN_PLYLST_REPEAT_0);}
    //fnFB_Repeat(UI_UPDATE_ACTIVE,NOFORCE);
    }
    CASE 'shuffle':
    {
    sSBS.sNowPlaying.cBtnShuffleCmdIcon = sMyFB.cFB_Val;
    if(sSBS.sStatus.nPlylistShuffle){fnBtn_DoCommand(SBS_BTN_PLYLST_SHUFFLE_0);}
    //fnFB_Shuffle(UI_UPDATE_ACTIVE,NOFORCE);
    }
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'buttons':
    {
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'fwd':{sSBS.sNowPlaying.nBtnFFwd = atoi(sMyFB.cFB_Val);}//1 is available, 0 is not available for use
    CASE 'rew':{sSBS.sNowPlaying.nBtnRew = atoi(sMyFB.cFB_Val);}
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'repeat'://thumbsup on pandora
    {
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'icon': {sSBS.sNowPlaying.cBtnRepeatIcon = sMyFB.cFB_Val;}
    CASE 'jiveStyle': {sSBS.sNowPlaying.cBtnRepeatJiveStyle = sMyFB.cFB_Val;fnFB_Repeat(UI_UPDATE_ACTIVE,NOFORCE);}//tumbsup
    CASE 'tooltip': {sSBS.sNowPlaying.cBtnRepeatToolTip = sMyFB.cFB_Val;}//I like this song in pandora
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'shuffle'://tumbsdown on pandora
    {
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'icon': {sSBS.sNowPlaying.cBtnShuffleIcon = sMyFB.cFB_Val;}
    CASE 'jiveStyle': {sSBS.sNowPlaying.cBtnShuffleJiveStyle = sMyFB.cFB_Val;fnFB_Shuffle(UI_UPDATE_ACTIVE,NOFORCE);}//tumbsdown
    CASE 'tooltip': {sSBS.sNowPlaying.cBtnShuffleToolTip = sMyFB.cFB_Val;}//I don't like this song in pandora
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'data':
    CASE 'status':
    {
    if(i==1)// && sMyFB.cObjTag == 'status')
    {
    STACK_VAR _sStatusInfo sStatusClear; // Status block to receive current status 1427637377.0878

    sSBS.sStatus = sStatusClear;
    }
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'player_ip': {sSBS.sStatus.cPlayerIP = sMyFB.cFB_Val;}
    CASE 'play time': {sSBS.sStatus.cPlayTime = sMyFB.cFB_Val;}
    CASE 'id': {sSBS.sStatus.cItem_ID = sMyFB.cFB_Val;}
    CASE 'can_seek': {sSBS.sStatus.cCanSeek = sMyFB.cFB_Val;}
    CASE 'playlist_timestamp': {sSBS.sStatus.cPL_TmStamp = sMyFB.cFB_Val;}
    CASE 'playlist mode': {sSBS.sStatus.cPL_Mode = sMyFB.cFB_Val;}
    CASE 'seq_no': {sSBS.sStatus.cSeqNo = sMyFB.cFB_Val;}
    CASE 'title': {sSBS.sNowPlaying.cTitle = fnStrReplace(sMyFB.cFB_Val,'|',' * ');}
    CASE 'genre': {sSBS.sNowPlaying.cGenre = sMyFB.cFB_Val;}
    CASE 'artist': {sSBS.sNowPlaying.cArtist = sMyFB.cFB_Val;}
    CASE 'album': {sSBS.sNowPlaying.cAlbum = sMyFB.cFB_Val;}
    CASE 'current_title': {sSBS.sNowPlaying.cCurrentTitle = fnStrReplace(sMyFB.cFB_Val,'|',' * ');}
    CASE 'player_name': {sSBS.sStatus.cPlayerName = sMyFB.cFB_Val;}
    CASE 'player_connected': {sSBS.sStatus.nPlayer_Connected = atoi(sMyFB.cFB_Val);}
    CASE 'power': {sSBS.sStatus.nPower = atoi(sMyFB.cFB_Val);sSBS.sPlayer.nPort = sSBS.sStatus.nPower;}
    CASE 'signalstrength': {sSBS.sStatus.nSignalStrength = atoi(sMyFB.cFB_Val);}
    CASE 'rescan': {fnSBS_SetRescan(atoi(sMyFB.cFB_Val));}
    CASE 'mode':
    {
    SWITCH(sMyFB.cFB_Val)
    {
    CASE 'play': {sSBS.sStatus.nMode = SBS_PlayMode_Play;fnPlayer_Play();}
    CASE 'pause': {sSBS.sStatus.nMode = SBS_PlayMode_Pause;fnPlayer_Pause();}
    CASE 'stop': {sSBS.sStatus.nMode = SBS_PlayMode_Stop;fnPlayer_Stop();}
    CASE 'off': {sSBS.sStatus.nMode = SBS_PlayMode_Off;fnPlayer_Stop();}
    DEFAULT:
    {
    sSBS.sStatus.nMode = SBS_PlayMode_Unknown;
    fnPlayer_Stop();
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'artwork_url': {sSBS.sNowPlaying.cArtworkURL = sMyFB.cFB_Val;}
    CASE 'rate': {sSBS.sStatus.nRate = atol(sMyFB.cFB_Val);}
    CASE 'time': {sSBS.sSongTime.nSongTime = atoi(sMyFB.cFB_Val);}
    CASE 'duration': {sSBS.sNowPlaying.nDuration = atoi(sMyFB.cFB_Val);}
    CASE 'sleep': {sSBS.sStatus.nSleepTime = atoi(sMyFB.cFB_Val);}
    CASE 'will_sleep_in': {sSBS.sStatus.nSleepRemaining = atoi(sMyFB.cFB_Val);}
    CASE 'mixer volume':
    {
    STACK_VAR FLOAT volume;

    sSBS.sStatus.nMixVolume = atoi(sMyFB.cFB_Val);
    // Convert to I/R scale as well (as shown on Squeezebox display)
    volume = atof(sMyFB.cFB_Val);
    volume = (volume + 0.1) / 2.5;
    sSBS.sStatus.nIRVolume = type_cast(volume);
    }
    CASE 'mixer balance': {sSBS.sStatus.nMixBalance = atoi(sMyFB.cFB_Val);}
    CASE 'mixer bass': {sSBS.sStatus.nMixBass = atoi(sMyFB.cFB_Val);}
    CASE 'mixer treble': {sSBS.sStatus.nMixTreble = atoi(sMyFB.cFB_Val);}
    CASE 'mixer pitch': {sSBS.sStatus.nMixPitch = atoi(sMyFB.cFB_Val);}
    CASE 'playlist repeat': {sSBS.sStatus.nPlylistRepeat = atoi(sMyFB.cFB_Val);}//fnFB_Repeat(UI_UPDATE_ACTIVE,NOFORCE);
    CASE 'playlist shuffle': {sSBS.sStatus.nPlylistShuffle = atoi(sMyFB.cFB_Val);}//fnFB_Shuffle(UI_UPDATE_ACTIVE,NOFORCE);
    CASE 'remote': {sSBS.sNowPlaying.nRemote = atoi(sMyFB.cFB_Val);}
    CASE 'remote_title': {sSBS.sNowPlaying.cRemoteTitle = fnStrReplace(sMyFB.cFB_Val,'|',' * ');}
    CASE 'remoteMeta': {sSBS.sStatus.cRemoteMeta = sMyFB.cFB_Val;}
    CASE 'playlist_cur_index': {sSBS.sStatus.nPlylistCurIndx = atoi(sMyFB.cFB_Val)+1;}
    //fnQueue_QCmd("fnGet_PlayerMAC(),'playlist path ',sMyFB.cFB_Val,' ?'");
    //Zero based
    //myCurQ.nPlylistCurIndx = sStatus.nPlylistCurIndx;
    CASE 'playlist_tracks':
    {
    sSBS.sStatus.nPlylistTracks = atoi(sMyFB.cFB_Val);
    if(!sSBS.sStatus.nPlylistTracks)
    {
    sSBS.sStatus.nPlylistCurIndx = 0;
    }
    //sSBS.sCurQ.nPlylistTracks = sStatus.nPlylistTracks;

    if(sSBS.sCurQ.nTrackCount < sSBS.sStatus.nPlyListTracks)
    {
    CANCEL_WAIT 'GET_TOTAL_TIME';
    WAIT 100 'GET_TOTAL_TIME'
    {
    //fnDevMod_DeBug("'Parse_Playlist: TRACKS initiating fnGet_TotalPlayTime(',itoa(sSBS.sStatus.nPlyListTracks),') :DEBUG<',ITOA(__LINE__),'>'",2);
    //recent fnGet_TotalPlayTime(sSBS.sStatus.nPlyListTracks,SBS_ADD_TRKS,TYPE_CAST(sSBS.sStatus.nPlyListTracks - sSBS.sCurQ.nTrackCount));
    }
    }
    }
    CASE 'waitingToPlay':
    {
    //what to do with this????????????
    }
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'playlist_loop':
    {
    if(i==1 && sMyFB.cTopTag == 'status')
    {
    STACK_VAR _sCurQList sCurQListClear[MAX_NUM_BROWSE_LINES];

    sSBS.sCurQList = sCurQListClear;
    if(!nFBIndx){nFBIndx=1;}
    }
    else if(i==1 && sMyFB.cTopTag == 'data')
    {
    STACK_VAR _sNowPlaying sNowPlayingClear;

    sSBS.sNowPlaying = sNowPlayingClear;
    if(!nFBIndx){nFBIndx=1;}
    }
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'playlist index':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(sSBS.sCurQList[nFBIndx].nIndx){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].nIndx = (atoi(sMyFB.cFB_Val)+1);
    if(nFBIndx == 1){sSBS.sCurQ.nStartQItem = sSBS.sCurQList[nFBIndx].nIndx;}
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.nIndx = (atoi(sMyFB.cFB_Val)+1);
    }
    }
    CASE 'id':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(length_string(sSBS.sCurQList[nFBIndx].cItem_ID)){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].cItem_ID = sMyFB.cFB_Val;
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.cItem_ID = sMyFB.cFB_Val;
    }
    }
    CASE 'coverid':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(length_string(sSBS.sCurQList[nFBIndx].cCoverID)){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].cCoverID = sMyFB.cFB_Val;
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.cCoverID = sMyFB.cFB_Val;
    }
    }
    CASE 'url':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(length_string(sSBS.sCurQList[nFBIndx].cURL)){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].cURL = sMyFB.cFB_Val;
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.cURL = sMyFB.cFB_Val;
    nFBS = find_string(sMyFB.cFB_Val,"':'",1);
    if(nFBS) //just want file or app name
    {
    sSBS.sNowPlaying.cSource = LEFT_STRING(sMyFB.cFB_Val,nFBS-1);
    }
    }
    }
    CASE 'type':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(length_string(sSBS.sCurQList[nFBIndx].cType)){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].cType = sMyFB.cFB_Val;
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.cType = sMyFB.cFB_Val;
    }
    }
    CASE 'tracknum':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(sSBS.sCurQList[nFBIndx].nTrackNum){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].nTrackNum = atoi(sMyFB.cFB_Val);
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.nTrackNum = atoi(sMyFB.cFB_Val);
    }
    }
    CASE 'artwork_url':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(length_string(sSBS.sCurQList[nFBIndx].cArtworkURL)){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].cArtworkURL = sMyFB.cFB_Val;
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.cArtworkURL = sMyFB.cFB_Val;
    //will need to further parse out leading junk to use this
    //nFBS = find_string(sMyFB.cFB_Val,"':'",1);
    // if(nFBS) //just want file or app name
    // {
    // sSBS.sNowPlaying.cSource = LEFT_STRING(sMyFB.cFB_Val,nFBS-1);
    // }
    }
    }
    CASE 'year':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(length_string(sSBS.sCurQList[nFBIndx].cYear)){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].cYear = sMyFB.cFB_Val;
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.cYear = sMyFB.cFB_Val;
    }
    }
    CASE 'genre':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(length_string(sSBS.sCurQList[nFBIndx].cGenre)){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].cGenre = sMyFB.cFB_Val;
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.cGenre = sMyFB.cFB_Val;
    }
    }
    CASE 'artist':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(length_string(sSBS.sCurQList[nFBIndx].cArtist)){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].cArtist = sMyFB.cFB_Val;
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.cArtist = sMyFB.cFB_Val;
    }
    }
    CASE 'album':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(length_string(sSBS.sCurQList[nFBIndx].cAlbum)){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].cAlbum = sMyFB.cFB_Val;
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.cAlbum = sMyFB.cFB_Val;
    }
    }
    CASE 'title':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(length_string(sSBS.sCurQList[nFBIndx].cTitle)){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].cTitle = fnStrReplace(sMyFB.cFB_Val,'|',' * ');
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.cTitle = fnStrReplace(sMyFB.cFB_Val,'|',' * ');
    }
    }
    CASE 'duration':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(sSBS.sCurQList[nFBIndx].nDuration){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].nDuration = atoi(sMyFB.cFB_Val);
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.nDuration = atoi(sMyFB.cFB_Val);
    }
    }
    CASE 'remote':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(sSBS.sCurQList[nFBIndx].nRemote){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].nRemote = atoi(sMyFB.cFB_Val);
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.nRemote = atoi(sMyFB.cFB_Val);
    }
    }
    CASE 'remote_title':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(length_string(sSBS.sCurQList[nFBIndx].cRemoteTitle)){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].cRemoteTitle = fnStrReplace(sMyFB.cFB_Val,'|',' * ');
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.cRemoteTitle = fnStrReplace(sMyFB.cFB_Val,'|',' * ');
    }
    }
    CASE 'replay_gain':
    {
    if(sMyFB.cTopTag == 'status')
    {
    if(length_string(sSBS.sCurQList[nFBIndx].cReplayGain)){nFBIndx++;}

    sSBS.sCurQList[nFBIndx].cReplayGain = sMyFB.cFB_Val;
    }
    else if(sMyFB.cTopTag == 'data')
    {
    sSBS.sNowPlaying.cReplayGain = sMyFB.cFB_Val;
    }
    }
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'remoteMeta':
    {
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'id': {sSBS.sNowPlaying.cItem_ID = sMyFB.cFB_Val;}
    CASE 'title': {sSBS.sNowPlaying.cTitle = fnStrReplace(sMyFB.cFB_Val,'|',' * ');}
    CASE 'artist': {sSBS.sNowPlaying.cArtist = sMyFB.cFB_Val;}
    CASE 'duration': {sSBS.sNowPlaying.nDuration = atoi(sMyFB.cFB_Val);}
    CASE 'artwork_url':
    {
    sSBS.sNowPlaying.cArtworkURL = sMyFB.cFB_Val;
    nFBS = find_string(sMyFB.cFB_Val,"':'",1);
    //if(nFBS) //just want file or app name
    // {
    // sSBS.sNowPlaying.cSource = LEFT_STRING(sMyFB.cFB_Val,nFBS-1);
    // }
    }
    CASE 'album': {sSBS.sNowPlaying.cAlbum = sMyFB.cFB_Val;}
    CASE 'type': {sSBS.sNowPlaying.cType = sMyFB.cFB_Val;}
    CASE 'url':
    {
    sSBS.sNowPlaying.cURL = sMyFB.cFB_Val;
    nFBS = find_string(sMyFB.cFB_Val,"':'",1);
    if(nFBS) //just want file or app name
    {
    sSBS.sNowPlaying.cSource = LEFT_STRING(sMyFB.cFB_Val,nFBS-1);
    }
    }
    CASE 'remote': {sSBS.sNowPlaying.nRemote = sMyFB.cFB_Val;}
    CASE 'year': {sSBS.sNowPlaying.cYear = sMyFB.cFB_Val;}
    CASE 'replay_gain': {sSBS.sNowPlaying.cReplayGain = sMyFB.cFB_Val;}
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    }
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }
    CASE 'songinfo':
    {
    //STACK_VAR _sNowPlaying myNowPlaying;
    //STACK_VAR INTEGER nNowPlaying;

    SWITCH(sMyFB.cFB_Tag)
    {
    CASE 'album' :{sSongInfo.cAlbum = sMyFB.cFB_VAL;}
    CASE 'album_id' :{sSongInfo.cAlbum_ID = sMyFB.cFB_VAL;}
    CASE 'artist' :{sSongInfo.cArtist = sMyFB.cFB_VAL;}
    CASE 'artist_id' :{sSongInfo.cArtist_ID = sMyFB.cFB_VAL;}
    CASE 'genre' :{sSongInfo.cGenre = sMyFB.cFB_VAL;}
    CASE 'genre_id' :{sSongInfo.cGenre_ID = sMyFB.cFB_VAL;}
    //CASE 'cmd' :{sSongInfo.cCMD = atoi(sMyFB.cFB_VAL);}
    CASE 'artwork_url' :{sSongInfo.cArtworkURL = sMyFB.cFB_VAL;}
    CASE 'count' :{sSongInfo.nCount = atoi(sMyFB.cFB_VAL);}
    CASE 'cover_id' :{sSongInfo.cCoverID = sMyFB.cFB_VAL;}
    CASE 'title' :{sSongInfo.cTitle = fnStrReplace(sMyFB.cFB_VAL,'|',' * ');}
    CASE 'id' :{sSongInfo.cItem_ID = sMyFB.cFB_VAL;}
    CASE 'disc' :{sSongInfo.nDisc = atoi(sMyFB.cFB_VAL);}
    CASE 'disccount' :{sSongInfo.nDiscCount = atoi(sMyFB.cFB_VAL);}
    CASE 'tagversion' :{sSongInfo.cTagVersion = sMyFB.cFB_VAL;}
    CASE 'filesize' :{sSongInfo.cFileSize = sMyFB.cFB_VAL;}
    CASE 'coverart' :{sSongInfo.nCoverArtAvail = atoi(sMyFB.cFB_VAL);}
    CASE 'replay_gain' :{sSongInfo.cReplayGain = sMyFB.cFB_VAL;}
    CASE 'compilation' :{sSongInfo.nCompilation = atoi(sMyFB.cFB_VAL);}
    CASE 'samplerate' :{sSongInfo.cSampleRate = sMyFB.cFB_VAL;}
    CASE 'samplesize' :{sSongInfo.cSampleSize = sMyFB.cFB_VAL;}
    CASE 'rating' :{sSongInfo.cRating = sMyFB.cFB_VAL;}
    CASE 'bpm' :{sSongInfo.nBPM = atoi(sMyFB.cFB_VAL);}
    CASE 'type' :{sSongInfo.cType = sMyFB.cFB_VAL;}
    CASE 'duration' :{sSongInfo.nDuration = atoi(sMyFB.cFB_VAL);}
    CASE 'tracknum' :{sSongInfo.nTrackNum = atoi(sMyFB.cFB_VAL);}
    CASE 'bitrate' :{sSongInfo.cBitRate = sMyFB.cFB_VAL;}
    CASE 'year' :{sSongInfo.cYear = sMyFB.cFB_VAL;}
    CASE 'remote' :{sSongInfo.nRemote = atoi(sMyFB.cFB_VAL);}
    CASE 'remote_title' :{sSongInfo.cRemoteTitle = fnStrReplace(sMyFB.cFB_VAL,'|',' * ');}
    CASE 'url' :
    {
    sSongInfo.cURL = sMyFB.cFB_VAL;
    nFBS = find_string(sSongInfo.cURL,"':'",1);
    if(nFBS)
    {
    sSongInfo.cSource = LEFT_STRING(sSongInfo.cURL,nFBS-1);
    if(sSongInfo.cSource = 'http')
    {
    sSongInfo.cSource = 'Internet Radio';
    }
    else if(sSongInfo.cSource = 'file')
    {
    sSongInfo.cSource = 'Hard Drive';
    }
    }
    }
    CASE 'track_id' :{sSongInfo.cItem_ID = sMyFB.cFB_VAL;}
    CASE 'album_replay_gain' :{sSongInfo.cAlbum = sMyFB.cFB_VAL;}
    CASE 'modificationTime' :{sSongInfo.cAlbum = sMyFB.cFB_VAL;}
    CASE 'artwork_track_id' :{sSongInfo.cAlbum = sMyFB.cFB_VAL;}
    DEFAULT:
    {
    nRecognized = 0;
    fnJSON_Debug("'Process_FB, !!, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",1);
    }
    }
    if(nRecognized)
    {
    fnJSON_Debug("'Process_FB, $$, TOPTAG-[ ',sMyFB.cTopTag,' ], TAG-[ ',sMyFB.cTag,' ], OBJTAG-[ ',sMyFB.cObjTag,' ], FBTAG-[ ',sMyFB.cFB_Tag[i],' ], VAL-[ ',sMyFB.cFB_Val[i],' ], FBINDX- :DEBUG<',ITOA(__LINE__),'>'",3);
    nRecognized = 0;
    }
    }

    CASE 'id': {sLevel[nLVL].nID = atoi(sMyFB.cFB_VAL);}

    CASE 'player':
    {
    SWITCH(sMyFB.cFB_Tag)
    {
    CASE '_count':
    {
    if(fnIsNumber(sMyFB.cFB_VAL[1]))
    {
    sServer.sStats.nPlayers_Count = atoi(sMyFB.cFB_VAL);
    if(sServer.sStats.nPlayers_Count)
    {
    fnQueue_QCmd("'serverstatus 0 ',itoa(sServer.sStats.nPlayers_Count),' tags:'");
    }
    else
    {
    fnQueue_QCmd("'serverstatus 0 5 tags:'");//max possible
    }
    }
    else
    {
    fnQueue_QCmd("'serverstatus 0 5 tags:'");//max possible
    }
    }
    CASE '_id': {}
    CASE '_name': {}
    CASE '_ip': {}
  • TonyAngeloTonyAngelo Posts: 315
    What about parsing the API outside of the Netlinx system (something like google app engine) and rolling your own api for retrieving the info in a Netlinx friendly format?

    You could do all your API parsing for all your systems from a single app in theory.
Sign In or Register to comment.