mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
handle .xspf requests. Like m3u, send a webroot file if it exists else generate
one. The generated one comes from an xslt in adminroot. Just need some icons svn path=/icecast/trunk/icecast/; revision=13539
This commit is contained in:
parent
bb0b1a2a32
commit
e06793a7ad
73
admin/xspf.xsl
Normal file
73
admin/xspf.xsl
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<!--
|
||||||
|
XSPF xslt stylesheet for Icecast 2.3.1 and above
|
||||||
|
Copyright (C) 2007 Thomas B. Ruecker, tbr@ruecker-itk.de
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the
|
||||||
|
Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0" >
|
||||||
|
<xsl:output omit-xml-declaration="no" media-type="application/xspf+xml"
|
||||||
|
method="xml" indent="yes" encoding="UTF-8" />
|
||||||
|
<xsl:template match = "/icestats" >
|
||||||
|
<playlist version="1" xmlns="http://xspf.org/ns/0/">
|
||||||
|
<title><xsl:value-of select="server" /></title>
|
||||||
|
<creator><xsl:value-of select="server" /></creator>
|
||||||
|
<trackList >
|
||||||
|
<!-- end of "header" -->
|
||||||
|
|
||||||
|
<xsl:for-each select="source">
|
||||||
|
|
||||||
|
<!-- do we need to do something about streams that need auth?-->
|
||||||
|
|
||||||
|
<track>
|
||||||
|
<location><xsl:value-of select="listenurl" /></location>
|
||||||
|
|
||||||
|
|
||||||
|
<xsl:if test="artist"><creator><xsl:value-of select="artist" /></creator></xsl:if>
|
||||||
|
<title><xsl:value-of select="title" /></title>
|
||||||
|
<!-- The <xsl:text>\n</xsl:text> elements in the following part are used
|
||||||
|
to enforce linebreaks this format seems to be expected by clients -->
|
||||||
|
<annotation>
|
||||||
|
<xsl:if test="server_name">Stream Title: <xsl:value-of select="server_name" /><xsl:text>
|
||||||
|
</xsl:text></xsl:if>
|
||||||
|
<xsl:if test="server_description">Stream Description: <xsl:value-of select="server_description" /></xsl:if>
|
||||||
|
Content Type:<xsl:value-of select="server_type" /><xsl:text>
|
||||||
|
</xsl:text>
|
||||||
|
<xsl:if test="bitrate">Bitrate: <xsl:value-of select="bitrate" /><xsl:text>
|
||||||
|
</xsl:text></xsl:if>
|
||||||
|
<xsl:if test="quality">Quality: <xsl:value-of select="quality" /><xsl:text>
|
||||||
|
</xsl:text></xsl:if>
|
||||||
|
<xsl:if test="video_quality">Video Quality: <xsl:value-of select="video_quality" /><xsl:text>
|
||||||
|
</xsl:text></xsl:if>
|
||||||
|
<xsl:if test="frame_size">Framesize: <xsl:value-of select="frame_size" /><xsl:text>
|
||||||
|
</xsl:text></xsl:if>
|
||||||
|
<xsl:if test="frame_rate">Framerate: <xsl:value-of select="frame_rate" /><xsl:text>
|
||||||
|
</xsl:text></xsl:if>
|
||||||
|
<xsl:if test="listeners">Current Listeners: <xsl:value-of select="listeners" /><xsl:text>
|
||||||
|
</xsl:text></xsl:if>
|
||||||
|
<xsl:if test="listener_peak">Peak Listeners: <xsl:value-of select="listener_peak" /><xsl:text>
|
||||||
|
</xsl:text></xsl:if>
|
||||||
|
<xsl:if test="genre">Stream Genre: <xsl:value-of select="genre" /></xsl:if>
|
||||||
|
</annotation>
|
||||||
|
|
||||||
|
<xsl:if test="server_url"><info><xsl:value-of select="server_url" /></info></xsl:if>
|
||||||
|
|
||||||
|
</track>
|
||||||
|
|
||||||
|
</xsl:for-each>
|
||||||
|
</trackList>
|
||||||
|
</playlist>
|
||||||
|
|
||||||
|
</xsl:template>
|
||||||
|
</xsl:stylesheet>
|
13
src/admin.c
13
src/admin.c
@ -33,6 +33,7 @@
|
|||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "xslt.h"
|
#include "xslt.h"
|
||||||
#include "fserve.h"
|
#include "fserve.h"
|
||||||
|
#include "admin.h"
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
@ -109,10 +110,6 @@
|
|||||||
#define DEFAULT_TRANSFORMED_REQUEST ""
|
#define DEFAULT_TRANSFORMED_REQUEST ""
|
||||||
#define BUILDM3U_RAW_REQUEST "buildm3u"
|
#define BUILDM3U_RAW_REQUEST "buildm3u"
|
||||||
|
|
||||||
#define RAW 1
|
|
||||||
#define TRANSFORMED 2
|
|
||||||
#define PLAINTEXT 3
|
|
||||||
|
|
||||||
int admin_get_command(char *command)
|
int admin_get_command(char *command)
|
||||||
{
|
{
|
||||||
if(!strcmp(command, FALLBACK_RAW_REQUEST))
|
if(!strcmp(command, FALLBACK_RAW_REQUEST))
|
||||||
@ -195,8 +192,6 @@ static void command_updatemetadata(client_t *client, source_t *source,
|
|||||||
static void admin_handle_mount_request(client_t *client, source_t *source,
|
static void admin_handle_mount_request(client_t *client, source_t *source,
|
||||||
int command);
|
int command);
|
||||||
static void admin_handle_general_request(client_t *client, int command);
|
static void admin_handle_general_request(client_t *client, int command);
|
||||||
static void admin_send_response(xmlDocPtr doc, client_t *client,
|
|
||||||
int response, char *xslt_template);
|
|
||||||
|
|
||||||
/* build an XML doc containing information about currently running sources.
|
/* build an XML doc containing information about currently running sources.
|
||||||
* If a mountpoint is passed then that source will not be added to the XML
|
* If a mountpoint is passed then that source will not be added to the XML
|
||||||
@ -267,8 +262,8 @@ xmlDocPtr admin_build_sourcelist (const char *mount)
|
|||||||
return(doc);
|
return(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void admin_send_response(xmlDocPtr doc, client_t *client,
|
void admin_send_response (xmlDocPtr doc, client_t *client,
|
||||||
int response, char *xslt_template)
|
int response, const char *xslt_template)
|
||||||
{
|
{
|
||||||
if (response == RAW)
|
if (response == RAW)
|
||||||
{
|
{
|
||||||
@ -958,7 +953,7 @@ static void command_stats(client_t *client, int response) {
|
|||||||
|
|
||||||
DEBUG0("Stats request, sending xml stats");
|
DEBUG0("Stats request, sending xml stats");
|
||||||
|
|
||||||
stats_get_xml(&doc, 1);
|
stats_get_xml(&doc, 1, NULL);
|
||||||
admin_send_response(doc, client, response, STATS_TRANSFORMED_REQUEST);
|
admin_send_response(doc, client, response, STATS_TRANSFORMED_REQUEST);
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
return;
|
return;
|
||||||
|
@ -13,9 +13,18 @@
|
|||||||
#ifndef __ADMIN_H__
|
#ifndef __ADMIN_H__
|
||||||
#define __ADMIN_H__
|
#define __ADMIN_H__
|
||||||
|
|
||||||
|
#include <libxml/parser.h>
|
||||||
|
#include <libxml/tree.h>
|
||||||
|
|
||||||
#include "refbuf.h"
|
#include "refbuf.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
|
||||||
|
#define RAW 1
|
||||||
|
#define TRANSFORMED 2
|
||||||
|
#define PLAINTEXT 3
|
||||||
|
|
||||||
void admin_handle_request(client_t *client, char *uri);
|
void admin_handle_request(client_t *client, char *uri);
|
||||||
|
void admin_send_response(xmlDocPtr doc, client_t *client,
|
||||||
|
int response, const char *xslt_template);
|
||||||
|
|
||||||
#endif /* __ADMIN_H__ */
|
#endif /* __ADMIN_H__ */
|
||||||
|
21
src/fserve.c
21
src/fserve.c
@ -50,6 +50,7 @@
|
|||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "cfgfile.h"
|
#include "cfgfile.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "admin.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
|
||||||
#include "fserve.h"
|
#include "fserve.h"
|
||||||
@ -376,6 +377,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
char *fullpath;
|
char *fullpath;
|
||||||
int m3u_requested = 0, m3u_file_available = 1;
|
int m3u_requested = 0, m3u_file_available = 1;
|
||||||
|
int xspf_requested = 0, xspf_file_available = 1;
|
||||||
ice_config_t *config;
|
ice_config_t *config;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
|
|
||||||
@ -385,11 +387,14 @@ int fserve_client_create (client_t *httpclient, const char *path)
|
|||||||
if (strcmp (util_get_extension (fullpath), "m3u") == 0)
|
if (strcmp (util_get_extension (fullpath), "m3u") == 0)
|
||||||
m3u_requested = 1;
|
m3u_requested = 1;
|
||||||
|
|
||||||
|
if (strcmp (util_get_extension (fullpath), "xspf") == 0)
|
||||||
|
xspf_requested = 1;
|
||||||
|
|
||||||
/* check for the actual file */
|
/* check for the actual file */
|
||||||
if (stat (fullpath, &file_buf) != 0)
|
if (stat (fullpath, &file_buf) != 0)
|
||||||
{
|
{
|
||||||
/* the m3u can be generated, but send an m3u file if available */
|
/* the m3u can be generated, but send an m3u file if available */
|
||||||
if (m3u_requested == 0)
|
if (m3u_requested == 0 && xspf_requested == 0)
|
||||||
{
|
{
|
||||||
WARN2 ("req for file \"%s\" %s", fullpath, strerror (errno));
|
WARN2 ("req for file \"%s\" %s", fullpath, strerror (errno));
|
||||||
client_send_404 (httpclient, "The file you requested could not be found");
|
client_send_404 (httpclient, "The file you requested could not be found");
|
||||||
@ -397,6 +402,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
m3u_file_available = 0;
|
m3u_file_available = 0;
|
||||||
|
xspf_file_available = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
httpclient->refbuf->len = PER_CLIENT_REFBUF_SIZE;
|
httpclient->refbuf->len = PER_CLIENT_REFBUF_SIZE;
|
||||||
@ -443,6 +449,19 @@ int fserve_client_create (client_t *httpclient, const char *path)
|
|||||||
free (fullpath);
|
free (fullpath);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (xspf_requested && xspf_file_available == 0)
|
||||||
|
{
|
||||||
|
xmlDocPtr doc;
|
||||||
|
char *reference = strdup (path);
|
||||||
|
char *eol = strrchr (reference, '.');
|
||||||
|
if (eol)
|
||||||
|
*eol = '\0';
|
||||||
|
stats_get_xml (&doc, 0, reference);
|
||||||
|
free (reference);
|
||||||
|
admin_send_response (doc, httpclient, TRANSFORMED, "xspf.xsl");
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* on demand file serving check */
|
/* on demand file serving check */
|
||||||
config = config_get_config();
|
config = config_get_config();
|
||||||
|
32
src/stats.c
32
src/stats.c
@ -878,7 +878,7 @@ void stats_transform_xslt(client_t *client, const char *uri)
|
|||||||
xmlDocPtr doc;
|
xmlDocPtr doc;
|
||||||
char *xslpath = util_get_path_from_normalised_uri (uri);
|
char *xslpath = util_get_path_from_normalised_uri (uri);
|
||||||
|
|
||||||
stats_get_xml(&doc, 0);
|
stats_get_xml(&doc, 0, NULL);
|
||||||
|
|
||||||
xslt_transform(doc, xslpath, client);
|
xslt_transform(doc, xslpath, client);
|
||||||
|
|
||||||
@ -886,7 +886,7 @@ void stats_transform_xslt(client_t *client, const char *uri)
|
|||||||
free (xslpath);
|
free (xslpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stats_get_xml(xmlDocPtr *doc, int show_hidden)
|
void stats_get_xml(xmlDocPtr *doc, int show_hidden, const char *show_mount)
|
||||||
{
|
{
|
||||||
stats_event_t *event;
|
stats_event_t *event;
|
||||||
event_queue_t queue;
|
event_queue_t queue;
|
||||||
@ -906,16 +906,24 @@ void stats_get_xml(xmlDocPtr *doc, int show_hidden)
|
|||||||
{
|
{
|
||||||
if (event->hidden <= show_hidden)
|
if (event->hidden <= show_hidden)
|
||||||
{
|
{
|
||||||
xmlChar *name, *value;
|
do
|
||||||
name = xmlEncodeEntitiesReentrant (*doc, event->name);
|
{
|
||||||
value = xmlEncodeEntitiesReentrant (*doc, event->value);
|
xmlChar *name, *value;
|
||||||
srcnode = node;
|
name = xmlEncodeEntitiesReentrant (*doc, event->name);
|
||||||
if (event->source) {
|
value = xmlEncodeEntitiesReentrant (*doc, event->value);
|
||||||
srcnode = _find_xml_node(event->source, &src_nodes, node);
|
srcnode = node;
|
||||||
}
|
if (event->source)
|
||||||
xmlNewChild(srcnode, NULL, name, value);
|
{
|
||||||
xmlFree (value);
|
if (show_mount && strcmp (event->source, show_mount) != 0)
|
||||||
xmlFree (name);
|
break;
|
||||||
|
srcnode = _find_xml_node(event->source, &src_nodes, node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
srcnode = node;
|
||||||
|
xmlNewChild(srcnode, NULL, name, value);
|
||||||
|
xmlFree (value);
|
||||||
|
xmlFree (name);
|
||||||
|
} while (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
_free_event(event);
|
_free_event(event);
|
||||||
|
@ -90,7 +90,7 @@ void stats_callback (client_t *client, void *notused);
|
|||||||
|
|
||||||
void stats_transform_xslt(client_t *client, const char *uri);
|
void stats_transform_xslt(client_t *client, const char *uri);
|
||||||
void stats_sendxml(client_t *client);
|
void stats_sendxml(client_t *client);
|
||||||
void stats_get_xml(xmlDocPtr *doc, int show_hidden);
|
void stats_get_xml(xmlDocPtr *doc, int show_hidden, const char *show_mount);
|
||||||
char *stats_get_value(char *source, char *name);
|
char *stats_get_value(char *source, char *name);
|
||||||
|
|
||||||
#endif /* __STATS_H__ */
|
#endif /* __STATS_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user