put man pages here at top level
[ardour2.git] / gtk2_ardour / sfdb_freesound_mootcher.cc
blob7daecfc5935f10a740518e04bb76d3f4740aa664
1 /* sfdb_freesound_mootcher.cpp **********************************************************************
3 Adapted for Ardour by Ben Loftis, March 2008
5 Mootcher 23-8-2005
7 Mootcher Online Access to thefreesoundproject website
8 http://freesound.iua.upf.edu/
10 GPL 2005 Jorn Lemon
11 mail for questions/remarks: mootcher@twistedlemon.nl
12 or go to the freesound website forum
14 -----------------------------------------------------------------
16 Includes:
17 curl.h (version 7.14.0)
18 Librarys:
19 libcurl.lib
21 -----------------------------------------------------------------
22 Licence GPL:
24 This program is free software; you can redistribute it and/or
25 modify it under the terms of the GNU General Public License
26 as published by the Free Software Foundation; either version 2
27 of the License, or (at your option) any later version.
29 This program is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 GNU General Public License for more details.
34 You should have received a copy of the GNU General Public License
35 along with this program; if not, write to the Free Software
36 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
39 *************************************************************************************/
40 #include "sfdb_freesound_mootcher.h"
42 #include <pbd/xml++.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
47 #include <ardour/audio_library.h>
49 #define TRUE 1
51 //------------------------------------------------------------------------
52 Mootcher:: Mootcher(const char *saveLocation)
53 : curl( NULL )
54 , connection( 0 )
56 changeWorkingDir(saveLocation);
58 //------------------------------------------------------------------------
59 Mootcher:: ~Mootcher()
61 remove( "cookiejar.txt" );
63 //------------------------------------------------------------------------
64 const char* Mootcher::changeWorkingDir(const char *saveLocation)
66 basePath = saveLocation;
67 #ifdef __WIN32__
68 std::string replace = "/";
69 int pos = (int)basePath.find("\\");
70 while( pos != std::string::npos ){
71 basePath.replace(pos, 1, replace);
72 pos = (int)basePath.find("\\");
74 #endif
75 //
76 int pos2 = basePath.find_last_of("/");
77 if(basePath.length() != (pos2+1)) basePath += "/";
79 // create Freesound directory and sound dir
80 std::string sndLocation = basePath;
81 mkdir(sndLocation.c_str(), 0777);
82 sndLocation += "snd";
83 mkdir(sndLocation.c_str(), 0777);
85 return basePath.c_str();
88 //------------------------------------------------------------------------
89 size_t Mootcher::WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
91 register int realsize = (int)(size * nmemb);
92 struct MemoryStruct *mem = (struct MemoryStruct *)data;
94 // There might be a realloc() out there that doesn't like
95 // reallocing NULL pointers, so we take care of it here
96 if(mem->memory) mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
97 else mem->memory = (char *)malloc(mem->size + realsize + 1);
99 if (mem->memory) {
100 memcpy(&(mem->memory[mem->size]), ptr, realsize);
101 mem->size += realsize;
102 mem->memory[mem->size] = 0;
104 return realsize;
108 //------------------------------------------------------------------------
109 void Mootcher::toLog(std::string input)
111 printf("%s\n", input.c_str());// for debugging
115 //------------------------------------------------------------------------
116 void Mootcher::setcUrlOptions()
118 // basic init for curl
119 curl_global_init(CURL_GLOBAL_ALL);
120 // some servers don't like requests that are made without a user-agent field, so we provide one
121 curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
122 // setup curl error buffer
123 CURLcode res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
124 // always use the cookie with session id which is received at the login
125 curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookiejar.txt");
126 // Allow redirection
127 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
130 //------------------------------------------------------------------------
131 int Mootcher::doLogin(std::string login, std::string password)
133 if(connection==1)
134 return 1;
136 struct MemoryStruct xml_page;
137 xml_page.memory = NULL;
138 xml_page.size = 0;
140 // create the post message from the login and password
141 std::string postMessage;
142 postMessage += "username=";
143 postMessage += curl_escape(login.c_str(), 0);
144 postMessage += "&password=";
145 postMessage += curl_escape(password.c_str(), 0);
146 postMessage += "&login=";
147 postMessage += curl_escape("1", 0);
148 postMessage += "&redirect=";
149 postMessage += curl_escape("../tests/login.php", 0);
151 // Do the setup for libcurl
152 curl = curl_easy_init();
154 if(curl)
156 setcUrlOptions();
157 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
158 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&xml_page);
159 // save the sessoin id that is given back by the server in a cookie
160 curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookiejar.txt");
161 // use POST for login variables
162 curl_easy_setopt(curl, CURLOPT_POST, TRUE);
163 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postMessage.c_str());
164 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1);
166 // the url to get
167 std::string login_url = "http://www.freesound.org/forum/login.php";
168 curl_easy_setopt(curl, CURLOPT_URL, login_url.c_str() );
170 // perform online request
171 connection = 1;
172 CURLcode res = curl_easy_perform(curl);
173 if( res != 0 ) {
174 toLog("curl login error\n");
175 toLog(curl_easy_strerror(res));
176 connection = 0;
179 if (connection == 1){
180 std::string check_page = xml_page.memory;
181 int test = (int)check_page.find("login"); //logged
182 if( strcmp(xml_page.memory, "login") == 0 )
183 toLog("Logged in.\n");
184 else {
185 toLog("Login failed: Check username and password.\n");
186 connection = 0;
190 // free the memory
191 if(xml_page.memory){
192 free( xml_page.memory );
193 xml_page.memory = NULL;
194 xml_page.size = 0;
197 std::cerr << "Login was cool, connection = " << connection << std::endl;
198 return connection;
200 else return 3; // will be returned if a curl related problem ocurrs
202 //------------------------------------------------------------------------
203 std::string Mootcher::searchText(std::string word)
205 struct MemoryStruct xml_page;
206 xml_page.memory = NULL;
207 xml_page.size = 0;
209 std::string result;
211 if(connection != 0)
213 // create a url encoded post message
214 std::string postMessage;
215 char tempString[ 128 ];
216 char *tempPointer = &tempString[0];
218 postMessage = "search=";
219 postMessage += curl_escape(word.c_str(), 0);
220 sprintf( tempPointer, "&searchDescriptions=1");
221 postMessage += tempPointer;
222 sprintf( tempPointer, "&searchtags=1");
223 postMessage += tempPointer;
225 if(curl)
227 // basic init for curl
228 setcUrlOptions();
229 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
230 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&xml_page);
231 // setup the post message
232 curl_easy_setopt(curl, CURLOPT_POST, TRUE);
233 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postMessage.c_str());
234 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1);
236 // the url to get
237 std::string search_url = "http://www.freesound.org/searchTextXML.php";
238 curl_easy_setopt(curl, CURLOPT_URL, search_url.c_str());
240 // perform the online search
241 connection = 1;
242 CURLcode res = curl_easy_perform(curl);
243 if( res != 0 ) {
244 toLog("curl login error\n");
245 toLog(curl_easy_strerror(res));
246 connection = 0;
249 result = xml_page.memory;
250 toLog( result.c_str() );
252 // free the memory
253 if(xml_page.memory){
254 free( xml_page.memory );
255 xml_page.memory = NULL;
256 xml_page.size = 0;
262 return result;
265 //------------------------------------------------------------------------
266 std::string Mootcher::changeExtension(std::string filename)
268 std::string aiff = ".aiff";
269 std::string aif = ".aif";
270 std::string wav = ".wav";
271 std::string mp3 = ".mp3";
272 std::string ogg = ".ogg";
273 std::string flac = ".flac";
275 std::string replace = ".xml";
276 int pos = 0;
278 pos = (int)filename.find(aiff);
279 if(pos != std::string::npos) filename.replace(pos, aiff.size(), replace);
280 pos = (int)filename.find(aif);
281 if(pos != std::string::npos) filename.replace(pos, aif.size(), replace);
282 pos = (int)filename.find(wav);
283 if(pos != std::string::npos) filename.replace(pos, wav.size(), replace);
284 pos = (int)filename.find(mp3);
285 if(pos != std::string::npos) filename.replace(pos, mp3.size(), replace);
286 pos = (int)filename.find(ogg);
287 if(pos != std::string::npos) filename.replace(pos, ogg.size(), replace);
288 pos = (int)filename.find(flac);
289 if(pos != std::string::npos) filename.replace(pos, flac.size(), replace);
291 return filename;
293 //------------------------------------------------------------------------
294 void Mootcher::GetXml(std::string ID, struct MemoryStruct &xml_page)
297 if(curl) {
298 setcUrlOptions();
299 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
300 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&xml_page);
302 // URL to get
303 std::string getxml_url = "http://www.freesound.org/samplesViewSingleXML.php?id=";
304 getxml_url += ID;
306 curl_easy_setopt(curl, CURLOPT_URL, getxml_url.c_str() );
308 // get it!
309 connection = 1;
310 CURLcode res = curl_easy_perform(curl);
311 if( res != 0 ) {
312 toLog("curl login error\n");
313 toLog(curl_easy_strerror(res));
314 connection = 0;
318 //------------------------------------------------------------------------
319 std::string Mootcher::getXmlFile(std::string ID, int &length)
321 struct MemoryStruct xml_page;
322 xml_page.memory = NULL;
323 xml_page.size = NULL;
325 std::string xmlFileName;
326 std::string audioFileName;
327 std::string filename;
329 if(connection != 0) {
330 // download the xmlfile into xml_page
331 GetXml(ID, xml_page);
333 // if sample ID does not exist on the freesound website
334 if(strcmp(xml_page.memory, "sample non existant") == 0){
335 free( xml_page.memory );
336 sprintf(message, "getXmlFile: sample with ID:%s does not exist!\n", ID.c_str() );
337 toLog(message);
338 return filename;
339 } else {
340 XMLTree doc;
341 doc.read_buffer( xml_page.memory );
342 XMLNode *freesound = doc.root();
344 // if the page is not a valid xml document with a 'freesound' root
345 if( freesound == NULL){
346 sprintf(message, "getXmlFile: There is no valid root in the xml file");
347 toLog(message);
348 } else {
349 XMLNode *sample = freesound->child("sample");
350 XMLNode *name = NULL;
351 XMLNode *filesize = NULL;
352 if (sample) {
353 name = sample->child("originalFilename");
354 filesize = sample->child("filesize");
357 // get the file name and size from xml file
358 if (sample && name && filesize) {
360 audioFileName = name->child("text")->content();
361 sprintf( message, "getXmlFile: %s needs to be downloaded\n", audioFileName.c_str() );
362 toLog(message);
364 length = atoi(filesize->child("text")->content().c_str());
366 // create new filename with the ID number
367 filename = basePath;
368 filename += "snd/";
369 filename += sample->property("id")->value();
370 filename += "-";
371 filename += audioFileName;
372 // change the extention into .xml
373 xmlFileName = changeExtension( filename );
375 sprintf(message, "getXmlFile: saving XML: %s\n", xmlFileName.c_str() );
376 toLog(message);
378 // save the xml file to disk
379 doc.write(xmlFileName.c_str());
381 //store all the tags in the database
382 XMLNode *tags = sample->child("tags");
383 if (tags) {
384 XMLNodeList children = tags->children();
385 XMLNodeConstIterator niter;
386 vector<string> strings;
387 for (niter = children.begin(); niter != children.end(); ++niter) {
388 XMLNode *node = *niter;
389 if( strcmp( node->name().c_str(), "tag") == 0 ) {
390 XMLNode *text = node->child("text");
391 if (text) strings.push_back(text->content());
394 ARDOUR::Library->set_tags (string("//")+filename, strings);
395 ARDOUR::Library->save_changes ();
399 // clear the memory
400 if(xml_page.memory){
401 free( xml_page.memory );
402 xml_page.memory = NULL;
403 xml_page.size = 0;
405 return audioFileName;
409 else {
410 return audioFileName;
415 int audioFileWrite(void *buffer, size_t size, size_t nmemb, void *file)
417 return (int)fwrite(buffer, size, nmemb, (FILE*) file);
420 //------------------------------------------------------------------------
421 std::string Mootcher::getFile(std::string ID)
423 CURLcode result_curl;
425 std::string audioFileName;
427 if(connection != 0)
429 int length;
430 std::string name = getXmlFile(ID, length);
431 if( name != "" ){
433 // create new filename with the ID number
434 audioFileName += basePath;
435 audioFileName += "snd/";
436 audioFileName += ID;
437 audioFileName += "-";
438 audioFileName += name;
440 //check to see if audio file already exists
441 FILE *testFile = fopen(audioFileName.c_str(), "r");
442 if (testFile) { //TODO: should also check length to see if file is complete
443 fseek (testFile , 0 , SEEK_END);
444 if (ftell (testFile) == length) {
445 sprintf(message, "%s already exists\n", audioFileName.c_str() );
446 toLog(message);
447 fclose (testFile);
448 return audioFileName;
449 } else {
450 remove( audioFileName.c_str() ); //file was not correct length, delete it and try again
455 //now download the actual file
456 if (curl) {
458 FILE* theFile;
459 theFile = fopen( audioFileName.c_str(), "wb" );
461 // create the download url, this url will also update the download statics on the site
462 std::string audioURL;
463 audioURL += "http://www.freesound.org/samplesDownload.php?id=";
464 audioURL += ID;
466 setcUrlOptions();
467 curl_easy_setopt(curl, CURLOPT_URL, audioURL.c_str() );
468 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, audioFileWrite);
469 curl_easy_setopt(curl, CURLOPT_WRITEDATA, theFile);
471 connection = 1;
472 CURLcode res = curl_easy_perform(curl);
473 if( res != 0 ) {
474 toLog("curl login error\n");
475 toLog(curl_easy_strerror(res));
476 connection = 0;
479 fclose(theFile);
483 bar.dlnowMoo = 0;
484 bar.dltotalMoo = 0;
485 curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0); // turn on the process bar thingy
486 curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, progress_callback);
487 curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, &bar);
492 return audioFileName;
495 //---------
496 int Mootcher::progress_callback(void *bar, double dltotal, double dlnow, double ultotal, double ulnow)
498 struct dlprocess *lbar = (struct dlprocess *) bar;
499 lbar->dltotalMoo = dltotal;
500 lbar->dlnowMoo = dlnow;
501 return 0;