⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shoutcast.c

📁 linux下网络收音机的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2002, 2003, 2004 Jean-Yves Lefort * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include <string.h>#include <stdlib.h>#include <glib/gi18n.h>#include "streamtuner.h"/*** cpp *********************************************************************/#define SHOUTCAST_ROOT		"http://www.shoutcast.com/"#define MAX_STREAMS_PER_PAGE	100 /* enforced by SHOUTcast */#define PARSE_ERROR		st_handler_notice(shoutcast_handler, _("parse error at %s"), G_STRLOC)#define CONFIG_STREAM_LIMIT_ENABLED	"stream-limit-enabled"#define CONFIG_STREAM_LIMIT		"stream-limit"#define MIN_STREAM_LIMIT	0#define MAX_STREAM_LIMIT	9999/*** type definitions ********************************************************/typedef struct{  STStream	stream;  char		*genre;  char		*description;  char		*now_playing;  int		listeners;  int		max;  int		bitrate;  char		*url_postfix;  char		*homepage;  /*   * url_list may be set after the stream has entered streamtuner, so   * we need to protect it.   */  GSList	*url_list;  GMutex	*url_list_mutex;} SHOUTcastStream;enum {  FIELD_GENRE,  FIELD_DESCRIPTION,  FIELD_NOW_PLAYING,  FIELD_LISTENERS,  FIELD_MAX,  FIELD_BITRATE,  FIELD_URL_POSTFIX,  FIELD_HOMEPAGE,  FIELD_URL_LIST};typedef struct{  GNode			**categories;  GList			**streams;  int			page;  int			npages;  GNode			*parent_node;  SHOUTcastStream	*stream;} ReloadInfo;/*** variable declarations ***************************************************/static STPlugin *shoutcast_plugin = NULL;static STHandler *shoutcast_handler = NULL;static GtkWidget *preferences_stream_limit_check;static GtkWidget *preferences_stream_limit_spin;static GtkWidget *preferences_stream_limit_label;/*** function declarations ***************************************************/static gboolean	reload_cb	(STCategory	*category,				 GNode		**categories,				 GList		**streams,				 gpointer	data,				 GError		**err);static void	reload_body_cb		(const char	*line,					 gpointer	data);static SHOUTcastStream *stream_new_cb (gpointer data);static void stream_field_get_cb (SHOUTcastStream	*stream,				 STHandlerField		*field,				 GValue			*value,				 gpointer		data);static void stream_field_set_cb (SHOUTcastStream	*stream,				 STHandlerField		*field,				 const GValue		*value,				 gpointer		data);static void stream_stock_field_get_cb (SHOUTcastStream		*stream,				       STHandlerStockField	stock_field,				       GValue			*value,				       gpointer			data);static void stream_free_cb	(SHOUTcastStream	*stream,				 gpointer		data);static void stream_get_url_list	(SHOUTcastStream	*stream,				 GValue			*value);static gboolean stream_resolve		(SHOUTcastStream	*stream,					 GError			**err);static gboolean stream_resolve_cb	(SHOUTcastStream	*stream,					 gpointer		data,					 GError			**err);static gboolean	stream_tune_in_cb	(SHOUTcastStream	*stream,					 gpointer		data,					 GError			**err);static gboolean	stream_record_cb	(SHOUTcastStream	*stream,					 gpointer		data,					 GError			**err);static gboolean	stream_browse_cb	(SHOUTcastStream	*stream,					 gpointer		data,					 GError			**err);static int	search_url_cb		(STCategory		*category);static GtkWidget *	preferences_widget_new_cb	(gpointer        data);static void		preferences_update_sensitivity	(void);static void		preferences_stream_limit_toggled_h        (GtkToggleButton *button,								   gpointer        user_data);static void		preferences_stream_limit_changed_h        (GtkSpinButton   *spin,								   gpointer        user_data);static void	init_handler		(void);static gboolean check_api_version	(GError **err);/*** implementation **********************************************************/static SHOUTcastStream *stream_new_cb (gpointer data){  SHOUTcastStream *stream;  stream = g_new0(SHOUTcastStream, 1);  stream->url_list_mutex = g_mutex_new();  return stream;}static voidstream_field_get_cb (SHOUTcastStream *stream,		     STHandlerField *field,		     GValue *value,		     gpointer data){  switch (field->id)    {    case FIELD_GENRE:      g_value_set_string(value, stream->genre);      break;    case FIELD_DESCRIPTION:      g_value_set_string(value, stream->description);      break;    case FIELD_NOW_PLAYING:      g_value_set_string(value, stream->now_playing);      break;    case FIELD_LISTENERS:      g_value_set_int(value, stream->listeners);      break;    case FIELD_MAX:      g_value_set_int(value, stream->max);      break;    case FIELD_BITRATE:      g_value_set_int(value, stream->bitrate);      break;    case FIELD_URL_POSTFIX:      g_value_set_string(value, stream->url_postfix);      break;    case FIELD_HOMEPAGE:      g_value_set_string(value, stream->homepage);      break;    case FIELD_URL_LIST:      stream_get_url_list(stream, value);      break;          default:      g_return_if_reached();    }}static voidstream_field_set_cb (SHOUTcastStream *stream,		     STHandlerField *field,		     const GValue *value,		     gpointer data){  switch (field->id)    {    case FIELD_GENRE:      stream->genre = g_value_dup_string(value);      break;    case FIELD_DESCRIPTION:      stream->description = g_value_dup_string(value);      break;    case FIELD_NOW_PLAYING:      stream->now_playing = g_value_dup_string(value);      break;    case FIELD_LISTENERS:      stream->listeners = g_value_get_int(value);      break;    case FIELD_MAX:      stream->max = g_value_get_int(value);      break;    case FIELD_BITRATE:      stream->bitrate = g_value_get_int(value);      break;    case FIELD_URL_POSTFIX:      stream->url_postfix = g_value_dup_string(value);      break;    case FIELD_HOMEPAGE:      stream->homepage = g_value_dup_string(value);      break;    case FIELD_URL_LIST:      {	GValueArray *value_array;	int i;	value_array = g_value_get_boxed(value);	for (i = 0; i < value_array->n_values; i++)	  {	    GValue *url_value = g_value_array_get_nth(value_array, i);	    stream->url_list = g_slist_append(stream->url_list, g_value_dup_string(url_value));	  }	break;      }          default:      g_return_if_reached();    }}static voidstream_stock_field_get_cb (SHOUTcastStream *stream,			   STHandlerStockField stock_field,			   GValue *value,			   gpointer data){  switch (stock_field)    {    case ST_HANDLER_STOCK_FIELD_NAME:      g_value_set_string(value, stream->description);      break;    case ST_HANDLER_STOCK_FIELD_GENRE:      g_value_set_string(value, stream->genre);      break;    case ST_HANDLER_STOCK_FIELD_DESCRIPTION:      /* nop */      break;    case ST_HANDLER_STOCK_FIELD_HOMEPAGE:      g_value_set_string(value, stream->homepage);      break;          case ST_HANDLER_STOCK_FIELD_URI_LIST:      stream_get_url_list(stream, value);      break;    }}static voidstream_free_cb (SHOUTcastStream *stream, gpointer data){  GSList *l;  g_free(stream->genre);  g_free(stream->description);  g_free(stream->now_playing);  g_free(stream->url_postfix);  g_free(stream->homepage);  for (l = stream->url_list; l; l = l->next)    g_free(l->data);  g_slist_free(stream->url_list);  g_mutex_free(stream->url_list_mutex);  st_stream_free((STStream *) stream);}static voidstream_get_url_list (SHOUTcastStream *stream, GValue *value){  GValueArray *value_array;  GSList *l;    g_return_if_fail(stream != NULL);  g_return_if_fail(value != NULL);  value_array = g_value_array_new(0);  g_mutex_lock(stream->url_list_mutex);  for (l = stream->url_list; l; l = l->next)    {      GValue url_value = { 0, };            g_value_init(&url_value, G_TYPE_STRING);      g_value_set_string(&url_value, l->data);      g_value_array_append(value_array, &url_value);      g_value_unset(&url_value);    }  g_mutex_unlock(stream->url_list_mutex);    g_value_take_boxed(value, value_array);}static gbooleanstream_resolve (SHOUTcastStream *stream, GError **err){  gboolean already_resolved;  STTransferSession *session;  char *url;  char *playlist;  gboolean status;  g_return_val_if_fail(stream != NULL, FALSE);  g_mutex_lock(stream->url_list_mutex);  already_resolved = stream->url_list != NULL;  g_mutex_unlock(stream->url_list_mutex);  if (already_resolved)    return TRUE;		/* already resolved */  url = g_strconcat(SHOUTCAST_ROOT, stream->url_postfix, NULL);  session = st_transfer_session_new();  status = st_transfer_session_get(session, url, ST_TRANSFER_UTF8, NULL, &playlist, err);  st_transfer_session_free(session);  g_free(url);  if (status)    {      gboolean empty;      g_mutex_lock(stream->url_list_mutex);      stream->url_list = st_pls_parse(playlist);      empty = stream->url_list == NULL;      g_mutex_unlock(stream->url_list_mutex);      g_free(playlist);      if (empty)	{	  g_set_error(err, 0, 0, _("stream is empty"));	  return FALSE;	}    }    return status;}static gbooleanstream_resolve_cb (SHOUTcastStream *stream, gpointer data, GError **err){  return stream_resolve(stream, err);}static gbooleanstream_tune_in_cb (SHOUTcastStream *stream, gpointer data, GError **err){  char *m3uname;  gboolean status;    if (! stream_resolve(stream, err))    return FALSE;  g_mutex_lock(stream->url_list_mutex);  m3uname = st_m3u_mktemp("streamtuner.shoutcast.XXXXXX", stream->url_list, err);  g_mutex_unlock(stream->url_list_mutex);  if (! m3uname)    return FALSE;    status = st_action_run("play-m3u", m3uname, err);  g_free(m3uname);  return status;}static gbooleanstream_record_cb (SHOUTcastStream *stream, gpointer data, GError **err){  gboolean status;  if (! stream_resolve(stream, err))    return FALSE;  g_mutex_lock(stream->url_list_mutex);  status = st_action_run("record-stream", stream->url_list->data, err);  g_mutex_unlock(stream->url_list_mutex);  return status;}static gbooleanstream_browse_cb (SHOUTcastStream *stream, gpointer data, GError **err){  if (! stream->homepage) /* older versions of the plugin didn't have this field */    {      g_set_error(err, 0, 0, _("the stream is too old, please reload"));      return FALSE;    }  return st_action_run("view-web", stream->homepage, err);}static gbooleanreload_cb (STCategory *category,	   GNode **categories,	   GList **streams,	   gpointer data,	   GError **err){  ReloadInfo info;  STTransferSession *session;  gboolean status;  int stream_limit;  int requested_streams = 0;  int received_streams = 0;  g_return_val_if_fail(category != NULL, FALSE);  g_return_val_if_fail(category->url_postfix != NULL, FALSE);  *categories = g_node_new(NULL);  *streams = NULL;  info.categories = categories;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -