Now uses proper xform functions, removed all playlist writing related code. Seems like something that should be implemented client-side.
Now iterates through each line of the stream, extracting urls from anchors instead of reading the entire thing into memory and g_strsplit-ing it. Added more magic signatures and extensions. --- src/plugins/html/html.c | 491 +++++++++------------------------------------- src/plugins/html/wscript | 2 +- 2 files changed, 91 insertions(+), 402 deletions(-) diff --git a/src/plugins/html/html.c b/src/plugins/html/html.c index 5570fe9..e13eac8 100644 --- a/src/plugins/html/html.c +++ b/src/plugins/html/html.c @@ -14,428 +14,119 @@ * Lesser General Public License for more details. */ - - - -#include "xmms/xmms_plugin.h" -#include "xmms/xmms_transport.h" -#include "xmms/xmms_log.h" -#include "xmms/xmms_plsplugins.h" -#include "xmms/xmms_medialib.h" - #include <string.h> #include <stdio.h> #include <stdlib.h> #include <glib.h> -#include <glib/gprintf.h> -/* - * Function prototypes - */ +#include "xmms/xmms_xformplugin.h" +#include "xmms/xmms_log.h" +#include "xmms/xmms_medialib.h" +#include "xmms/xmms_util.h" -static gboolean xmms_html_read_playlist (xmms_transport_t *transport, guint playlist_id); -static GString *xmms_html_write_playlist (guint32 *list); +/* xform methods */ +static gboolean xmms_html_setup (xmms_xform_plugin_t *xform); +static gboolean xmms_html_init (xmms_xform_t *xform); +static gboolean xmms_html_browse (xmms_xform_t *xform, + const gchar *url, xmms_error_t *error); -static gchar *escape_html (const gchar *in); -static gboolean valid_suffix (gchar **suffix, gchar *path); +/* for extracting the href attribute out of a tags */ static gchar* parse_tag (const gchar *tag, const gchar *plspath); -static gchar* build_url (const gchar *plspath, const gchar *file); -static gchar* path_get_body (const gchar *path); - -static gchar html_header[] = -"<?xml version=\"1.0\" encoding=\"utf8\"?>\n" -"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" -"<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n" -"<head>\n" -" <title>XMMS2 Playlist</title>\n" -" <meta name=\"generator\" content=\"XMMS2\"/>\n" -" <meta http-equiv=\"content-type\" content=\"text/xhtml; charset=utf8\"/>\n" -" <meta http-equiv=\"content-style-type\" content=\"text/css\"/>\n" -" <link href=\"playlist.css\" rel=\"stylesheet\" type=\"text/css\"/>\n" -"</head>\n" -"<body>\n" -" <h1>XMMS2 Playlist</h1>\n" -"\n" -" <div id=\"container\">\n" -" <p>\n" -" Number of tracks: %i\n" -" <br/>\n" -" Total playtime: %i:%02i:%02i\n" -" </p>\n" -"\n" -" <h2>Tracks</h2>\n" -"\n" -" <ol id=\"playlist\">\n"; -static gchar html_entry_even[] = "\t\t\t<li class=\"entry_even\">%s</li>\n"; -static gchar html_entry_odd[] = "\t\t\t<li class=\"entry_odd\">%s</li>\n"; -static gchar html_footer[] = -" </div>\n" -" </div>\n" -"</body>\n" -"</html>\n"; - -/* - * Plugin header - */ +/* declare the plugin */ +XMMS_XFORM_PLUGIN ("html", + "HTML Playlist Reader", + XMMS_VERSION, + "Reads HTML playlists", + xmms_html_setup); -xmms_plugin_t * -xmms_plugin_get (void) +static gboolean xmms_html_setup (xmms_xform_plugin_t *xform) { - xmms_plugin_t *plugin; - - plugin = xmms_plugin_new (XMMS_PLUGIN_TYPE_PLAYLIST, - XMMS_PLAYLIST_PLUGIN_API_VERSION, - "html", - "HTML Playlist", - XMMS_VERSION, - "HTML Playlist reader"); - - if (!plugin) { - return NULL; - } + xmms_xform_methods_t methods; + XMMS_XFORM_METHODS_INIT (methods); + + methods.init = xmms_html_init; + methods.browse = xmms_html_browse; + xmms_xform_plugin_methods_set (xform, &methods); + + xmms_xform_plugin_indata_add (xform, + XMMS_STREAM_TYPE_MIMETYPE, + "text/html", + NULL); + + xmms_magic_extension_add ("text/html", "*.html"); + xmms_magic_extension_add ("text/html", "*.xhtml"); + + xmms_magic_add ("html ucase doctype", "text/html", + "0 string <!DOCTYPE HTML "); + + xmms_magic_add ("html ucase tag", "text/html", + "0 string <HTML "); + + xmms_magic_add ("html w/ doctype", "text/html", + "0 string <!DOCTYPE html "); + + xmms_magic_add ("html tag", "text/html", + "0 string <html "); + + xmms_magic_add ("html header tag", "text/html", + "0 string <head "); + + xmms_magic_add ("xml tag", "text/html", + "0 string <?xml "); - xmms_plugin_info_add (plugin, "URL", "http://www.xmms.org/"); - xmms_plugin_info_add (plugin, "Author", "XMMS Team"); - - xmms_plugin_method_add (plugin, XMMS_PLUGIN_METHOD_READ_PLAYLIST, xmms_html_read_playlist); - xmms_plugin_method_add (plugin, XMMS_PLUGIN_METHOD_WRITE_PLAYLIST, xmms_html_write_playlist); - - xmms_plugin_config_property_register (plugin, "suffixes", - "mp3,ogg,flac,wav,spx,sid", - NULL, NULL); - - xmms_plugin_magic_add (plugin, "html w/ doctype", "text/html", - "0 string <!DOCTYPE html ", NULL); - - /* we accept broken HTML, too */ - xmms_plugin_magic_add (plugin, "html tag", "text/html", - "0 string <html ", NULL); - xmms_plugin_magic_add (plugin, "html header tag", "text/html", - "0 string <head ", NULL); - - /* XHTML */ - xmms_plugin_magic_add (plugin, "xml tag", "text/html", - "0 string <?xml ", NULL); - - return plugin; + return TRUE; } -static gboolean -xmms_html_read_playlist (xmms_transport_t *transport, - guint32 playlist_id) +static gboolean xmms_html_init (xmms_xform_t *xform) { - gchar *buffer; - const gchar *plsurl; - gchar **tags; - gchar **suffix; - xmms_config_property_t *val; - xmms_medialib_session_t *session; - xmms_error_t error; - - gint cnt, readlen, buflen; - - g_return_val_if_fail (transport, FALSE); - g_return_val_if_fail (playlist_id, FALSE); - - buflen = xmms_transport_size (transport); - if (buflen == 0) { - XMMS_DBG ("Empty playlist, nothing to add here"); - return TRUE; - } - - if (buflen == -1) { - buflen = 4096; - } - - buffer = g_malloc0 (buflen); - g_return_val_if_fail (buffer, FALSE); - - readlen = 0; - while (readlen < buflen) { - gint ret; - - ret = xmms_transport_read (transport, buffer + readlen, - buflen - readlen, &error); - - XMMS_DBG ("Got %d bytes", ret); - if (ret <= 0) { - if (readlen > 0) { - break; - } - - g_free (buffer); - - return FALSE; - } - - readlen += ret; - g_assert (readlen >= 0); - } - - tags = g_strsplit (buffer, "<", 0); - g_free (buffer); - - val = xmms_config_lookup ("playlist.html.suffixes"); - suffix = g_strsplit (xmms_config_property_get_string (val), ",", 0); - - plsurl = xmms_transport_url_get (transport); - - session = xmms_medialib_begin_write (); - - for (cnt = 0; tags[cnt] != NULL; cnt++) { - gchar *url, *full; - xmms_medialib_entry_t entry; - - url = parse_tag (tags[cnt], plsurl); - if (!url) { - continue; - } - - if (!valid_suffix (suffix, url)) { - g_free (url); - continue; - } - - full = build_url (plsurl, url); - - entry = xmms_medialib_entry_new (session, full, &error); - if (entry) - xmms_medialib_playlist_add (session, playlist_id, entry); - - g_free (url); - g_free (full); - } - - g_strfreev (suffix); - g_strfreev (tags); - - xmms_medialib_end (session); - + xmms_xform_outdata_type_add (xform, + XMMS_STREAM_TYPE_MIMETYPE, + "application/x-xmms2-playlist-entries", + XMMS_STREAM_TYPE_END); return TRUE; } -static GString * -xmms_html_write_playlist (guint32 *list) +static gboolean xmms_html_browse (xmms_xform_t *xform, const gchar *url, + xmms_error_t *error) { - GString *ret; - xmms_medialib_session_t *session; - gboolean is_even = TRUE; - guint num_entries = 0, total_len = 0; - guint i; - - g_return_val_if_fail (list, FALSE); - - session = xmms_medialib_begin (); - - /* get the playlists total playtime */ - while (list[num_entries]) { - xmms_medialib_entry_t entry = list[num_entries]; - - total_len += xmms_medialib_entry_property_get_int (session, entry, - XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION); - - num_entries++; - } - - ret = g_string_new (NULL); - g_string_append_printf (ret, html_header, num_entries, - total_len / 3600000, (total_len / 60000) % 60, - (total_len / 1000) % 60); - - i = 0; - - while (list[i]) { - gchar buf[256], *artist, *title, *url; - xmms_medialib_entry_t entry; - guint len; - - entry = list[i]; - - artist = escape_html (xmms_medialib_entry_property_get_str (session, entry, - XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST)); - title = escape_html (xmms_medialib_entry_property_get_str (session, entry, - XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE)); - len = xmms_medialib_entry_property_get_int (session, entry, - XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION); - url = escape_html (xmms_medialib_entry_property_get_str (session, entry, - XMMS_MEDIALIB_ENTRY_PROPERTY_URL)); - - if (!artist && !title) { - g_snprintf (buf, sizeof (buf), "%s (%02i:%02i)", - url, len / 60000, (len / 1000) % 60); - } else { - g_snprintf (buf, sizeof (buf), "%s - %s (%02i:%02i)", - artist ? artist : "Unknown artist", - title ? title : "Unknown title", - len / 60000, (len / 1000) % 60); + g_return_val_if_fail (xform, FALSE); + + gchar buffer[XMMS_XFORM_MAX_LINE_SIZE]; + const gchar *plsurl = xmms_xform_get_url (xform); + + g_return_val_if_fail (plsurl, FALSE); + + xmms_error_reset(error); + + xmms_medialib_session_t *session = xmms_medialib_begin_write (); + g_return_val_if_fail (session, FALSE); + + while (xmms_xform_read_line (xform, buffer, error)) + { + gchar *tagbeg = buffer; + while ((tagbeg = strchr (tagbeg, '<'))) + { + gchar *aurl=NULL; + if ((aurl = parse_tag(++tagbeg, plsurl))) + { + gchar *full = xmms_build_playlist_url (plsurl, + aurl); + xmms_xform_browse_add_symlink (xform, + NULL, full); + g_free (full); + g_free(aurl); + } } - - if (artist) - g_free (artist); - if (title) - g_free (title); - if (url) - g_free (url); - - g_string_append_printf (ret, is_even ? html_entry_even - : html_entry_odd, buf); - is_even = !is_even; - - i++; } xmms_medialib_end (session); - g_string_append (ret, html_footer); - - return ret; -} - -static gchar * -escape_html (const gchar *in) -{ - gchar *ret = NULL, *retptr; - const gchar *inptr; - gsize len = 0; - gboolean need_escape = FALSE; - - if (!in) - return NULL; - - /* check whether we need to escape this string at all, - * and if we do, get the required length of the new buffer. - */ - for (inptr = in; *inptr; inptr++) { - switch (*inptr) { - case '"': - need_escape = TRUE; - len += 6; /* " */ - break; - case '&': - need_escape = TRUE; - len += 5; /* & */ - break; - case '>': - case '<': - need_escape = TRUE; - len += 4; /* > resp < */ - break; - default: - len++; - } - } - - if (!need_escape) - return g_strdup (in); - - len++; /* terminating NUL */ - retptr = ret = g_malloc (len); - *ret = '\0'; - - for (inptr = in; *inptr; inptr++) { - gint n; - - switch (*inptr) { - case '"': - n = g_snprintf (retptr, len, """); - break; - case '&': - n = g_snprintf (retptr, len, "&"); - break; - case '>': - n = g_snprintf (retptr, len, ">"); - break; - case '<': - n = g_snprintf (retptr, len, "<"); - break; - default: - n = g_snprintf (retptr, len, "%c", *inptr); - } - - len -= n; - retptr += n; - } - return ret; -} - -static gboolean -valid_suffix (gchar **suffix, gchar *path) -{ - guint current; - - g_return_val_if_fail (suffix, FALSE); - g_return_val_if_fail (path, FALSE); - - for (current = 0; suffix[current] != NULL; current++) { - if (g_str_has_suffix (path, g_strstrip (suffix[current]))) - return TRUE; - } - - return FALSE; -} - -static gchar * -build_url (const gchar *plspath, const gchar *file) -{ - gchar *url; - gchar *path; - - g_return_val_if_fail (plspath, NULL); - g_return_val_if_fail (file, NULL); - - if (strstr (file, "://") != NULL) { - return g_strdup (file); - } - - if (file[0] == '/') { - path = path_get_body (plspath); - url = g_build_filename (path, file, NULL); - - g_free (path); - - return url; - } - - path = g_path_get_dirname (plspath); - url = g_build_filename (path, file, NULL); - - g_free (path); - - return url; -} - -/* - * proto://domain/dir/file -> proto://domain - * domain/dir/file -> domain - **/ - -static gchar * -path_get_body (const gchar *path) -{ - gchar *beg, *end; - - g_return_val_if_fail (path, NULL); - - beg = strstr (path, "://"); - - if (!beg) { - return g_strndup (path, strcspn (path, "/")); - } - - beg += 3; - end = strchr (beg, '/'); - - if (!end) { - return g_strdup (path); - } - - return g_strndup (path, end - path); + return TRUE; } -static gchar * -parse_tag (const gchar *tag, const gchar *plspath) +static gchar *parse_tag (const gchar *tag, const gchar *plspath) { size_t urlend; gchar *href, *url; @@ -443,19 +134,16 @@ parse_tag (const gchar *tag, const gchar *plspath) g_return_val_if_fail (tag, NULL); g_return_val_if_fail (plspath, NULL); - if (g_ascii_strncasecmp (tag, "a ", 2) != 0) { + if (g_ascii_strncasecmp (tag, "a ", 2) != 0) return NULL; - } href = strstr (tag, "href=\""); - if (!href) { + if (!href) href = strstr (tag, "HREF=\""); - } - if (!href) { + if (!href) return NULL; - } urlend = strcspn (href + 6, "\""); @@ -463,3 +151,4 @@ parse_tag (const gchar *tag, const gchar *plspath) return url; } + diff --git a/src/plugins/html/wscript b/src/plugins/html/wscript index 5de9a97..57d8382 100644 --- a/src/plugins/html/wscript +++ b/src/plugins/html/wscript @@ -1,3 +1,3 @@ from waftools.plugin import plugin -configure, build = plugin('html', broken=True) +configure, build = plugin('html', broken=False) -- 1.6.0.3 -- _______________________________________________ Xmms2-devel mailing list [email protected] http://lists.xmms.se/cgi-bin/mailman/listinfo/xmms2-devel
