xiph / Icecast-Server

Icecast streaming media server (Mirror) - Please report bugs at https://gitlab.xiph.org/xiph/icecast-server/issues
https://icecast.org
GNU General Public License v2.0
465 stars 127 forks source link

Request: Make status-json.xslt a real JSON REST API endpoint #65

Open djechelon opened 1 year ago

djechelon commented 1 year ago

TL:DR;

Please make sure that icecast status-json.xslt returns a singleton array of source when there is a single source available, to allow consumers using an object-oriented model of icecast output for scraping.


As a programmer, I enjoy integrating open systems that speak popular protocols.

I was working on a mobile front end for icecast2 and I found that icecast exposes a JSON API to parse the available streams. I worked with Angular to process it.

I found that the JSON is generated by an XSL transform, which produces an output that in the REST paradigm is not easy to work with. In XML, especially if you have a schema defined, you can easily tell whether the <source> tag appears once or multiple times, and multiple tags appear at the same level. In JSON, the source must be either an object or an array for the client to parse it easily

The problem is, look at these outputs when you have a single stream running, or multiple:

{
  "icestats": {
    "admin": "example@localhost",
    "host": "localhost",
    "location": "somewhere",
    "server_id": "Icecast 2.4.4",
    "server_start": "Tue, 06 Jun 2023 09:33:57 +0000",
    "server_start_iso8601": "2023-06-06T09:33:57+0000",
    "source": [
      {
        ...
        "listenurl": "http://localhost:8000/silent2.ogg",
        "server_description": "Unspecified description",
        "server_name": "The Silent Party",
        ...
      },
      {
        ...
        "listenurl": "http://localhost:8000/stream",
        "server_description": "Unspecified description",
        ....
      }
    ]
  }
}
{
  "icestats": {
    "admin": "example@localhost",
    "host": "localhost",
    "location": "somewhere",
    "server_id": "Icecast 2.4.4",
    "server_start": "Tue, 06 Jun 2023 09:33:57 +0000",
    "server_start_iso8601": "2023-06-06T09:33:57+0000",
    "source": {
      "audio_bitrate": 128000,
      ....
      "listenurl": "http://localhost:8000/silent2.ogg",
      "server_description": "Unspecified description",
      "server_name": "The Silent Party",
      ....
    }
  }
}

As you can see, if there is a single stream, then the object is a map. Otherwise, it's an array.

Software working on JSON has to suffer additional burden (i.e. more code, more tests, less reliability) to handle the icecast output compared to the straight solution of using an array for the sources.

Here is my solution for an Angular app

export interface IcecastStatsDto {
  admin?: string;
  client_connections?: number;
  ....
  stats_connections?: number;
  source?: IcecastSourceDto | IcecastSourceDto[];
}

And some typescript code to change the IcecastSourceDto | IcecastSourceDto[] into a (singleton?) array

  private getArrayFromSingleValue(x?: IcecastSourceDto | IcecastSourceDto[]): IcecastSourceDto[] {
    if (!x) {
      return <IcecastSourceDto[]>[];
    } else if ('filter' in x) {
      return <IcecastSourceDto[]>x;
    } else if ('server_url' in x) {
      return <IcecastSourceDto[]>[<IcecastSourceDto>x];
    } else {
      return <IcecastSourceDto[]>[];
    }
  }

This is for a Javascript FE. If I was using a C# or Java application, decoding icecast output into a POCO/POJO woulc be much harder. Defining a singleton array (i.e. an array containing one element) is the preferred solution in OO world,

I hope my feedback will be useful to improve the software