From c4eb943e685140bebc0f3956f141a3976d954135 Mon Sep 17 00:00:00 2001
From: Colin Fletcher <colin.m.fletcher@googlemail.com>
Date: Mon, 18 Jan 2016 18:38:12 +0000
Subject: [PATCH 2/4] Update to Freesound API v2 (search only)

Update the Freesound mootcher to use the new APIv2. Mostly working, except
that the actual download of the original file fails, because Freesound now
require OAuth authorisation for downloading, which I haven't yet implemented.
---
 gtk2_ardour/sfdb_freesound_mootcher.cc | 64 +++++++++++++++++++++++-----------
 gtk2_ardour/sfdb_freesound_mootcher.h  |  3 +-
 gtk2_ardour/sfdb_ui.cc                 | 22 ++++++------
 3 files changed, 58 insertions(+), 31 deletions(-)

diff --git a/gtk2_ardour/sfdb_freesound_mootcher.cc b/gtk2_ardour/sfdb_freesound_mootcher.cc
index 94e0058..3a24958 100644
--- a/gtk2_ardour/sfdb_freesound_mootcher.cc
+++ b/gtk2_ardour/sfdb_freesound_mootcher.cc
@@ -53,19 +53,29 @@
 #include "i18n.h"
 
 #include "ardour/audio_library.h"
+#include "ardour/debug.h"
 #include "ardour/rc_configuration.h"
 #include "pbd/pthread_utils.h"
 #include "gui_thread.h"
 
 using namespace PBD;
 
-static const std::string base_url = "http://www.freesound.org/api";
-static const std::string api_key = "9d77cb8d841b4bcfa960e1aae62224eb"; // ardour3
+static const std::string base_url = "http://www.freesound.org/apiv2";
+static const std::string default_api_key = "b2cc51878bd4fde055e3e84591eb289715d01503"; // Ardour 4
+// Ardour 4 	c7eff9328525c51775cb 	b2cc51878bd4fde055e3e84591eb289715d01503
+
+static const std::string fields = "id,name,duration,filesize,samplerate,license,download";
 
 //------------------------------------------------------------------------
-Mootcher::Mootcher()
+Mootcher::Mootcher(const std::string &the_api_key)
 	: curl(curl_easy_init())
 {
+	DEBUG_TRACE(PBD::DEBUG::Freesound, "Created new Mootcher\n");
+	if  (the_api_key != "") {
+		api_key = the_api_key;
+	} else {
+		api_key = default_api_key;
+	}
 	cancel_download_btn.set_label (_("Cancel"));
 	progress_hbox.pack_start (progress_bar, true, true);
 	progress_hbox.pack_end (cancel_download_btn, false, false);
@@ -77,6 +87,7 @@ Mootcher::Mootcher()
 Mootcher:: ~Mootcher()
 {
 	curl_easy_cleanup(curl);
+	DEBUG_TRACE(PBD::DEBUG::Freesound, "Destroyed Mootcher\n");
 }
 
 //------------------------------------------------------------------------
@@ -85,6 +96,7 @@ void Mootcher::ensureWorkingDir ()
 {
 	std::string p = ARDOUR::Config->get_freesound_download_dir();
 
+	DEBUG_TRACE(PBD::DEBUG::Freesound, "ensureWorkingDir() - " + p + "\n");
 	if (!Glib::file_test (p, Glib::FILE_TEST_IS_DIR)) {
 		if (g_mkdir_with_parents (p.c_str(), 0775) != 0) {
 			PBD::error << "Unable to create Mootcher working dir" << endmsg;
@@ -176,17 +188,21 @@ std::string Mootcher::doRequest(std::string uri, std::string params)
 	// the url to get
 	std::string url = base_url + uri + "?";
 	if (params != "") {
-		url += params + "&api_key=" + api_key + "&format=xml";
+		url += params + "&token=" + api_key + "&format=xml";
 	} else {
-		url += "api_key=" + api_key + "&format=xml";
+		url += "token=" + api_key + "&format=xml";
 	}
 
 	curl_easy_setopt(curl, CURLOPT_URL, url.c_str() );
 
+	DEBUG_TRACE(PBD::DEBUG::Freesound, url + "\n"); 
+
 	// perform online request
 	CURLcode res = curl_easy_perform(curl);
 	if( res != 0 ) {
-		error << string_compose (_("curl error %1 (%2)"), res, curl_easy_strerror(res)) << endmsg;
+		std::string errmsg = string_compose (_("curl error %1 (%2)"), res, curl_easy_strerror(res));
+		error << errmsg << endmsg;
+		DEBUG_TRACE(PBD::DEBUG::Freesound, errmsg + "\n"); 
 		return "";
 	}
 
@@ -199,6 +215,7 @@ std::string Mootcher::doRequest(std::string uri, std::string params)
 	xml_page.memory = NULL;
 	xml_page.size = 0;
 
+	DEBUG_TRACE(PBD::DEBUG::Freesound, result + "\n");
 	return result;
 }
 
@@ -207,10 +224,12 @@ std::string Mootcher::searchSimilar(std::string id)
 {
 	std::string params = "";
 
-	params += "&fields=id,original_filename,duration,filesize,samplerate,license,serve";
+	params += "&fields=" + fields;
 	params += "&num_results=100";
+	// XXX should we filter out MP3s here, too?
+	// XXX and what if there are more than 100 similar sounds?
 
-	return doRequest("/sounds/" + id + "/similar", params);
+	return doRequest("/sounds/" + id + "/similar/", params);
 }
 
 //------------------------------------------------------------------------
@@ -221,27 +240,27 @@ std::string Mootcher::searchText(std::string query, int page, std::string filter
 	char buf[24];
 
 	if (page > 1) {
-		snprintf(buf, 23, "p=%d&", page);
+		snprintf(buf, 23, "page=%d&", page);
 		params += buf;
 	}
 
 	char *eq = curl_easy_escape(curl, query.c_str(), query.length());
-	params += "q=\"" + std::string(eq) + "\"";
+	params += "query=\"" + std::string(eq) + "\"";
 	free(eq);
 
 	if (filter != "") {
 		char *ef = curl_easy_escape(curl, filter.c_str(), filter.length());
-		params += "&f=" + std::string(ef);
+		params += "&filter=" + std::string(ef);
 		free(ef);
 	}
 
 	if (sort)
-		params += "&s=" + sortMethodString(sort);
+		params += "&sort=" + sortMethodString(sort);
 
-	params += "&fields=id,original_filename,duration,filesize,samplerate,license,serve";
-	params += "&sounds_per_page=100";
+	params += "&fields=" + fields;
+	params += "&page_size=100";
 
-	return doRequest("/sounds/search", params);
+	return doRequest("/search/text/", params);
 }
 
 //------------------------------------------------------------------------
@@ -255,7 +274,7 @@ std::string Mootcher::getSoundResourceFile(std::string ID)
 
 
 	// download the xmlfile into xml_page
-	xml = doRequest("/sounds/" + ID, "");
+	xml = doRequest("/sounds/" + ID + "/", "");
 
 	XMLTree doc;
 	doc.read_buffer( xml.c_str() );
@@ -267,12 +286,12 @@ std::string Mootcher::getSoundResourceFile(std::string ID)
 		return "";
 	}
 
-	if (strcmp(doc.root()->name().c_str(), "response") != 0) {
-		error << string_compose (_("getSoundResourceFile: root = %1, != response"), doc.root()->name()) << endmsg;
+	if (strcmp(doc.root()->name().c_str(), "root") != 0) {
+		error << string_compose (_("getSoundResourceFile: root = %1, != \"root\""), doc.root()->name()) << endmsg;
 		return "";
 	}
 
-	XMLNode *name = freesound->child("original_filename");
+	XMLNode *name = freesound->child("name");
 
 	// get the file name and size from xml file
 	if (name) {
@@ -361,6 +380,7 @@ freesound_download_thread_func(void *arg)
 
 bool Mootcher::checkAudioFile(std::string originalFileName, std::string theID)
 {
+	DEBUG_TRACE(PBD::DEBUG::Freesound, string_compose("checkAudiofile(%1, %2)\n", originalFileName, theID));
 	ensureWorkingDir();
 	ID = theID;
 	audioFileName = Glib::build_filename (basePath, ID + "-" + originalFileName);
@@ -384,6 +404,9 @@ bool Mootcher::checkAudioFile(std::string originalFileName, std::string theID)
 
 bool Mootcher::fetchAudioFile(std::string originalFileName, std::string theID, std::string audioURL, SoundFileBrowser *caller)
 {
+
+	DEBUG_TRACE(PBD::DEBUG::Freesound, string_compose("fetchAudiofile(%1, %2, %3...)\n", originalFileName, theID, audioURL));
+
 	ensureWorkingDir();
 	ID = theID;
 	audioFileName = Glib::build_filename (basePath, ID + "-" + originalFileName);
@@ -395,11 +418,12 @@ bool Mootcher::fetchAudioFile(std::string originalFileName, std::string theID, s
 	theFile = g_fopen( (audioFileName + ".part").c_str(), "wb" );
 
 	if (!theFile) {
+		DEBUG_TRACE(PBD::DEBUG::Freesound, "Can't open file for writing:" + audioFileName + ".part\n");
 		return false;
 	}
 
 	// create the download url
-	audioURL += "?api_key=" + api_key;
+	audioURL += "?token=" + api_key;
 
 	setcUrlOptions();
 	curl_easy_setopt(curl, CURLOPT_URL, audioURL.c_str() );
diff --git a/gtk2_ardour/sfdb_freesound_mootcher.h b/gtk2_ardour/sfdb_freesound_mootcher.h
index 4095cc9..6dfad6c 100644
--- a/gtk2_ardour/sfdb_freesound_mootcher.h
+++ b/gtk2_ardour/sfdb_freesound_mootcher.h
@@ -66,7 +66,7 @@ enum sortMethod {
 class Mootcher: public sigc::trackable, public PBD::ScopedConnectionList
 {
 public:
-	Mootcher();
+	Mootcher(const std::string &api_key = "");
 	~Mootcher();
 
 	bool		checkAudioFile(std::string originalFileName, std::string ID);
@@ -118,5 +118,6 @@ private:
 
 	std::string basePath;
 	std::string xmlLocation;
+	std::string api_key;
 };
 
diff --git a/gtk2_ardour/sfdb_ui.cc b/gtk2_ardour/sfdb_ui.cc
index 4c96172..c61efe0 100644
--- a/gtk2_ardour/sfdb_ui.cc
+++ b/gtk2_ardour/sfdb_ui.cc
@@ -1094,7 +1094,7 @@ SoundFileBrowser::freesound_search()
 #ifdef GTKOSX
 			"", // OSX eats anything incl mp3
 #else
-			"type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
+			"type:(wav OR aiff OR flac OR aif OR ogg OR oga)",
 #endif
 			sort_method
 			);
@@ -1114,14 +1114,14 @@ SoundFileBrowser::handle_freesound_results(std::string theString) {
 		return;
 	}
 
-	if ( strcmp(root->name().c_str(), "response") != 0) {
-		error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
+	if ( strcmp(root->name().c_str(), "root") != 0) {
+		error << string_compose ("root node name == %1 != \"root\"", root->name()) << endmsg;
 		return;
 	}
 
 	// find out how many pages are available to search
 	int freesound_n_pages = 1;
-	XMLNode *res = root->child("num_pages");
+	XMLNode *res = root->child("count");
 	if (res) {
 		string result = res->child("text")->content();
 		freesound_n_pages = atoi(result);
@@ -1140,9 +1140,9 @@ SoundFileBrowser::handle_freesound_results(std::string theString) {
 		freesound_more_btn.set_tooltip_text(_("No more results available"));
 	}
 
-	XMLNode *sounds_root = root->child("sounds");
+	XMLNode *sounds_root = root->child("results");
 	if (!sounds_root) {
-		error << "no child node \"sounds\" found!" << endmsg;
+		error << "no child node \"results\" found!" << endmsg;
 		return;
 	}
 
@@ -1156,8 +1156,8 @@ SoundFileBrowser::handle_freesound_results(std::string theString) {
 	XMLNode *node;
 	for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
 		node = *niter;
-		if( strcmp( node->name().c_str(), "resource") != 0 ) {
-			error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
+		if( strcmp( node->name().c_str(), "list-item") != 0 ) {
+			error << string_compose ("node->name()=%1 != \"list-item\"", node->name()) << endmsg;
 			break;
 		}
 
@@ -1165,8 +1165,8 @@ SoundFileBrowser::handle_freesound_results(std::string theString) {
 
 
 		XMLNode *id_node  = node->child ("id");
-		XMLNode *uri_node = node->child ("serve");
-		XMLNode *ofn_node = node->child ("original_filename");
+		XMLNode *uri_node = node->child ("download");
+		XMLNode *ofn_node = node->child ("name");
 		XMLNode *dur_node = node->child ("duration");
 		XMLNode *siz_node = node->child ("filesize");
 		XMLNode *srt_node = node->child ("samplerate");
@@ -1238,6 +1238,8 @@ SoundFileBrowser::handle_freesound_results(std::string theString) {
 			row[freesound_list_columns.smplrate] = srt;
 			row[freesound_list_columns.license ] = shortlicense;
 			matches++;
+		} else {
+			error << _("Failed to retrieve XML for file") << std::endl;
 		}
 	}
 }
-- 
2.7.0.rc3

