/* ------------------------------------------------------------------ libofa -- the Open Fingerprint Architecture library Public Domain (PD) 2006 Predixis Corporation No rights reserved. -------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include using namespace std; #include "protocol.h" const char *url = "http://ofa.musicdns.org/ofa/1/track"; const char *userAgent = "libofa_example"; const char *unknown = "unknown"; // Lookup by fingerprint const char *request_format = "lkt=1&" // Lookup by print "cid=%s&" // Client ID "cvr=%s&" // Client Version "fpt=%s&" // Fingerprint "rmd=%d&" // m = 1: return metadata; m = 0: only return id "brt=%d&" // bitrate (kbps) "fmt=%s&" // File extension (e.g. mp3, ogg, flac) "dur=%ld&" // Length of track (milliseconds) "art=%s&" // Artist name. If there is none, send "unknown" "ttl=%s&" // Track title. If there is none, send "unknown" "alb=%s&" // Album name. If there is none, send "unknown" "tnm=%d&" // Track number in album. If there is none, send "0" "gnr=%s&" // Genre. If there is none, send "unknown" "yrr=%s&" // Year. If there is none, send "0" "enc=%s&" // Encoding. e = true: ISO-8859-15; e = false: UTF-8 (default). Optional. "\r\n"; // Lookup by PUID (Most fields drop out) const char *request_format2 = "lkt=2&" // Lookup by PUID "cid=%s&" // Client ID "cvr=%s&" // Client Version "pid=%s&" // PUID "rmd=%d&" // m = 1: return metadata; m = 0: only return id "brt=%d&" // bitrate (kbps) "fmt=%s&" // File extension (e.g. mp3, ogg, flac) "dur=%ld&" // Length of track (milliseconds) "art=%s&" // Artist name. If there is none, send "unknown" "ttl=%s&" // Track title. If there is none, send "unknown" "alb=%s&" // Album name. If there is none, send "unknown" "tnm=%d&" // Track number in album. If there is none, send "0" "gnr=%s&" // Genre. If there is none, send "unknown" "yrr=%s&" // Year. If there is none, send "0" "enc=%s&" // Encoding. e = true: ISO-8859-15; e = false: UTF-8 (default). Optional. "\r\n"; // -------------------------------------------------------------------- // HTTP POST support using standard curl calls // -------------------------------------------------------------------- size_t data_callback(void *ptr, size_t size, size_t num, void *arg) { string *str = (string *)arg; (*str) += string((const char *)ptr, size * num); return size * num; } long http_post(const string &url, const string &userAgent, const string &postData, string &doc) { CURL *curl; long ret = 0; struct curl_slist *headerlist=NULL; headerlist = curl_slist_append(headerlist, "Expect:"); curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&doc); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, data_callback); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postData.length()); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str()); curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent.c_str()); curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &ret); curl_easy_cleanup(curl); curl_slist_free_all (headerlist); return ret; } // -------------------------------------------------------------------- // XML Parsing support // -------------------------------------------------------------------- struct ParseInfo { string path; string pcdata; TrackInformation *info; }; void begin_element(void *data, const XML_Char *el, const XML_Char **attr) { map attrs; for(; *attr;) { char *key = (char *)*(attr++); char *value = (char *)*(attr++); attrs[string(key)] = string(value); } ((ParseInfo *)data)->path += "/"; ((ParseInfo *)data)->path += el; if (((ParseInfo *)data)->path == "/metadata/track/puid-list/puid") ((ParseInfo *)data)->info->setPUID(attrs["id"]); ((ParseInfo *)data)->pcdata = ""; } void end_element(void *data, const XML_Char *el) { string::size_type pos; if (((ParseInfo *)data)->path == "/metadata/track/title") ((ParseInfo *)data)->info->setTrack(((ParseInfo *)data)->pcdata); if (((ParseInfo *)data)->path == "/metadata/track/artist/name") ((ParseInfo *)data)->info->setArtist(((ParseInfo *)data)->pcdata); pos = ((ParseInfo *)data)->path.rfind("/"); if (pos != string::npos) ((ParseInfo *)data)->path = ((ParseInfo *)data)->path.substr(0, pos); } void pc_data(void *data, const XML_Char *charData, int len) { char *temp; temp = new char[len + 1]; strncpy(temp, (char *)charData, len); temp[len] = 0; ((ParseInfo *)data)->pcdata += string(temp); delete temp; } bool parse_xml(const string &doc, TrackInformation *info, string &err) { ParseInfo pinfo; err = ""; pinfo.info = info; XML_Parser parser = XML_ParserCreate(NULL); XML_SetUserData(parser, (void *)&pinfo); XML_SetElementHandler(parser, ::begin_element, ::end_element); XML_SetCharacterDataHandler(parser, ::pc_data); int ret = XML_Parse(parser, doc.c_str(), doc.length(), 1); if (ret) { XML_ParserFree(parser); return true; } err = string(XML_ErrorString(XML_GetErrorCode(parser))); char num[10]; sprintf(num, "%d", XML_GetCurrentLineNumber(parser)); err += string(" on line ") + string(num); XML_ParserFree(parser); return false; } // -------------------------------------------------------------------- // Retrieve metadata for fingerprint // -------------------------------------------------------------------- #define DB printf("%s:%d\n", __FILE__, __LINE__); // Returns true on success bool retrieve_metadata(TrackInformation *info) { if (!info) return false; // All metadata fields must be provided before this call if the // information is available, as part of the Terms of Service. // This helps create a better database for all users of the system. // // If the fields are not available, you can use default values. // Here we check for fields which have no default values. if (info->getClientKey().length() == 0) return false; if (info->getClientVersion().length() == 0) return false; bool lookupByPrint = false; if (info->getPUID().length() == 0) { // Lookup by fingerprint if (info->getPrint().length() == 0) return false; if (info->getFormat().length() == 0) return false; if (info->getLengthInMS() == 0) return false; lookupByPrint = true; } // Sloppily estimate the size of the resultant URL. Err on the side of making the string too big. int bufSize = strlen(lookupByPrint ? request_format : request_format2) + info->getClientKey().length() + info->getClientVersion().length() + (lookupByPrint ? info->getPrint().length() : info->getPUID().length()) + 16 + // info->getMetadataFlag() ? 1 : 0, 16 + // info->getBitrate(), 16 + //info->getFormat().c_str(), 16 + //info->getLengthInMS(), ((info->getArtist().c_str() == 0) ? strlen(unknown) : info->getArtist().length()) + ((info->getTrack().c_str() == 0) ? strlen(unknown) : info->getTrack().length()) + ((info->getAlbum().c_str() == 0) ? strlen(unknown) : info->getAlbum().length()) + 16 + // info->getTrackNum() + ((info->getGenre().c_str() == 0) ? strlen(unknown) : info->getGenre().length()) + ((info->getYear().c_str() == 0) ? 1 : info->getYear().length()) + info->getEncoding().length(); char *buf = new char[bufSize]; sprintf(buf, lookupByPrint ? request_format : request_format2, info->getClientKey().c_str(), info->getClientVersion().c_str(), lookupByPrint ? info->getPrint().c_str() : info->getPUID().c_str(), info->getMetadataFlag() ? 1 : 0, info->getBitrate(), info->getFormat().c_str(), info->getLengthInMS(), (info->getArtist().length() == 0) ? unknown : info->getArtist().c_str(), (info->getTrack().length() == 0) ? unknown : info->getTrack().c_str(), (info->getAlbum().length() == 0) ? unknown : info->getAlbum().c_str(), info->getTrackNum(), (info->getGenre().length() == 0) ? unknown : info->getGenre().c_str(), (info->getYear().length() == 0) ? "0" : info->getYear().c_str(), info->getEncoding().c_str()); //printf("request: %s\n\n", buf); string response; long ret = http_post(url, userAgent, buf, response); delete [] buf; if (ret != 200) { //printf("Error: %ld\n", ret); //printf("response: %s\n\n", response.c_str()); return false; } //printf("response: %s\n\n", response.c_str()); unsigned int q = response.find("setTrack(""); info->setArtist(""); info->setPUID(""); if (parse_xml(response, info, err)) { //printf(" Title: %s\n", info->getTrack().c_str()); //printf("Artist: %s\n", info->getArtist().c_str()); //printf(" PUID: %s\n", info->getPUID().c_str()); } else { //printf("Error: %s\n", err.c_str()); // Clears title if it wasn't returned info->setTrack(""); // Clears artists if it wasn't returned info->setArtist(""); } return true; }