1 /* sfdb_freesound_mootcher.cpp **********************************************************************
3 Adapted for Ardour by Ben Loftis, March 2008
7 Mootcher Online Access to thefreesoundproject website
8 http://freesound.iua.upf.edu/
11 mail for questions/remarks: mootcher@twistedlemon.nl
12 or go to the freesound website forum
14 -----------------------------------------------------------------
17 curl.h (version 7.14.0)
21 -----------------------------------------------------------------
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>
45 #include <sys/types.h>
47 #include <ardour/audio_library.h>
51 //------------------------------------------------------------------------
52 Mootcher:: Mootcher(const char *saveLocation
)
56 changeWorkingDir(saveLocation
);
58 //------------------------------------------------------------------------
59 Mootcher:: ~Mootcher()
61 remove( "cookiejar.txt" );
63 //------------------------------------------------------------------------
64 const char* Mootcher::changeWorkingDir(const char *saveLocation
)
66 basePath
= saveLocation
;
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("\\");
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);
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);
100 memcpy(&(mem
->memory
[mem
->size
]), ptr
, realsize
);
101 mem
->size
+= realsize
;
102 mem
->memory
[mem
->size
] = 0;
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");
127 curl_easy_setopt(curl
, CURLOPT_FOLLOWLOCATION
, 1);
130 //------------------------------------------------------------------------
131 int Mootcher::doLogin(std::string login
, std::string password
)
136 struct MemoryStruct xml_page
;
137 xml_page
.memory
= NULL
;
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();
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);
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
172 CURLcode res
= curl_easy_perform(curl
);
174 toLog("curl login error\n");
175 toLog(curl_easy_strerror(res
));
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");
185 toLog("Login failed: Check username and password.\n");
192 free( xml_page
.memory
);
193 xml_page
.memory
= NULL
;
197 std::cerr
<< "Login was cool, connection = " << connection
<< std::endl
;
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
;
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
;
227 // basic init for curl
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);
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
242 CURLcode res
= curl_easy_perform(curl
);
244 toLog("curl login error\n");
245 toLog(curl_easy_strerror(res
));
249 result
= xml_page
.memory
;
250 toLog( result
.c_str() );
254 free( xml_page
.memory
);
255 xml_page
.memory
= NULL
;
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";
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
);
293 //------------------------------------------------------------------------
294 void Mootcher::GetXml(std::string ID
, struct MemoryStruct
&xml_page
)
299 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, WriteMemoryCallback
);
300 curl_easy_setopt(curl
, CURLOPT_WRITEDATA
, (void *)&xml_page
);
303 std::string getxml_url
= "http://www.freesound.org/samplesViewSingleXML.php?id=";
306 curl_easy_setopt(curl
, CURLOPT_URL
, getxml_url
.c_str() );
310 CURLcode res
= curl_easy_perform(curl
);
312 toLog("curl login error\n");
313 toLog(curl_easy_strerror(res
));
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() );
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");
349 XMLNode
*sample
= freesound
->child("sample");
350 XMLNode
*name
= NULL
;
351 XMLNode
*filesize
= NULL
;
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() );
364 length
= atoi(filesize
->child("text")->content().c_str());
366 // create new filename with the ID number
369 filename
+= sample
->property("id")->value();
371 filename
+= audioFileName
;
372 // change the extention into .xml
373 xmlFileName
= changeExtension( filename
);
375 sprintf(message
, "getXmlFile: saving XML: %s\n", xmlFileName
.c_str() );
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");
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 ();
401 free( xml_page
.memory
);
402 xml_page
.memory
= NULL
;
405 return audioFileName
;
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
;
430 std::string name
= getXmlFile(ID
, length
);
433 // create new filename with the ID number
434 audioFileName
+= basePath
;
435 audioFileName
+= "snd/";
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() );
448 return audioFileName
;
450 remove( audioFileName
.c_str() ); //file was not correct length, delete it and try again
455 //now download the actual file
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=";
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
);
472 CURLcode res
= curl_easy_perform(curl
);
474 toLog("curl login error\n");
475 toLog(curl_easy_strerror(res
));
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
;
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
;