Guy Baconnière
2006-Sep-24  01:55 UTC
[Icecast] Add-on patch to support .pls .asx .ram .qtl listing formats
Hi,
If you have multiple players installed on your PC/Mac .m3u will always
open the last media player who are the default in charge of the extension
and mime m3u.
On your web site you want maybe to force a link to open real media player
or quicktime/itune. You need to create a .pls to force winamp loading the 
streaming because windows media player won't open .pls etc.
If you add a .pls file or other listing formats to icecast root you
will receive incorrect mime type so maybe a futur "todo" can be
customized
mime-types for each extension.
So I have included in attachement a patch to implement all listings formats
available in order to generate a listing with a link to the streaming.
Based on http://www.streamalot.com/playlists/playlist-formats.htm
I hope you can include this patch in your next release and make once again
icecast the best audio streaming server available on the market !
-- thanks for your great product !
Best Regards,
Guy Baconniere
--
Infomaniak Network SA
Guy Baconniere <baco@infomaniak.ch>
Unix System Administrator
Certified Linux Engineer (RHCE, LPIC-2)
Avenue de la Praille 26
1227 Carouge (Geneva)
Switzerland (CH)
Phone +41 (0)22 820 3541
Fax +41 (0)22 820 3546
AS29222 / BACO-RIPE
-------------- next part --------------
--- ChangeLog	2005-11-30 19:17:41.000000000 +0100
+++ ChangeLog	2006-09-22 15:52:11.191506000 +0200
@@ -1,3 +1,15 @@
+2006-09-22 16:38  baco
+
+	* trunk/icecast/src/admin.c, trunk/icecast/src/fserve.c,
+	  trunk/icecast/web/status.xsl, trunk/icecast/web/auth.xsl,
+	  trunk/icecast/admin/listmounts.xsl, trunk/icecast/admin/stats.xsl,
+	  trunk/icecast/admin/listclients.xsl, 
+	  trunk/icecast/doc/icecast2_basicsetup.html,
+	  trunk/icecast/doc/icecast2_listenerauth.html:
+	  add pls,asx,ram,qtl support when user want to launch a specific player
+	  Now support winamp, windows media player, real media player, quicktime
player
+	  listing format.
+
 2005-11-29 03:06  karl
 
 	* trunk/icecast/src/auth_url.c: update for authentication header
--- admin/listclients.xsl	2005-09-27 22:22:18.000000000 +0200
+++ admin/listclients.xsl	2006-09-22 15:07:08.531673000 +0200
@@ -46,7 +46,15 @@
 <a href="/auth.xsl"><img border="0"
src="/key.png"/></a>
 </xsl:when>
 <xsl:otherwise>
-<a href="{@mount}.m3u"><img border="0"
src="/tunein.png"/></a>
+<a href="{@mount}.m3u"><img border="0"
src="/tunein.png" alt="M3U"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.pls"><img border="0"
src="/tunein.png" alt="PLS"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.asx"><img border="0"
src="/tunein.png" alt="ASX"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.ram"><img border="0"
src="/tunein.png" alt="RAM"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.qtl"><img border="0"
src="/tunein.png" alt="QTL"/></a>
 </xsl:otherwise>
 </xsl:choose>
 <xsl:if test="server_name"><xsl:value-of
select="server_name" /> </xsl:if>
--- admin/listmounts.xsl	2005-09-27 22:21:28.000000000 +0200
+++ admin/listmounts.xsl	2006-09-22 15:10:51.112936000 +0200
@@ -44,7 +44,15 @@
 <a href="/auth.xsl"><img border="0"
src="/key.png"/></a>
 </xsl:when>
 <xsl:otherwise>
-<a href="{@mount}.m3u"><img border="0"
src="/tunein.png"/></a>
+<a href="{@mount}.m3u"><img border="0"
src="/tunein.png" alt="M3U"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.pls"><img border="0"
src="/tunein.png" alt="PLS"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.asx"><img border="0"
src="/tunein.png" alt="ASX"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.ram"><img border="0"
src="/tunein.png" alt="RAM"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.qtl"><img border="0"
src="/tunein.png" alt="QTL"/></a>
 </xsl:otherwise>
 </xsl:choose>
 <xsl:if test="server_name"><xsl:value-of
select="server_name" /> </xsl:if>
--- admin/stats.xsl	2005-09-27 22:21:55.000000000 +0200
+++ admin/stats.xsl	2006-09-22 15:08:31.827158000 +0200
@@ -73,7 +73,15 @@
 <a href="/auth.xsl"><img border="0"
src="/key.png"/></a>
 </xsl:when>
 <xsl:otherwise>
-<a href="{@mount}.m3u"><img border="0"
src="/tunein.png"/></a>
+<a href="{@mount}.m3u"><img border="0"
src="/tunein.png" alt="M3U"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.pls"><img border="0"
src="/tunein.png" alt="PLS"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.asx"><img border="0"
src="/tunein.png" alt="ASX"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.ram"><img border="0"
src="/tunein.png" alt="RAM"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.qtl"><img border="0"
src="/tunein.png" alt="QTL"/></a>
 </xsl:otherwise>
 </xsl:choose>
 Mount Point : (<xsl:value-of select="@mount" />)
--- doc/icecast2_basicsetup.html	2005-09-30 01:46:33.000000000 +0200
+++ doc/icecast2_basicsetup.html	2006-09-22 15:04:55.943809000 +0200
@@ -66,7 +66,7 @@
 </p>
 <p>Additionally, you will need to choose a mountpoint and specify this in
the source client.  Icecast does not need to know about each mount point
(although you can configure settings for specific mountpoint - this is covered
under Advanced configuration) there are, however, some points to mention
regarding mountpoints.  All Ogg Vorbis streams should have mountpoints that end
in .ogg (i,e. /mystream.ogg).  This is due to the lazy way most media players
infer the type of stream.  MP3 streams usually do not contain an extension
(/mystream).  Mount points also should not contain any spaces or odd characters
(again due to the lazy way many of the media players are coded).</p>
 <p>Once you have configured your source client, you should be able to
connect it to the icecast server.  Verify that it is connected by hitting the
stats.xml URL that was mentioned above.</p>
-<p>Now that you have the source connnected, listening to the stream
involves simply opening the appropriate following URL in a browser:
http://yourip:port/mounpointyouspecified.m3u.  So, for instance, if you attached
your source client to an icecast server located at 192.168.1.10:8000 with a
mountpoint of /mystream.ogg, then you would open :
http://192.168.1.10:8000/mystream.ogg.m3u.  Note that the .m3u extention will
serve up a link that opens most media players.  Also it is important to note
that m3u need not contain only MP3 stream, it can contain streams of arbitrary
content-type and is used by icecast to serve a playlist that represents your
broadcast to listening clients.  Alternatively you can open up the stream URL
directly within your media player (http://192.168.1.10:8000/mystream.ogg in this
case)</p>
+<p>Now that you have the source connnected, listening to the stream
involves simply opening the appropriate following URL in a browser:
http://yourip:port/mounpointyouspecified.m3u or others listing formats .pls .asx
.ram .qtl.  So, for instance, if you attached your source client to an icecast
server located at 192.168.1.10:8000 with a mountpoint of /mystream.ogg, then you
would open : http://192.168.1.10:8000/mystream.ogg.m3u or any other format like
.ogg.pls .ogg.asx .ogg.ram .ogg.qtl.  Note that all extentions will serve up a
link that opens media players.  Also it is important to note that all listing
formats not contain only MP3 stream, it can contain streams of arbitrary
content-type and is used by icecast to serve a playlist that represents your
broadcast to listening clients.  Alternatively you can open up the stream URL
directly within your media player (http://192.168.1.10:8000/mystream.ogg in this
case)</p>
 <p>
 <br />
 <br />
--- doc/icecast2_listenerauth.html	2005-08-20 01:20:56.000000000 +0200
+++ doc/icecast2_listenerauth.html	2006-09-22 14:58:26.488075000 +0200
@@ -61,7 +61,7 @@
 <h3>Finishing it all off</h3>
 <p>Ok, so you've created your users, and you have everything setup
properly, how do your users login ?  Well, we've provided a simple login
form that you can use for this purpose.  This page (http://server:port/auth.xsl)
will bring up a form that users can use to enter their username and
password.</p>
 <img src="listener_auth3.jpg" alt="Screenshot of
http://server:port/auth.xsl" />
-<p>This page will serve a m3u with the username and password and in most
cases should open the correct media player and begin playing your
stream</p>
+<p>This page will serve a m3u, pls, asx, ram, qtl with the username and
password and in most cases should open the correct media player and begin
playing your stream</p>
 <br />
 <br />
 <h2>URL</h2>
--- src/admin.c	2005-09-13 00:50:48.000000000 +0200
+++ src/admin.c	2006-09-22 17:05:53.541833000 +0200
@@ -79,6 +79,10 @@
 
 /* Admin commands requiring no auth */
 #define COMMAND_BUILDM3U                    501
+#define COMMAND_BUILDPLS                    502
+#define COMMAND_BUILDASX                    503
+#define COMMAND_BUILDRAM                    504
+#define COMMAND_BUILDQTL                    505
 
 #define FALLBACK_RAW_REQUEST "fallbacks"
 #define FALLBACK_TRANSFORMED_REQUEST "fallbacks.xsl"
@@ -108,6 +112,10 @@
 #define DEFAULT_RAW_REQUEST ""
 #define DEFAULT_TRANSFORMED_REQUEST ""
 #define BUILDM3U_RAW_REQUEST "buildm3u"
+#define BUILDPLS_RAW_REQUEST "buildpls"
+#define BUILDASX_RAW_REQUEST "buildasx"
+#define BUILDRAM_RAW_REQUEST "buildram"
+#define BUILDQTL_RAW_REQUEST "buildqtl"
 
 #define RAW         1
 #define TRANSFORMED 2
@@ -165,6 +173,14 @@
         return COMMAND_TRANSFORMED_UPDATEMETADATA;
     else if(!strcmp(command, BUILDM3U_RAW_REQUEST))
         return COMMAND_BUILDM3U;
+    else if(!strcmp(command, BUILDPLS_RAW_REQUEST))
+        return COMMAND_BUILDPLS;
+    else if(!strcmp(command, BUILDASX_RAW_REQUEST))
+        return COMMAND_BUILDASX;
+    else if(!strcmp(command, BUILDRAM_RAW_REQUEST))
+        return COMMAND_BUILDRAM;
+    else if(!strcmp(command, BUILDQTL_RAW_REQUEST))
+        return COMMAND_BUILDQTL;
     else if(!strcmp(command, DEFAULT_TRANSFORMED_REQUEST))
         return COMMAND_TRANSFORMED_STATS;
     else if(!strcmp(command, DEFAULT_RAW_REQUEST))
@@ -188,6 +204,14 @@
         int response);
 static void command_buildm3u(client_t *client, source_t *source,
         int response);
+static void command_buildpls(client_t *client, source_t *source,
+        int response);
+static void command_buildasx(client_t *client, source_t *source,
+        int response);
+static void command_buildram(client_t *client, source_t *source,
+        int response);
+static void command_buildqtl(client_t *client, source_t *source,
+        int response);
 static void command_kill_source(client_t *client, source_t *source,
         int response);
 static void command_updatemetadata(client_t *client, source_t *source,
@@ -360,7 +384,9 @@
     if(mount != NULL) {
         source_t *source;
 
-        if (command == COMMAND_BUILDM3U) {
+        if ( (command == COMMAND_BUILDM3U) || (command == COMMAND_BUILDPLS)
+          || (command == COMMAND_BUILDASX) || (command == COMMAND_BUILDRAM)
+          || (command == COMMAND_BUILDQTL) ) {
             noauth = 1;
         }
         /* This is a mount request, handle it as such */
@@ -528,6 +554,18 @@
         case COMMAND_BUILDM3U:
             command_buildm3u(client, source, RAW);
             break;
+        case COMMAND_BUILDPLS:
+            command_buildpls(client, source, RAW);
+            break;
+        case COMMAND_BUILDASX:
+            command_buildasx(client, source, RAW);
+            break;
+        case COMMAND_BUILDRAM:
+            command_buildram(client, source, RAW);
+            break;
+        case COMMAND_BUILDQTL:
+            command_buildqtl(client, source, RAW);
+            break;
         default:
             WARN0("Mount request not recognised");
             client_send_400(client, "Mount request unknown");
@@ -703,6 +741,138 @@
 }
 
 
+static void command_buildpls(client_t *client, source_t *source,
+    int response)
+{
+    char *username = NULL;
+    char *password = NULL;
+    ice_config_t *config;
+
+    COMMAND_REQUIRE(client, "username", username);
+    COMMAND_REQUIRE(client, "password", password);
+
+    client->respcode = 200;
+    config = config_get_config();
+    snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE,
+        "HTTP/1.0 200 OK\r\n"
+        "Content-Type: audio/x-scpls\r\n"
+        "Content-Disposition = attachment;
filename=listen.pls\r\n\r\n"
+        "[playlist]\r\n"
+        "File1=http://%s:%s@%s:%d%s\r\n"
+        "Title1=\r\n"
+        "Length1=-1\r\n"
+        "NumberOfEntries=1\r\n"
+        "Version=2\r\n",
+        username,
+        password,
+        config->hostname,
+        config->port,
+        source->mount
+    );
+    config_release_config();
+
+    client->refbuf->len = strlen (client->refbuf->data);
+    fserve_add_client (client, NULL);
+}
+
+
+static void command_buildasx(client_t *client, source_t *source,
+    int response)
+{
+    char *username = NULL;
+    char *password = NULL;
+    ice_config_t *config;
+
+    COMMAND_REQUIRE(client, "username", username);
+    COMMAND_REQUIRE(client, "password", password);
+
+    client->respcode = 200;
+    config = config_get_config();
+    snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE,
+        "HTTP/1.0 200 OK\r\n"
+        "Content-Type: video/x-ms-asf\r\n"
+        "Content-Disposition = attachment;
filename=listen.asx\r\n\r\n"
+        "<ASX version=\"3.0\">\r\n"
+        "<TITLE></TITLE>\r\n"
+        "<ENTRY>\r\n"
+        "<TITLE></TITLE>\r\n"
+        "<REF HREF=\"http://%s:%s@%s:%d%s\" />\r\n"
+        "</ENTRY>\r\n"
+        "</ASX>\r\n",
+        username,
+        password,
+        config->hostname,
+        config->port,
+        source->mount
+    );
+    config_release_config();
+
+    client->refbuf->len = strlen (client->refbuf->data);
+    fserve_add_client (client, NULL);
+}
+
+
+static void command_buildram(client_t *client, source_t *source,
+    int response)
+{
+    char *username = NULL;
+    char *password = NULL;
+    ice_config_t *config;
+
+    COMMAND_REQUIRE(client, "username", username);
+    COMMAND_REQUIRE(client, "password", password);
+
+    client->respcode = 200;
+    config = config_get_config();
+    snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE,
+        "HTTP/1.0 200 OK\r\n"
+        "Content-Type: audio/x-pn-realaudio\r\n"
+        "Content-Disposition = attachment;
filename=listen.ram\r\n\r\n"
+        "http://%s:%s@%s:%d%s\r\n",
+        username,
+        password,
+        config->hostname,
+        config->port,
+        source->mount
+    );
+    config_release_config();
+
+    client->refbuf->len = strlen (client->refbuf->data);
+    fserve_add_client (client, NULL);
+}
+
+
+static void command_buildqtl(client_t *client, source_t *source,
+    int response)
+{
+    char *username = NULL;
+    char *password = NULL;
+    ice_config_t *config;
+
+    COMMAND_REQUIRE(client, "username", username);
+    COMMAND_REQUIRE(client, "password", password);
+
+    client->respcode = 200;
+    config = config_get_config();
+    snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE,
+        "HTTP/1.0 200 OK\r\n"
+        "Content-Type: application/x-quicktimeplayer\r\n"
+        "Content-Disposition = attachment;
filename=listen.qtl\r\n\r\n"
+        "<?quicktime
type=\"application/x-quicktime-media-link\"?>\r\n"
+        "<embed autoplay=\"true\" moviename=\"\"
src=\"http://%s:%s@%s:%d%s.pls\" />\r\n",
+        username,
+        password,
+        config->hostname,
+        config->port,
+        source->mount
+    );
+    config_release_config();
+
+    client->refbuf->len = strlen (client->refbuf->data);
+    fserve_add_client (client, NULL);
+}
+
+
 static void command_manageauth(client_t *client, source_t *source,
     int response)
 {
--- src/fserve.c	2005-09-08 16:03:51.000000000 +0200
+++ src/fserve.c	2006-09-22 15:51:25.426800000 +0200
@@ -340,6 +340,14 @@
             return "image/png";
         else if(!strcmp(ext, "m3u"))
             return "audio/x-mpegurl";
+        else if(!strcmp(ext, "pls"))
+            return "audio/x-scpls";
+        else if(!strcmp(ext, "asx"))
+            return "video/x-ms-asf";
+        else if(!strcmp(ext, "ram"))
+            return "audio/x-pn-realaudio";
+        else if(!strcmp(ext, "qtl"))
+            return "application/x-quicktimeplayer";
         else
             return "application/octet-stream";
     }
@@ -376,6 +384,10 @@
     int ret = 0;
     char *fullpath;
     int m3u_requested = 0, m3u_file_available = 1;
+    int pls_requested = 0, pls_file_available = 1;
+    int asx_requested = 0, asx_file_available = 1;
+    int ram_requested = 0, ram_file_available = 1;
+    int qtl_requested = 0, qtl_file_available = 1;
     ice_config_t *config;
     FILE *file;
 
@@ -384,12 +396,20 @@
 
     if (strcmp (util_get_extension (fullpath), "m3u") == 0)
         m3u_requested = 1;
+    if (strcmp (util_get_extension (fullpath), "pls") == 0)
+        pls_requested = 1;
+    if (strcmp (util_get_extension (fullpath), "asx") == 0)
+        asx_requested = 1;
+    if (strcmp (util_get_extension (fullpath), "ram") == 0)
+        ram_requested = 1;
+    if (strcmp (util_get_extension (fullpath), "qtl") == 0)
+        qtl_requested = 1;
 
     /* check for the actual file */
     if (stat (fullpath, &file_buf) != 0)
     {
-        /* the m3u can be generated, but send an m3u file if available */
-        if (m3u_requested == 0)
+        /* an listing can be generated, but send an listing file if available
*/
+        if ( (m3u_requested == 0) && (pls_requested == 0) &&
(asx_requested == 0) && (ram_requested == 0) && (qtl_requested
== 0) )
         {
             WARN2 ("req for file \"%s\" %s", fullpath,
strerror (errno));
             client_send_404 (httpclient, "The file you requested could not
be found");
@@ -397,6 +417,10 @@
             return -1;
         }
         m3u_file_available = 0;
+        pls_file_available = 0;
+        asx_file_available = 0;
+        ram_file_available = 0;
+        qtl_file_available = 0;
     }
 
     httpclient->refbuf->len = PER_CLIENT_REFBUF_SIZE;
@@ -443,6 +467,200 @@
         free (fullpath);
         return 0;
     }
+	if (pls_requested && pls_file_available == 0)
+    {
+        char *host = httpp_getvar (httpclient->parser, "host");
+        char *sourceuri = strdup (path);
+        char *dot = strrchr(sourceuri, '.');
+
+        /* at least a couple of players (fb2k/winamp) are reported to send a 
+         * host header but without the port number. So if we are missing the
+         * port then lets treat it as if no host line was sent */
+        if (host && strchr (host, ':') == NULL)
+            host = NULL;
+
+        *dot = 0;
+        httpclient->respcode = 200;
+        if (host == NULL)
+        {
+            config = config_get_config();
+            snprintf (httpclient->refbuf->data, BUFSIZE,
+                    "HTTP/1.0 200 OK\r\n"
+                    "Content-Type: audio/x-scpls\r\n\r\n"
+                    "[playlist]\r\n"
+                    "File1=http://%s:%d%s\r\n"
+                    "Title1=\r\n"
+                    "Length1=-1\r\n"
+                    "NumberOfEntries=1\r\n"
+                    "Version=2\r\n",
+                    config->hostname, config->port,
+                    sourceuri
+                    );
+            config_release_config();
+        }
+        else
+        {
+            snprintf (httpclient->refbuf->data, BUFSIZE,
+                    "HTTP/1.0 200 OK\r\n"
+                    "Content-Type: audio/x-scpls\r\n\r\n"
+                    "[playlist]\r\n"
+                    "File1=http://%s%s\r\n"
+                    "Title1=\r\n"
+                    "Length1=-1\r\n"
+                    "NumberOfEntries=1\r\n"
+                    "Version=2\r\n",
+                    host, 
+                    sourceuri
+                    );
+        }
+        httpclient->refbuf->len = strlen
(httpclient->refbuf->data);
+        fserve_add_client (httpclient, NULL);
+        free (sourceuri);
+        free (fullpath);
+        return 0;
+    }
+	if (asx_requested && asx_file_available == 0)
+    {
+        char *host = httpp_getvar (httpclient->parser, "host");
+        char *sourceuri = strdup (path);
+        char *dot = strrchr(sourceuri, '.');
+
+        /* at least a couple of players (fb2k/winamp) are reported to send a 
+         * host header but without the port number. So if we are missing the
+         * port then lets treat it as if no host line was sent */
+        if (host && strchr (host, ':') == NULL)
+            host = NULL;
+
+        *dot = 0;
+        httpclient->respcode = 200;
+        if (host == NULL)
+        {
+            config = config_get_config();
+            snprintf (httpclient->refbuf->data, BUFSIZE,
+                    "HTTP/1.0 200 OK\r\n"
+                    "Content-Type: video/x-ms-asf\r\n\r\n"
+                    "<ASX version=\"3.0\">\r\n"
+                    "<TITLE></TITLE>\r\n"
+                    "<ENTRY>\r\n"
+                    "<TITLE></TITLE>\r\n"
+                    "<REF HREF=\"http://%s:%d%s\"
/>\r\n"
+                    "</ENTRY>\r\n"
+                    "</ASX>\r\n",
+                    config->hostname, config->port,
+                    sourceuri
+                    );
+            config_release_config();
+        }
+        else
+        {
+            snprintf (httpclient->refbuf->data, BUFSIZE,
+                    "HTTP/1.0 200 OK\r\n"
+                    "Content-Type: video/x-ms-asf\r\n\r\n"
+                    "<ASX version=\"3.0\">\r\n"
+                    "<TITLE></TITLE>\r\n"
+                    "<ENTRY>\r\n"
+                    "<TITLE></TITLE>\r\n"
+                    "<REF HREF=\"http://%s%s\"
/>\r\n"
+                    "</ENTRY>\r\n"
+                    "</ASX>\r\n",
+                    host, 
+                    sourceuri
+                    );
+        }
+        httpclient->refbuf->len = strlen
(httpclient->refbuf->data);
+        fserve_add_client (httpclient, NULL);
+        free (sourceuri);
+        free (fullpath);
+        return 0;
+    }
+    if (ram_requested && ram_file_available == 0)
+    {
+        char *host = httpp_getvar (httpclient->parser, "host");
+        char *sourceuri = strdup (path);
+        char *dot = strrchr(sourceuri, '.');
+
+        /* at least a couple of players (fb2k/winamp) are reported to send a 
+         * host header but without the port number. So if we are missing the
+         * port then lets treat it as if no host line was sent */
+        if (host && strchr (host, ':') == NULL)
+            host = NULL;
+
+        *dot = 0;
+        httpclient->respcode = 200;
+        if (host == NULL)
+        {
+            config = config_get_config();
+            snprintf (httpclient->refbuf->data, BUFSIZE,
+                    "HTTP/1.0 200 OK\r\n"
+                    "Content-Type: audio/x-pn-realaudio\r\n\r\n"
+                    "http://%s:%d%s\r\n", 
+                    config->hostname, config->port,
+                    sourceuri
+                    );
+            config_release_config();
+        }
+        else
+        {
+            snprintf (httpclient->refbuf->data, BUFSIZE,
+                    "HTTP/1.0 200 OK\r\n"
+                    "Content-Type: audio/x-pn-realaudio\r\n\r\n"
+                    "http://%s%s\r\n", 
+                    host, 
+                    sourceuri
+                    );
+        }
+        httpclient->refbuf->len = strlen
(httpclient->refbuf->data);
+        fserve_add_client (httpclient, NULL);
+        free (sourceuri);
+        free (fullpath);
+        return 0;
+    }
+	if (qtl_requested && qtl_file_available == 0)
+    {
+        char *host = httpp_getvar (httpclient->parser, "host");
+        char *sourceuri = strdup (path);
+        char *dot = strrchr(sourceuri, '.');
+
+        /* at least a couple of players (fb2k/winamp) are reported to send a 
+         * host header but without the port number. So if we are missing the
+         * port then lets treat it as if no host line was sent */
+        if (host && strchr (host, ':') == NULL)
+            host = NULL;
+
+        *dot = 0;
+        httpclient->respcode = 200;
+        if (host == NULL)
+        {
+            config = config_get_config();
+            snprintf (httpclient->refbuf->data, BUFSIZE,
+                    "HTTP/1.0 200 OK\r\n"
+                    "Content-Type:
application/x-quicktimeplayer\r\n\r\n"
+                    "<?xml version=\"1.0\"?>\r\n"
+                    "<?quicktime
type=\"application/x-quicktime-media-link\"?>\r\n"
+                    "<embed autoplay=\"true\"
moviename=\"\" src=\"http://%s:%d%s.pls\" />\r\n",
+                    config->hostname, config->port,
+                    sourceuri
+                    );
+            config_release_config();
+        }
+        else
+        {
+            snprintf (httpclient->refbuf->data, BUFSIZE,
+                    "HTTP/1.0 200 OK\r\n"
+                    "Content-Type:
application/x-quicktimeplayer\r\n\r\n"
+                    "<?xml version=\"1.0\"?>\r\n"
+                    "<?quicktime
type=\"application/x-quicktime-media-link\"?>\r\n"
+                    "<embed autoplay=\"true\"
moviename=\"\" src=\"http://%s%s.pls\" />\r\n",
+                    host, 
+                    sourceuri
+                    );
+        }
+        httpclient->refbuf->len = strlen
(httpclient->refbuf->data);
+        fserve_add_client (httpclient, NULL);
+        free (sourceuri);
+        free (fullpath);
+        return 0;
+    }
 
     /* on demand file serving check */
     config = config_get_config();
--- web/auth.xsl	2005-08-20 01:20:56.000000000 +0200
+++ web/auth.xsl	2006-09-22 15:12:54.234812000 +0200
@@ -31,6 +31,42 @@
 </table>
 <input type="hidden" name="mount"
value="{@mount}"/>
 </form>
+<br></br>
+<form method="GET" action="/admin/buildpls">
+<table border="0" cellpadding="4">
+<tr><td>Username : <input type="text"
name="username"/></td></tr>
+<tr><td>Password : <input type="password"
name="password"/></td></tr>
+<tr><td><input type="Submit"
value="Login"/></td></tr>
+</table>
+<input type="hidden" name="mount"
value="{@mount}"/>
+</form>
+<br></br>
+<form method="GET" action="/admin/buildasx">
+<table border="0" cellpadding="4">
+<tr><td>Username : <input type="text"
name="username"/></td></tr>
+<tr><td>Password : <input type="password"
name="password"/></td></tr>
+<tr><td><input type="Submit"
value="Login"/></td></tr>
+</table>
+<input type="hidden" name="mount"
value="{@mount}"/>
+</form>
+<br></br>
+<form method="GET" action="/admin/buildram">
+<table border="0" cellpadding="4">
+<tr><td>Username : <input type="text"
name="username"/></td></tr>
+<tr><td>Password : <input type="password"
name="password"/></td></tr>
+<tr><td><input type="Submit"
value="Login"/></td></tr>
+</table>
+<input type="hidden" name="mount"
value="{@mount}"/>
+</form>
+<br></br>
+<form method="GET" action="/admin/buildqtl">
+<table border="0" cellpadding="4">
+<tr><td>Username : <input type="text"
name="username"/></td></tr>
+<tr><td>Password : <input type="password"
name="password"/></td></tr>
+<tr><td><input type="Submit"
value="Login"/></td></tr>
+</table>
+<input type="hidden" name="mount"
value="{@mount}"/>
+</form>
 </xsl:if>
 </xsl:when>
 <xsl:otherwise>
--- web/status.xsl	2005-09-27 22:17:53.000000000 +0200
+++ web/status.xsl	2006-09-22 15:17:56.286132000 +0200
@@ -44,7 +44,15 @@
 <a href="/auth.xsl"><img border="0"
src="/key.png"/></a>
 </xsl:when>
 <xsl:otherwise>
-<a href="{@mount}.m3u"><img border="0"
src="/tunein.png"/></a>
+<a href="{@mount}.m3u"><img border="0"
src="/tunein.png" alt="M3U"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.pls"><img border="0"
src="/tunein.png" alt="PLS"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.asx"><img border="0"
src="/tunein.png" alt="ASX"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.ram"><img border="0"
src="/tunein.png" alt="RAM"/></a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.qtl"><img border="0"
src="/tunein.png" alt="QTL"/></a>
 </xsl:otherwise>
 </xsl:choose>
 Mount Point : (<xsl:value-of select="@mount" />) : 
@@ -53,7 +61,17 @@
 <a href="/auth.xsl">Click to Listen</a>
 </xsl:when>
 <xsl:otherwise>
-<a href="{@mount}.m3u">Click to Listen</a>
+Click to Listen :
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.m3u">M3U</a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.pls">PLS</a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.asx">ASX</a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.ram">RAM</a>
+<xsl:text
disable-output-escaping="yes">&</xsl:text>nbsp;
+<a href="{@mount}.qtl">QTL</a>
 </xsl:otherwise>
 </xsl:choose>
 </h3>
Leo Currie
2006-Sep-25  04:51 UTC
[Icecast] Add-on patch to support .pls .asx .ram .qtl listing formats
On 24/09/06, Guy Baconni?re <baco@infomaniak.ch> wrote:> Hi, > > If you have multiple players installed on your PC/Mac .m3u will always > open the last media player who are the default in charge of the extension > and mime m3u. > > On your web site you want maybe to force a link to open real media player > or quicktime/itune. You need to create a .pls to force winamp loading the > streaming because windows media player won't open .pls etc. > > If you add a .pls file or other listing formats to icecast root you > will receive incorrect mime type so maybe a futur "todo" can be customized > mime-types for each extension. > > So I have included in attachement a patch to implement all listings formats > available in order to generate a listing with a link to the streaming. > Based on http://www.streamalot.com/playlists/playlist-formats.htm > > I hope you can include this patch in your next release and make once again > icecast the best audio streaming server available on the market ! > -- thanks for your great product ! >I agree this is a useful feature. It would be great if the .asx playlist could contain the correct stream title information. Is this possible? Leo