/* * Raffael Himmelreich * * Compile with: * gcc cover_art.c -o cover_art -lcurl `xml2-config --cflags` `xml2-config --libs` * * Usage: * raffi@sofie:~/src/gtkpod/src$ ./cover_art "raffi banana phone" * http://images.amazon.com/images/P/B0000003HW.01.THUMBZZZ.jpg * raffi@sofie:~/src/gtkpod/src$ * */ #include #include #include #include #include #include #include #include #include #include struct MemoryStruct { char *memory; size_t size; }; void *myrealloc(void *ptr, size_t size) { /* There might be a realloc() out there that doesn't like reallocing * NULL pointers, so we take care of it here */ if (ptr) return (void *)realloc(ptr, size); else return (void *)malloc(size); } size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) { size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)data; mem->memory = (char *)myrealloc(mem->memory, mem->size + realsize + 1); if (mem->memory) { memcpy(&(mem->memory[mem->size]), ptr, realsize); mem->size += realsize; mem->memory[mem->size] = 0; } return realsize; } int get_cover_url(char *content, int length) { xmlDocPtr doc; xmlXPathContextPtr xpathCtx; xmlXPathObjectPtr xpathObj; const xmlChar *xpathExpr = BAD_CAST "//Details/ImageUrlSmall"; int node_nr, ret = 0; xmlInitParser(); doc = xmlReadMemory(content, length, "amazon.xml", NULL, 0); if ( doc == NULL ) { fprintf(stderr, "Failed to parse XML\n"); return -1; } /* Create xpath evaluation context */ xpathCtx = xmlXPathNewContext(doc); if( xpathCtx == NULL ) { fprintf(stderr,"Error: unable to create new XPath context\n"); xmlFreeDoc(doc); return -1; } /* Evaluate xpath expression */ xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); if( xpathObj == NULL ) { fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", xpathExpr); xmlXPathFreeContext(xpathCtx); xmlFreeDoc(doc); return -1; } node_nr = (xpathObj->nodesetval) ? xpathObj->nodesetval->nodeNr : 0; if ( node_nr ) printf("%s\n", xmlNodeGetContent(xpathObj->nodesetval->nodeTab[0])); else ret = -1; /* Cleanup of XPath data */ xmlXPathFreeObject(xpathObj); xmlXPathFreeContext(xpathCtx); xmlFreeDoc(doc); xmlCleanupParser(); return ret; } int main(int argc, char **argv) { #if defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_SAX1_ENABLED) const char *LICENSE = "D1URM11J3F2CEH", *tld = "com", *music_mode = "music", *locale = "us"; char url[512]; int ret, running_handles; CURL *curl; CURLM *curlm; char *search = curl_escape(argv[1], 0); struct MemoryStruct chunk; chunk.memory=NULL; /* we expect realloc(NULL, size) to work */ chunk.size = 0; /* no data at this point */ ret = snprintf(url, sizeof(url), "http://xml.amazon.%s" "/onca/xml3?t=webservices-20&dev-t=%s" "&KeywordSearch=%s&mode=%s&type=lite&locale=%s&page=1&f=xml", tld, LICENSE, search, music_mode, locale); if ( ret == -1 ) fprintf(stderr, "Amazon search string too long!\n"); curl_free(search); curl = curl_easy_init(); curlm = curl_multi_init(); curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15); /* send all data to this function */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); /* we pass our 'chunk' struct to the callback function */ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); /* some servers don't like requests that are made without a user-agent * field, so we provide one */ curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); curl_multi_add_handle(curlm, curl); running_handles = 1; while ( running_handles > 0 ) curl_multi_perform(curlm, &running_handles); curl_easy_cleanup(curl); curl_global_cleanup(); get_cover_url(chunk.memory, chunk.size); if(chunk.memory) free(chunk.memory); #else #error Please compile libxml2 with Xpath support to enjoy gtkpod's album art retrieval feature! fprintf(stderr, "You don't have Xpath support!"); #endif return 0; }