Re: [Rhythmbox-devel] covert art thingo to play with



Hi,

So I played a bit...  Here is an updated version that uses XPATH instead 
of looping through nodes, fixes a few bugs, and takes the artist and 
title from the results rather than from the user's input.  This last 
part is necessary because the user input is actually a search expression.

And this is what causes a few problems.  It seems that the only search 
method we can use is the KeywordSearch.  We really want something 
similiar to the PowerSearch capability so that we can do:

http://xml.amazon.com/onca/xml3?t=hadess@hadess.net&dev-t=D1EEUYQ7Y68BJ3&PowerSearch=artist:Dead%20Meadow%20and%20title:Dead%20Meadow&mode=music&sort=+pmrank&offer=All&type=lite&page=&f=xml

However, PowerSearch is only for books :(.  I think we are stuck with:

http://xml.amazon.com/onca/xml3?t=hadess@hadess.net&dev-t=D1EEUYQ7Y68BJ3&KeywordSearch=Dead%20Meadow&mode=music&sort=+pmrank&offer=All&type=lite&page=&f=xml

This means that the technique of simply using the first result won't 
always work.  Think about self titled or numbered albums (eg. Led 
Zeppelin I).  To work around this the program now takes separate artist 
and title strings as input.  It then uses XPATH to first look for exact 
matches in the results.  If one is not found then the first result is used.

So, the following works:
./test-cover "Dead Meadow" "Dead Meadow"

Jon
/* -*- mode:C; indent-tabs-mode:nil; tab-width:8; c-basic-offset:8; -*- */

/* 
 * Copyright (C) 2003 by Bastien Nocera <hadess@hadess.net>
 * Copyright (C) 2003 by William Jon McCann <mccann@jhu.edu>
 *
 * 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 of the License, or
 * (at your option) any later version.
 *
 * 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
 * GNU General Public License for more details.
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Compile with:
 * gcc -o test-cover `pkg-config --cflags --libs gnome-vfs-2.0 libxml-2.0` test-cover.c
 *
 */

#include <libgnomevfs/gnome-vfs.h>
#include <glib.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>

#define XPATH_BASE         "/ProductInfo/Details"
#define XPATH_SMALL_SIZE   "ImageUrlSmall"
#define XPATH_MEDIUM_SIZE  "ImageUrlMedium"
#define XPATH_LARGE_SIZE   "ImageUrlLarge"
#define XPATH_IMAGE        XPATH_BASE "/" XPATH_MEDIUM_SIZE
#define XPATH_ARTIST_SHORT "Artists/Artist"
#define XPATH_ALBUM_SHORT  "ProductName"
#define XPATH_ARTIST       XPATH_BASE "/" XPATH_ARTIST_SHORT
#define XPATH_ALBUM        XPATH_BASE "/" XPATH_ALBUM_SHORT

#define NO_IMAGE_URL "http://g-images.amazon.com/images/G/01/music/icons/music-no-image.gif";
#define SEARCH_URL_FORMAT "http://xml.amazon.com/onca/xml3?t=hadess@hadess.net&dev-t=D1EEUYQ7Y68BJ3&KeywordSearch=%s&mode=music&sort=+pmrank&offer=All&type=lite&page=&f=xml";

#define CURRENT_SIZE SMALL_SIZE
#define READ_CHUNK_SIZE 8192

static char *img_url = NULL;
static char *img_title = NULL;

static void
usage (const char *msg)
{
        char *prog_name;

        prog_name = g_get_prgname ();

	if (msg != NULL) {
		g_print ("Error: %s\n", msg);
	}
        
	g_print ("Usage: %s <artist> <title>\n", prog_name);

        g_free (prog_name);
	exit (1);
}

static GnomeVFSResult
my_eel_read_entire_file (const char *uri,
                         int *file_size,
                         char **file_contents)
{
        GnomeVFSResult result;
        GnomeVFSHandle *handle;
        char *buffer;
        GnomeVFSFileSize total_bytes_read;
        GnomeVFSFileSize bytes_read;

        *file_size = 0;
        *file_contents = NULL;

        /* Open the file. */
        result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
        if (result != GNOME_VFS_OK) {
                return result;
        }

        /* Read the whole thing. */
        buffer = NULL;
        total_bytes_read = 0;
        do {
                buffer = g_realloc (buffer, total_bytes_read + READ_CHUNK_SIZE);
                result = gnome_vfs_read (handle,
                                         buffer + total_bytes_read,
                                         READ_CHUNK_SIZE,
                                         &bytes_read);
                if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) {
                        g_free (buffer);
                        gnome_vfs_close (handle);
                        return result;
                }

                /* Check for overflow. */
                if (total_bytes_read + bytes_read < total_bytes_read) {
                        g_free (buffer);
                        gnome_vfs_close (handle);
                        return GNOME_VFS_ERROR_TOO_BIG;
                }

                total_bytes_read += bytes_read;
        } while (result == GNOME_VFS_OK);

        /* Close the file. */
        result = gnome_vfs_close (handle);
        if (result != GNOME_VFS_OK) {
                g_free (buffer);
                return result;
        }

        /* Return the file. */
        *file_size = total_bytes_read;
        *file_contents = g_realloc (buffer, total_bytes_read);
                                                                                
        return GNOME_VFS_OK;
}

static char *
print_uri (const char *artist_term, const char *album_term)
{
	char *escaped, *url, *search_expression;
        
        search_expression = g_strdup_printf ("%s %s", artist_term, album_term);

	/* Construct the URL */
	escaped = gnome_vfs_escape_path_string (search_expression);
	url = g_strdup_printf (SEARCH_URL_FORMAT, escaped);
        g_free (search_expression);
	g_free (escaped);

	return url;
}

static xmlXPathObjectPtr
getnodeset (xmlDocPtr doc, xmlChar *xpath)
{	
	xmlXPathContextPtr context;
	xmlXPathObjectPtr result;

	context = xmlXPathNewContext (doc);
	result = xmlXPathEvalExpression (xpath, context);
	if (xmlXPathNodeSetIsEmpty (result->nodesetval)) {
		return NULL;
	}
	xmlXPathFreeContext (context);
	return result;
}

static gchar *
get_first_xpath_string (xmlDocPtr doc, xmlChar *xpath)
{ 
        xmlChar *keyword = NULL;
	xmlXPathObjectPtr result;
	xmlNodeSetPtr nodeset;

	result = getnodeset (doc, xpath);
        if (result) {
		nodeset = result->nodesetval;
                if (nodeset->nodeNr > 0) {
			keyword = xmlNodeListGetString (doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
		}
	}
        return keyword;
}

static gboolean
parse_document (xmlDocPtr doc, const char *artist_term, const char *album_term)
{	
	xmlXPathObjectPtr result;
	xmlNodeSetPtr nodeset;
        gint i;
        xmlChar *xpath = NULL;
        xmlChar *keyword = NULL;
        xmlChar *keyword2 = NULL;

        /* look for an extact match of artist and title or use first result */
        xpath = g_strdup_printf ("%s[../%s='%s' and ../%s='%s']",
                                 XPATH_IMAGE, XPATH_ALBUM_SHORT, album_term, XPATH_ARTIST_SHORT, artist_term);
        keyword = get_first_xpath_string (doc, xpath);
        g_free (xpath);

        if (keyword != NULL) {
                img_url = keyword;
                img_title = g_strdup_printf ("%s - %s", artist_term, album_term);
        } else {
                keyword = get_first_xpath_string (doc, XPATH_IMAGE);
                img_url = keyword;
                keyword = NULL;
                keyword = get_first_xpath_string (doc, XPATH_ARTIST);
                if (keyword == NULL)
                        keyword = g_strdup ("Unknown");
                keyword2 = get_first_xpath_string (doc, XPATH_ALBUM);
                if (keyword2 == NULL)
                        keyword2 = g_strdup ("Unknown");
                img_title = g_strdup_printf ("%s - %s", keyword, keyword2);
                xmlFree (keyword);
                xmlFree (keyword2);
        }
	return TRUE;
}

static void
parse_xml (const char *url, const char *artist_term, const char *album_term)
{
	int size;
	char *contents = NULL;
	xmlDocPtr doc;
	xmlNodePtr node;

	if (my_eel_read_entire_file (url, &size, &contents) != GNOME_VFS_OK) {
		return;
	}

	contents = g_realloc (contents, size + 1);
	contents[size] = '\0';

	doc = xmlParseMemory (contents, size);
	if (doc == NULL)
		doc = xmlRecoverMemory (contents, size);
	g_free (contents);
        
	/* If the document has no root, or no name */
	if (!doc || !doc->children || !doc->children->name) {
                if (doc != NULL)
                        xmlFreeDoc(doc);
                return;
        }

	node = xmlDocGetRootElement(doc);
	parse_document (doc, artist_term, album_term);

	xmlFreeDoc(doc);
}

static char *
get_desktop_path (void)
{
	char *fullpath;
	gboolean desktop_exists;

	fullpath = g_build_path (G_DIR_SEPARATOR_S, g_get_home_dir (), "Desktop", NULL);
	desktop_exists = g_file_test (fullpath, G_FILE_TEST_EXISTS);
	g_free (fullpath);

	if (desktop_exists == TRUE) {
                return g_build_filename (G_DIR_SEPARATOR_S,
                                         g_get_home_dir (), "Desktop",
                                         "rb-current.desktop", NULL);
        } else {
                return g_build_filename (G_DIR_SEPARATOR_S,
                                         g_get_home_dir (), ".gnome-desktop",
                                         "rb-current.desktop", NULL);
        }

	return NULL;
}

static char *
copy_img_local (const char *url)
{
	GnomeVFSURI *src_uri, *dest_uri;
	GnomeVFSResult result;
	char *dest;

	if (url == NULL) {
		url = NO_IMAGE_URL;
	}

	dest = g_build_filename (G_DIR_SEPARATOR_S,
                                 g_get_home_dir (), ".gnome2",
                                 "rhythmbox", "rb-current.jpg", NULL);

	src_uri = gnome_vfs_uri_new (url);
	dest_uri = gnome_vfs_uri_new (dest);

	result = gnome_vfs_xfer_uri (src_uri, dest_uri,
                                     GNOME_VFS_XFER_DEFAULT,
                                     GNOME_VFS_XFER_ERROR_MODE_ABORT,
                                     GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
                                     NULL, NULL);
	gnome_vfs_uri_unref (src_uri);
	gnome_vfs_uri_unref (dest_uri);

	if (result != GNOME_VFS_OK) {
                g_free (dest);
                return NULL;
        }

	return dest;
}

static gboolean
write_string (GnomeVFSHandle *handle, const char *buf)
{
	GnomeVFSResult res;
	GnomeVFSFileSize written;
	int len;

	len = strlen (buf);
	res = gnome_vfs_write (handle, buf, len, &written);
	if (res != GNOME_VFS_OK || written < len) {
                gnome_vfs_close (handle);
                return FALSE;
        }
	return TRUE;
}

static void
create_desktop_file (const char *title, const char *icon)
{
	GnomeVFSHandle *handle;
	GnomeVFSResult res;
	char *desktop_path, *str;

	desktop_path = get_desktop_path ();
	if (desktop_path == NULL) {
		return;
	}

	res = gnome_vfs_open (&handle, desktop_path, GNOME_VFS_OPEN_WRITE);
	if (res == GNOME_VFS_ERROR_NOT_FOUND) {
                res = gnome_vfs_create (&handle, desktop_path,
                                        GNOME_VFS_OPEN_WRITE, FALSE,
                                        GNOME_VFS_PERM_USER_WRITE
                                        | GNOME_VFS_PERM_USER_READ
                                        | GNOME_VFS_PERM_GROUP_READ);
        }
        
	g_free (desktop_path);

	if (res != GNOME_VFS_OK) {
		return;
	}

	write_string (handle, "[Desktop Entry]\n");
	write_string (handle, "Encoding=UTF-8\n");

	str = g_strdup_printf ("Name=%s\n", title);
	write_string (handle, str);
	g_free (str);

	write_string (handle, "Exec=rhythmbox\n");

	if (icon != NULL) {
		str = g_strdup_printf ("Icon=%s\n", icon);
	} else {
		str = g_strdup ("Icon=\n");
	}
	write_string (handle, str);
	g_free (str);

	write_string (handle, "Terminal=0\n");
	write_string (handle, "Type=Application\n");

	gnome_vfs_close (handle);
}

int main (int argc, char **argv)
{
	char *url, *icon;
        char *artist_term, *album_term;

        g_set_prgname (argv[0]);

	if (argc != 3) {
		usage (NULL);
	}

	if (gnome_vfs_init () == FALSE) {
		usage ("Can't initialise gnome-vfs");
	}
        artist_term = g_strdup (argv[1]);
        album_term = g_strdup (argv[2]);

	url = print_uri (artist_term, album_term);
	parse_xml (url, artist_term, album_term);
	g_free (url);

	icon = copy_img_local (img_url);
	create_desktop_file (img_title, icon);

        g_free (img_url);
        g_free (img_title);
        g_free (icon);
        g_free (artist_term);
        g_free (album_term);

	return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]