#include "i18n.h"\r
\r
#include "ardour/audio_library.h"\r
+#include "ardour/rc_configuration.h"\r
+#include "pbd/pthread_utils.h"\r
+#include "gui_thread.h"\r
\r
using namespace PBD;\r
\r
Mootcher::Mootcher()\r
: curl(curl_easy_init())\r
{\r
- std::string path;\r
- path = Glib::get_home_dir() + "/Freesound/";\r
- changeWorkingDir ( path.c_str() );\r
+ cancel_download_btn.set_label (_("Cancel"));\r
+ progress_hbox.pack_start (progress_bar, true, true);\r
+ progress_hbox.pack_end (cancel_download_btn, false, false);\r
+ progress_bar.show();\r
+ cancel_download_btn.show();\r
+ cancel_download_btn.signal_clicked().connect(sigc::mem_fun (*this, &Mootcher::cancelDownload));\r
};\r
//------------------------------------------------------------------------\r
Mootcher:: ~Mootcher()\r
}\r
\r
//------------------------------------------------------------------------\r
-void Mootcher::changeWorkingDir(const char *saveLocation)\r
-{\r
- basePath = saveLocation;\r
-#ifdef __WIN32__\r
- std::string replace = "/";\r
- size_t pos = basePath.find("\\");\r
- while( pos != std::string::npos ){\r
- basePath.replace(pos, 1, replace);\r
- pos = basePath.find("\\");\r
- }\r
-#endif\r
- //\r
- size_t pos2 = basePath.find_last_of("/");\r
- if(basePath.length() != (pos2+1)) basePath += "/";\r
-}\r
\r
void Mootcher::ensureWorkingDir ()\r
{\r
- std::string p = Glib::build_filename (basePath, "snd");\r
+ std::string p = ARDOUR::Config->get_freesound_download_dir();\r
\r
if (!Glib::file_test (p, Glib::FILE_TEST_IS_DIR)) {\r
if (g_mkdir_with_parents (p.c_str(), 0775) != 0) {\r
PBD::error << "Unable to create Mootcher working dir" << endmsg;\r
}\r
}\r
+ basePath = p;\r
+#ifdef __WIN32__\r
+ std::string replace = "/";\r
+ size_t pos = basePath.find("\\");\r
+ while( pos != std::string::npos ){\r
+ basePath.replace(pos, 1, replace);\r
+ pos = basePath.find("\\");\r
+ }\r
+#endif\r
}\r
\r
\r
\r
//------------------------------------------------------------------------\r
\r
-std::string Mootcher::sortMethodString(enum sortMethod sort) {\r
+std::string Mootcher::sortMethodString(enum sortMethod sort)\r
+{\r
// given a sort type, returns the string value to be passed to the API to\r
// sort the results in the requested way.\r
\r
}\r
\r
\r
+std::string Mootcher::searchSimilar(std::string id)\r
+{\r
+ std::string params = "";\r
+\r
+ params += "&fields=id,original_filename,duration,filesize,samplerate,license,serve";\r
+ params += "&num_results=100";\r
+\r
+ return doRequest("/sounds/" + id + "/similar", params);\r
+}\r
+\r
+//------------------------------------------------------------------------\r
+\r
std::string Mootcher::searchText(std::string query, int page, std::string filter, enum sortMethod sort)\r
{\r
std::string params = "";\r
params += "&s=" + sortMethodString(sort);\r
\r
params += "&fields=id,original_filename,duration,filesize,samplerate,license,serve";\r
+ params += "&sounds_per_page=100";\r
\r
return doRequest("/sounds/search", params);\r
}\r
// get the file name and size from xml file\r
if (name) {\r
\r
- audioFileName = basePath + "snd/" + ID + "-" + name->child("text")->content();\r
+ audioFileName = Glib::build_filename (basePath, ID + "-" + name->child("text")->content());\r
\r
//store all the tags in the database\r
XMLNode *tags = freesound->child("tags");\r
};\r
\r
//------------------------------------------------------------------------\r
-std::string Mootcher::getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, SoundFileBrowser *caller)\r
+\r
+void *\r
+Mootcher::threadFunc() {\r
+CURLcode res;\r
+\r
+ res = curl_easy_perform (curl);\r
+ fclose (theFile);\r
+ curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1); // turn off the progress bar\r
+ \r
+ if (res != CURLE_OK) {\r
+ /* it's not an error if the user pressed the stop button */\r
+ if (res != CURLE_ABORTED_BY_CALLBACK) {\r
+ error << string_compose (_("curl error %1 (%2)"), res, curl_easy_strerror(res)) << endmsg;\r
+ }\r
+ remove ( (audioFileName+".part").c_str() ); \r
+ } else {\r
+ rename ( (audioFileName+".part").c_str(), audioFileName.c_str() );\r
+ // now download the tags &c.\r
+ getSoundResourceFile(ID);\r
+ }\r
+\r
+ return (void *) res;\r
+}\r
+ \r
+void\r
+Mootcher::doneWithMootcher()\r
+{\r
+\r
+ // update the sound info pane if the selection in the list box is still us \r
+ sfb->refresh_display(ID, audioFileName);\r
+\r
+ delete this; // this should be OK to do as long as Progress and Finished signals are always received in the order in which they are emitted\r
+}\r
+\r
+static void *\r
+freesound_download_thread_func(void *arg) \r
+{ \r
+ Mootcher *thisMootcher = (Mootcher *) arg;\r
+ void *res;\r
+\r
+ // std::cerr << "freesound_download_thread_func(" << arg << ")" << std::endl;\r
+ res = thisMootcher->threadFunc();\r
+\r
+ thisMootcher->Finished(); /* EMIT SIGNAL */\r
+ return res;\r
+}\r
+\r
+\r
+//------------------------------------------------------------------------\r
+\r
+bool Mootcher::checkAudioFile(std::string originalFileName, std::string theID)\r
{\r
ensureWorkingDir();\r
- std::string audioFileName = basePath + "snd/" + ID + "-" + originalFileName;\r
+ ID = theID;\r
+ audioFileName = Glib::build_filename (basePath, ID + "-" + originalFileName);\r
\r
// check to see if audio file already exists\r
FILE *testFile = g_fopen(audioFileName.c_str(), "r");\r
fseek (testFile , 0 , SEEK_END);\r
if (ftell (testFile) > 256) {\r
fclose (testFile);\r
- return audioFileName;\r
+ return true;\r
}\r
\r
- // else file was small, probably an error, delete it and try again\r
+ // else file was small, probably an error, delete it \r
fclose(testFile);\r
remove( audioFileName.c_str() ); \r
}\r
+ return false;\r
+}\r
\r
- if (!curl) {\r
- return "";\r
- }\r
\r
- //if already canceling a previous download, bail out here ( this can happen b/c getAudioFile gets called by various UI update funcs )\r
- if ( caller->freesound_download_cancel ) {\r
- return "";\r
+bool Mootcher::fetchAudioFile(std::string originalFileName, std::string theID, std::string audioURL, SoundFileBrowser *caller)\r
+{\r
+ ensureWorkingDir();\r
+ ID = theID;\r
+ audioFileName = Glib::build_filename (basePath, ID + "-" + originalFileName);\r
+\r
+ if (!curl) {\r
+ return false;\r
}\r
- \r
- //now download the actual file\r
- FILE* theFile;\r
- theFile = g_fopen( audioFileName.c_str(), "wb" );\r
+ // now download the actual file\r
+ theFile = g_fopen( (audioFileName + ".part").c_str(), "wb" );\r
\r
if (!theFile) {\r
- return "";\r
+ return false;\r
}\r
\r
// create the download url\r
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, audioFileWrite);\r
curl_easy_setopt(curl, CURLOPT_WRITEDATA, theFile);\r
\r
- /* hack to get rid of the barber-pole stripes */\r
- caller->freesound_progress_bar.hide();\r
- caller->freesound_progress_bar.show();\r
-\r
std::string prog;\r
prog = string_compose (_("%1"), originalFileName);\r
- caller->freesound_progress_bar.set_text(prog);\r
+ progress_bar.set_text(prog);\r
+\r
+ Gtk::VBox *freesound_vbox = dynamic_cast<Gtk::VBox *> (caller->notebook.get_nth_page(2));\r
+ freesound_vbox->pack_start(progress_hbox, Gtk::PACK_SHRINK);\r
+ progress_hbox.show();\r
+ cancel_download = false;\r
+ sfb = caller;\r
\r
curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0); // turn on the progress bar\r
curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, progress_callback);\r
- curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, caller);\r
+ curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, this);\r
\r
- CURLcode res = curl_easy_perform(curl);\r
- fclose(theFile);\r
+ Progress.connect(*this, invalidator (*this), boost::bind(&Mootcher::updateProgress, this, _1, _2), gui_context());\r
+ Finished.connect(*this, invalidator (*this), boost::bind(&Mootcher::doneWithMootcher, this), gui_context());\r
+ pthread_t freesound_download_thread;\r
+ pthread_create_and_store("freesound_import", &freesound_download_thread, freesound_download_thread_func, this);\r
\r
- curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1); // turn off the progress bar\r
- caller->freesound_progress_bar.set_fraction(0.0);\r
- caller->freesound_progress_bar.set_text("");\r
- \r
- if( res != 0 ) {\r
- error << string_compose (_("curl error %1 (%2)"), res, curl_easy_strerror(res)) << endmsg;\r
- remove( audioFileName.c_str() ); \r
- return "";\r
- } else {\r
- // now download the tags &c.\r
- getSoundResourceFile(ID);\r
- }\r
-\r
- return audioFileName;\r
+ return true;\r
}\r
\r
//---------\r
-int Mootcher::progress_callback(void *caller, double dltotal, double dlnow, double /*ultotal*/, double /*ulnow*/)\r
-{\r
\r
-SoundFileBrowser *sfb = (SoundFileBrowser *) caller;\r
- //XXX I hope it's OK to do GTK things in this callback. Otherwise\r
- // I'll have to do stuff like in interthread_progress_window.\r
- if (sfb->freesound_download_cancel) {\r
- return -1;\r
+void \r
+Mootcher::updateProgress(double dlnow, double dltotal) \r
+{\r
+ if (dltotal > 0) {\r
+ double fraction = dlnow / dltotal;\r
+ // std::cerr << "progress idle: " << progress->bar->get_text() << ". " << progress->dlnow << " / " << progress->dltotal << " = " << fraction << std::endl;\r
+ if (fraction > 1.0) {\r
+ fraction = 1.0;\r
+ } else if (fraction < 0.0) {\r
+ fraction = 0.0;\r
+ }\r
+ progress_bar.set_fraction(fraction);\r
}\r
+}\r
+\r
+int \r
+Mootcher::progress_callback(void *caller, double dltotal, double dlnow, double /*ultotal*/, double /*ulnow*/)\r
+{\r
+ // It may seem curious to pass a pointer to an instance of an object to a static\r
+ // member function, but we can't use a normal member function as a curl progress callback,\r
+ // and we want access to some private members of Mootcher.\r
+\r
+ Mootcher *thisMootcher = (Mootcher *) caller;\r
\r
- \r
- sfb->freesound_progress_bar.set_fraction(dlnow/dltotal);\r
- /* Make sure the progress widget gets updated */\r
- while (Glib::MainContext::get_default()->iteration (false)) {\r
- /* do nothing */\r
+ if (thisMootcher->cancel_download) {\r
+ return -1;\r
}\r
+\r
+ thisMootcher->Progress(dlnow, dltotal); /* EMIT SIGNAL */\r
return 0;\r
}\r
\r