📄 shoutcast.c
字号:
info.streams = streams; session = st_transfer_session_new(); stream_limit = st_handler_config_get_boolean(shoutcast_handler, CONFIG_STREAM_LIMIT_ENABLED) ? st_handler_config_get_int(shoutcast_handler, CONFIG_STREAM_LIMIT) : (! strcmp(category->name, "__main") ? 500 : -1); /* [1] */ /* * [1] The main category contains all the SHOUTcast streams (a lot), * so we just load the first 500. */ do { char *url; int rows; if (requested_streams != 0 && st_is_aborted()) { status = FALSE; break; } rows = stream_limit == -1 ? MAX_STREAMS_PER_PAGE : MIN(stream_limit - received_streams, MAX_STREAMS_PER_PAGE); url = g_strdup_printf(SHOUTCAST_ROOT "directory/?numresult=%i&startat=%i%s", rows, requested_streams, category->url_postfix); requested_streams += rows; info.page = 0; info.npages = 0; info.parent_node = NULL; info.stream = NULL; status = st_transfer_session_get_by_line(session, url, ST_TRANSFER_UTF8 | ST_TRANSFER_PARSE_HTTP_CHARSET | ST_TRANSFER_PARSE_HTML_CHARSET, NULL, NULL, reload_body_cb, &info, err); g_free(url); received_streams = g_list_length(*streams); if (info.stream) { stream_free_cb(info.stream, NULL); if (status) /* only display warning if the transfer was otherwise correct */ PARSE_ERROR; } } while (status && info.page > 0 && info.page < info.npages && (stream_limit == -1 || received_streams < stream_limit)); st_transfer_session_free(session); return status;}static voidreload_body_cb (const char *line, gpointer data){ ReloadInfo *info = data; char *s1, *s2, *s3, *s4, *s5; char *word1, *word2; if ((s1 = strstr(line, "sbin/shoutcast-playlist.pls")) && (s2 = st_strstr_span(s1, "filename.pls"))) { if (info->stream) /* a malformed stream remains, free it */ { PARSE_ERROR; stream_free_cb(info->stream, NULL); } info->stream = stream_new_cb(NULL); info->stream->url_postfix = st_sgml_ref_expand_len(s1, s2 - s1); } else if (info->page < 2 && (((s1 = st_str_has_prefix_span(line, "\t<OPTION VALUE=\"")) || (s1 = st_str_has_prefix_span(line, "\t\t<OPTION VALUE=\""))) && (s2 = strstr(s1, "\">")))) { STCategory *category; GNode *node; char *escaped; category = st_category_new(); category->name = st_sgml_ref_expand_len(s1, s2 - s1); category->label = st_sgml_ref_expand(s2 + 2); escaped = st_transfer_escape(category->name); category->url_postfix = g_strconcat("&sgenre=", escaped, NULL); g_free(escaped); node = g_node_new(category); if (g_str_has_prefix(category->label, " - ")) { if (info->parent_node) { char *new_label; new_label = g_strdup(category->label + 3); g_free(category->label); category->label = new_label; g_node_append(info->parent_node, node); } else { PARSE_ERROR; st_category_free(category); g_node_destroy(node); } } else { g_node_append(*(info->categories), node); info->parent_node = node; } } else if ((s1 = st_strstr_span(line, "<b>[")) && (s2 = strstr(s1, "]</font>")) && (s3 = st_strstr_span(s2, "href=\"")) && (s4 = strstr(s3, "\">")) && (s5 = strstr(s4, "</a>"))) { if (info->stream) { g_free(info->stream->genre); info->stream->genre = st_sgml_ref_expand_len(s1, s2 - s1); g_free(info->stream->homepage); info->stream->homepage = st_sgml_ref_expand_len(s3, s4 - s3); g_free(info->stream->description); s4 += 2; info->stream->description = st_sgml_ref_expand_len(s4, s5 - s4); } else PARSE_ERROR; } else if ((s1 = st_strstr_span(line, "Now Playing:</font> ")) && (s2 = strstr(s1, "</font>"))) { if (info->stream) { g_free(info->stream->now_playing); info->stream->now_playing = st_sgml_ref_expand_len(s1, s2 - s1); } else PARSE_ERROR; } else if ((s1 = st_str_has_prefix_span(line, "Page ")) && (s2 = strstr(s1, " of "))) { word1 = st_sgml_ref_expand_len(s1, s2 - s1); s2 += 4; word2 = st_sgml_ref_expand_len(s2, strspn(s2, ST_NUMERIC)); if (st_str_like(word1, ST_NUMERIC) && st_str_like(word2, ST_NUMERIC)) { info->page = atoi(word1); info->npages = atoi(word2); } else PARSE_ERROR; g_free(word1); g_free(word2); } else if ((s1 = st_strstr_span(line, "<font face=")) && (s2 = st_strchr_span(s1, '>')) && (s3 = strstr(s2, "</font>"))) { word1 = st_sgml_ref_expand_len(s2, s3 - s2); if (st_str_like(word1, ST_NUMERIC "/")) { if ((s1 = strchr(word1, '/'))) /* listeners */ { *s1 = 0; if (info->stream) { info->stream->listeners = atoi(word1); info->stream->max = atoi(s1 + 1); } else PARSE_ERROR; } else /* bitrate */ { if (info->stream) { info->stream->bitrate = atoi(word1); if (info->stream->genre && info->stream->description && info->stream->homepage) { ((STStream *) info->stream)->name = g_strdup_printf("%s%s%i", info->stream->genre, info->stream->description, info->stream->bitrate); *(info->streams) = g_list_append(*(info->streams), info->stream); } else { PARSE_ERROR; stream_free_cb(info->stream, NULL); } info->stream = NULL; } else PARSE_ERROR; } } g_free(word1); }}static gbooleansearch_url_cb (STCategory *category){ char *str; str = st_search_dialog(); if (str) { char *escaped; g_free(category->label); category->label = g_strdup_printf(_("Search results for \"%s\""), str); escaped = st_transfer_escape(str); g_free(str); g_free(category->url_postfix); category->url_postfix = g_strconcat("&s=", escaped, NULL); g_free(escaped); return TRUE; } else return FALSE;}static voidinit_handler (void){ GNode *stock_categories; STCategory *category; STHandlerField *field; shoutcast_handler = st_handler_new_from_plugin(shoutcast_plugin); st_handler_set_description(shoutcast_handler, _("SHOUTcast Yellow Pages")); st_handler_set_home(shoutcast_handler, "http://www.shoutcast.com/"); stock_categories = g_node_new(NULL); category = st_category_new(); category->name = "__main"; category->label = _("Top streams"); category->url_postfix = "&sgenre=TopTen"; g_node_append_data(stock_categories, category); category = st_category_new(); category->name = "__search"; category->label = g_strdup(_("Search")); category->url_cb = search_url_cb; g_node_append_data(stock_categories, category); st_handler_set_stock_categories(shoutcast_handler, stock_categories); st_handler_bind(shoutcast_handler, ST_HANDLER_EVENT_RELOAD, reload_cb, NULL); st_handler_bind(shoutcast_handler, ST_HANDLER_EVENT_STREAM_NEW, stream_new_cb, NULL); st_handler_bind(shoutcast_handler, ST_HANDLER_EVENT_STREAM_FIELD_GET, stream_field_get_cb, NULL); st_handler_bind(shoutcast_handler, ST_HANDLER_EVENT_STREAM_FIELD_SET, stream_field_set_cb, NULL); st_handler_bind(shoutcast_handler, ST_HANDLER_EVENT_STREAM_STOCK_FIELD_GET, stream_stock_field_get_cb, NULL); st_handler_bind(shoutcast_handler, ST_HANDLER_EVENT_STREAM_FREE, stream_free_cb, NULL); st_handler_bind(shoutcast_handler, ST_HANDLER_EVENT_STREAM_RESOLVE, stream_resolve_cb, NULL); st_handler_bind(shoutcast_handler, ST_HANDLER_EVENT_STREAM_TUNE_IN, stream_tune_in_cb, NULL); st_handler_bind(shoutcast_handler, ST_HANDLER_EVENT_STREAM_RECORD, stream_record_cb, NULL); st_handler_bind(shoutcast_handler, ST_HANDLER_EVENT_STREAM_BROWSE, stream_browse_cb, NULL); st_handler_bind(shoutcast_handler, ST_HANDLER_EVENT_PREFERENCES_WIDGET_NEW, preferences_widget_new_cb, NULL); field = st_handler_field_new(FIELD_GENRE, _("Genre"), G_TYPE_STRING, ST_HANDLER_FIELD_VISIBLE); st_handler_field_set_description(field, _("The stream genre")); st_handler_add_field(shoutcast_handler, field); field = st_handler_field_new(FIELD_DESCRIPTION, _("Description"), G_TYPE_STRING, ST_HANDLER_FIELD_VISIBLE); st_handler_field_set_description(field, _("The stream description")); st_handler_add_field(shoutcast_handler, field); field = st_handler_field_new(FIELD_NOW_PLAYING, _("Now playing"), G_TYPE_STRING, ST_HANDLER_FIELD_VISIBLE); st_handler_field_set_description(field, _("The currently playing song")); st_handler_add_field(shoutcast_handler, field); field = st_handler_field_new(FIELD_LISTENERS, _("Listeners"), G_TYPE_INT, ST_HANDLER_FIELD_VISIBLE); st_handler_field_set_description(field, _("The current number of listeners")); st_handler_add_field(shoutcast_handler, field); field = st_handler_field_new(FIELD_MAX, _("Max"), G_TYPE_INT, ST_HANDLER_FIELD_VISIBLE); st_handler_field_set_description(field, _("The maximum number of listeners")); st_handler_add_field(shoutcast_handler, field); field = st_handler_field_new(FIELD_BITRATE, _("Bitrate"), G_TYPE_INT, ST_HANDLER_FIELD_VISIBLE); st_handler_field_set_description(field, _("The stream bitrate, in kilobits per seconds")); st_handler_add_field(shoutcast_handler, field); st_handler_add_field(shoutcast_handler, st_handler_field_new(FIELD_URL_POSTFIX, _("URL postfix"), G_TYPE_STRING, 0)); field = st_handler_field_new(FIELD_HOMEPAGE, _("Homepage"), G_TYPE_STRING, ST_HANDLER_FIELD_VISIBLE | ST_HANDLER_FIELD_START_HIDDEN); st_handler_field_set_description(field, _("The stream homepage URL")); st_handler_add_field(shoutcast_handler, field); field = st_handler_field_new(FIELD_URL_LIST, _("URL list"), G_TYPE_VALUE_ARRAY, ST_HANDLER_FIELD_VISIBLE | ST_HANDLER_FIELD_START_HIDDEN); st_handler_field_set_description(field, _("The stream listen URL list")); st_handler_add_field(shoutcast_handler, field); st_handler_config_register(shoutcast_handler, g_param_spec_boolean(CONFIG_STREAM_LIMIT_ENABLED, NULL, NULL, FALSE, G_PARAM_READWRITE)); st_handler_config_register(shoutcast_handler, g_param_spec_int(CONFIG_STREAM_LIMIT, NULL, NULL, MIN_STREAM_LIMIT, MAX_STREAM_LIMIT, 100, G_PARAM_READWRITE)); st_handlers_add(shoutcast_handler);}static GtkWidget *preferences_widget_new_cb (gpointer data){ GtkWidget *box1; GtkWidget *box2; GtkWidget *section; box1 = gtk_hbox_new(FALSE, 12); preferences_stream_limit_check = gtk_check_button_new_with_mnemonic(_("_Load at most:")); box2 = gtk_hbox_new(FALSE, 6); preferences_stream_limit_spin = gtk_spin_button_new_with_range(MIN_STREAM_LIMIT, MAX_STREAM_LIMIT, 1); preferences_stream_limit_label = gtk_label_new(_("streams per category")); gtk_box_pack_start(GTK_BOX(box2), preferences_stream_limit_spin, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(box2), preferences_stream_limit_label, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(box1), preferences_stream_limit_check, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(box1), box2, FALSE, FALSE, 0); gtk_widget_show_all(box1); section = st_hig_section_new(_("Streams Limit"), box1); st_set_tooltip(preferences_stream_limit_check, _("If this option is enabled, the number of streams to download will be limited.")); st_set_tooltip(preferences_stream_limit_spin, _("The maximum number of streams to download per category")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(preferences_stream_limit_check), st_handler_config_get_boolean(shoutcast_handler, CONFIG_STREAM_LIMIT_ENABLED)); gtk_spin_button_set_value(GTK_SPIN_BUTTON(preferences_stream_limit_spin), st_handler_config_get_int(shoutcast_handler, CONFIG_STREAM_LIMIT)); preferences_update_sensitivity(); g_signal_connect(preferences_stream_limit_check, "toggled", G_CALLBACK(preferences_stream_limit_toggled_h), NULL); g_signal_connect(preferences_stream_limit_spin, "value-changed", G_CALLBACK(preferences_stream_limit_changed_h), NULL); return section;}static voidpreferences_update_sensitivity (void){ gboolean stream_limit_enabled; stream_limit_enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(preferences_stream_limit_check)); gtk_widget_set_sensitive(preferences_stream_limit_spin, stream_limit_enabled); gtk_widget_set_sensitive(preferences_stream_limit_label, stream_limit_enabled);}static voidpreferences_stream_limit_toggled_h (GtkToggleButton *button, gpointer user_data){ st_handler_config_set_boolean(shoutcast_handler, CONFIG_STREAM_LIMIT_ENABLED, gtk_toggle_button_get_active(button)); preferences_update_sensitivity();}static voidpreferences_stream_limit_changed_h (GtkSpinButton *spin, gpointer user_data){ st_handler_config_set_int(shoutcast_handler, CONFIG_STREAM_LIMIT, gtk_spin_button_get_value_as_int(spin));}static gbooleancheck_api_version (GError **err){ if (st_check_api_version(5, 8)) return TRUE; else { g_set_error(err, 0, 0, _("API version mismatch")); return FALSE; }}G_MODULE_EXPORT gbooleanplugin_get_info (STPlugin *plugin, GError **err){ GdkPixbuf *pixbuf; if (! check_api_version(err)) return FALSE; shoutcast_plugin = plugin; st_plugin_set_name(plugin, "shoutcast"); st_plugin_set_label(plugin, "SHOUTcast"); pixbuf = st_pixbuf_new_from_file(UIDIR "/shoutcast.png"); if (pixbuf) { st_plugin_set_icon_from_pixbuf(plugin, pixbuf); g_object_unref(pixbuf); } return TRUE;}G_MODULE_EXPORT gbooleanplugin_init (GError **err){ if (! check_api_version(err)) return FALSE; init_handler(); st_action_register("play-m3u", _("Listen to a .m3u file"), "xmms %q"); st_action_register("record-stream", _("Record a stream"), "xterm -e streamripper %q"); st_action_register("view-web", _("Open a web page"), "epiphany %q"); return TRUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -