Freesound fixes for #5853, and a few other small improvements

Add a 'More' button to load the next page of results without clearing the already-found list.
Don't allow cancellation of searches, and don't update progress bar around searches, since we only get one page at a time now.
Show number of pages of results remaining to download in the tooltip of the 'More' button.
Use a new Mootcher object for each request, to avoid bad things happening when clicking in the Freesound search results list while a search or file download is already in progress.
Make the 'Stop' button insensitive except when it will actually stop the download of a sound file.
Only retrieve one page worth of data per search, rather than looping to get all pages.
Don't show an error in the log window if the user cancelled download.
Request 100 items per page, rather than the default 30.
Fix DOS line endings.
This commit is contained in:
Colin Fletcher 2013-03-15 19:59:19 +00:00
parent 8cbb9727e9
commit 2233e91086
4 changed files with 253 additions and 244 deletions

View File

@ -226,6 +226,7 @@ std::string Mootcher::searchText(std::string query, int page, std::string filter
params += "&s=" + sortMethodString(sort);
params += "&fields=id,original_filename,duration,filesize,samplerate,license,serve";
params += "&sounds_per_page=100";
return doRequest("/sounds/search", params);
}
@ -318,12 +319,12 @@ std::string Mootcher::getAudioFile(std::string originalFileName, std::string ID,
return "";
}
//if already canceling a previous download, bail out here ( this can happen b/c getAudioFile gets called by various UI update funcs )
// if already cancelling a previous download, bail out here ( this can happen b/c getAudioFile gets called by various UI update funcs )
if ( caller->freesound_download_cancel ) {
return "";
}
//now download the actual file
// now download the actual file
FILE* theFile;
theFile = g_fopen( audioFileName.c_str(), "wb" );
@ -359,7 +360,10 @@ std::string Mootcher::getAudioFile(std::string originalFileName, std::string ID,
caller->freesound_progress_bar.set_text("");
if( res != 0 ) {
error << string_compose (_("curl error %1 (%2)"), res, curl_easy_strerror(res)) << endmsg;
/* it's not an error if the user pressed the stop button */
if (res != CURLE_ABORTED_BY_CALLBACK) {
error << string_compose (_("curl error %1 (%2)"), res, curl_easy_strerror(res)) << endmsg;
}
remove( audioFileName.c_str() );
return "";
} else {

View File

@ -17,80 +17,80 @@
*/
/*sfdb_freesound_mootcher.h****************************************************************************
Adapted for Ardour by Ben Loftis, March 2008
Updated to new Freesound API by Colin Fletcher, November 2011
Mootcher Online Access to thefreesoundproject website
http://freesound.iua.upf.edu/
GPL 2005 Jorn Lemon
mail for questions/remarks: mootcher@twistedlemon.nl
or go to the freesound website forum
*****************************************************************************/
#include <string>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <string>
#include <sstream>
#include <vector>
#include <gtkmm/progressbar.h>
//#include <ctime>
#include "sfdb_ui.h"
#include "curl/curl.h"
//--- struct to store XML file
struct MemoryStruct {
char *memory;
size_t size;
};
enum sortMethod {
sort_none, // no sort
sort_duration_desc, // Sort by the duration of the sounds, longest sounds first.
sort_duration_asc, // Same as above, but shortest sounds first.
sort_created_desc, // Sort by the date of when the sound was added. newest sounds first.
sort_created_asc, // Same as above, but oldest sounds first.
sort_downloads_desc, // Sort by the number of downloads, most downloaded sounds first.
sort_downloads_asc, // Same as above, but least downloaded sounds first.
sort_rating_desc, // Sort by the average rating given to the sounds, highest rated first.
sort_rating_asc // Same as above, but lowest rated sounds first.
};
class Mootcher
{
public:
Mootcher();
~Mootcher();
std::string getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, SoundFileBrowser *caller);
std::string searchText(std::string query, int page, std::string filter, enum sortMethod sort);
private:
void changeWorkingDir(const char *saveLocation);
void ensureWorkingDir();
std::string doRequest(std::string uri, std::string params);
void setcUrlOptions();
static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data);
static int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
std::string sortMethodString(enum sortMethod sort);
std::string getSoundResourceFile(std::string ID);
CURL *curl;
char errorBuffer[CURL_ERROR_SIZE]; // storage for cUrl error message
std::string basePath;
std::string xmlLocation;
};
/*sfdb_freesound_mootcher.h****************************************************************************
Adapted for Ardour by Ben Loftis, March 2008
Updated to new Freesound API by Colin Fletcher, November 2011
Mootcher Online Access to thefreesoundproject website
http://freesound.iua.upf.edu/
GPL 2005 Jorn Lemon
mail for questions/remarks: mootcher@twistedlemon.nl
or go to the freesound website forum
*****************************************************************************/
#include <string>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <string>
#include <sstream>
#include <vector>
#include <gtkmm/progressbar.h>
//#include <ctime>
#include "sfdb_ui.h"
#include "curl/curl.h"
//--- struct to store XML file
struct MemoryStruct {
char *memory;
size_t size;
};
enum sortMethod {
sort_none, // no sort
sort_duration_desc, // Sort by the duration of the sounds, longest sounds first.
sort_duration_asc, // Same as above, but shortest sounds first.
sort_created_desc, // Sort by the date of when the sound was added. newest sounds first.
sort_created_asc, // Same as above, but oldest sounds first.
sort_downloads_desc, // Sort by the number of downloads, most downloaded sounds first.
sort_downloads_asc, // Same as above, but least downloaded sounds first.
sort_rating_desc, // Sort by the average rating given to the sounds, highest rated first.
sort_rating_asc // Same as above, but lowest rated sounds first.
};
class Mootcher
{
public:
Mootcher();
~Mootcher();
std::string getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, SoundFileBrowser *caller);
std::string searchText(std::string query, int page, std::string filter, enum sortMethod sort);
private:
void changeWorkingDir(const char *saveLocation);
void ensureWorkingDir();
std::string doRequest(std::string uri, std::string params);
void setcUrlOptions();
static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data);
static int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
std::string sortMethodString(enum sortMethod sort);
std::string getSoundResourceFile(std::string ID);
CURL *curl;
char errorBuffer[CURL_ERROR_SIZE]; // storage for cUrl error message
std::string basePath;
std::string xmlLocation;
};

View File

@ -520,8 +520,6 @@ SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persi
//add freesound search
mootcher = new Mootcher();
HBox* passbox;
Label* label;
@ -553,8 +551,13 @@ SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persi
freesound_sort.set_active(0);
passbox->pack_start (freesound_search_btn, false, false);
passbox->pack_start (freesound_more_btn, false, false);
freesound_more_btn.set_label(_("More"));
freesound_more_btn.set_sensitive(false);
passbox->pack_end (freesound_stop_btn, false, false);
freesound_stop_btn.set_label(_("Stop"));
freesound_stop_btn.set_sensitive(false);
scroll = manage(new ScrolledWindow);
scroll->add(freesound_list_view);
@ -586,6 +589,7 @@ SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persi
freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
freesound_more_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_more_clicked));
freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
notebook.append_page (*vbox, _("Search Freesound"));
#endif
@ -802,12 +806,13 @@ void
SoundFileBrowser::freesound_list_view_selected ()
{
freesound_download_cancel = false;
freesound_stop_btn.set_sensitive(true);
#ifdef FREESOUND
if (!reset_options ()) {
set_action_sensitive (false);
} else {
Mootcher mootcher;
string file;
TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
@ -825,7 +830,7 @@ SoundFileBrowser::freesound_list_view_selected ()
gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
gdk_flush();
file = mootcher->getAudioFile(ofn, id, uri, this);
file = mootcher.getAudioFile(ofn, id, uri, this);
gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
@ -843,6 +848,7 @@ SoundFileBrowser::freesound_list_view_selected ()
preview.setup_labels (file);
}
#endif
freesound_stop_btn.set_sensitive(false);
}
void
@ -872,15 +878,26 @@ SoundFileBrowser::found_search_clicked ()
void
SoundFileBrowser::freesound_search_clicked ()
{
freesound_search_cancel = false;
freesound_page = 1;
freesound_list->clear();
matches = 0;
freesound_search();
}
void
SoundFileBrowser::freesound_more_clicked ()
{
char row_path[21];
freesound_page++;
freesound_search();
snprintf(row_path, 21, "%d", (freesound_page - 1) * 100);
freesound_list_view.scroll_to_row(Gtk::TreePath(row_path), 0);
}
void
SoundFileBrowser::freesound_stop_clicked ()
{
freesound_download_cancel = true;
freesound_search_cancel = true;
}
@ -888,9 +905,8 @@ void
SoundFileBrowser::freesound_search()
{
#ifdef FREESOUND
freesound_list->clear();
Mootcher mootcher;
freesound_list_view.get_column(1)->set_sizing(TREE_VIEW_COLUMN_GROW_ONLY);
matches = 0;
string search_string = freesound_entry.get_text ();
enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
@ -901,164 +917,155 @@ SoundFileBrowser::freesound_search()
freesound_progress_bar.set_fraction(0.0);
gdk_flush();
int freesound_n_pages = 1;
for (int page = 1; page <= 99 && page <= freesound_n_pages; page++ ) {
std::string prog;
if (freesound_n_pages > 1) {
freesound_progress_bar.set_fraction(page/(float)freesound_n_pages);
prog = string_compose (_("Searching Page %1 of %2, click Stop to cancel"), page, freesound_n_pages);
} else {
prog = _("Searching, click Stop to cancel");
}
freesound_progress_bar.set_text(prog);
while (Glib::MainContext::get_default()->iteration (false)) {
/* do nothing */
}
std::string theString = mootcher->searchText(
std::string theString = mootcher.searchText(
search_string,
page,
freesound_page,
#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",
#endif
sort_method
);
XMLTree doc;
doc.read_buffer( theString );
XMLNode *root = doc.root();
if (!root) {
error << "no root XML node!" << endmsg;
break;
}
if ( strcmp(root->name().c_str(), "response") != 0) {
error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
break;
}
//find out how many pages are available to search
XMLNode *res = root->child("num_pages");
if (res) {
string result = res->child("text")->content();
freesound_n_pages = atoi(result.c_str());
}
XMLNode *sounds_root = root->child("sounds");
if (!sounds_root) {
error << "no child node \"sounds\" found!" << endmsg;
break;
}
XMLNodeList sounds = sounds_root->children();
if (sounds.size() == 0) {
/* nothing found */
break;
}
XMLNodeConstIterator niter;
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;
freesound_search_cancel = true;
break;
}
// node->dump(cerr, "node:");
XMLNode *id_node = node->child ("id");
XMLNode *uri_node = node->child ("serve");
XMLNode *ofn_node = node->child ("original_filename");
XMLNode *dur_node = node->child ("duration");
XMLNode *siz_node = node->child ("filesize");
XMLNode *srt_node = node->child ("samplerate");
XMLNode *lic_node = node->child ("license");
if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
std::string id = id_node->child("text")->content();
std::string uri = uri_node->child("text")->content();
std::string ofn = ofn_node->child("text")->content();
std::string dur = dur_node->child("text")->content();
std::string siz = siz_node->child("text")->content();
std::string srt = srt_node->child("text")->content();
std::string lic = lic_node->child("text")->content();
std::string r;
// cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
double duration_seconds = atof(dur.c_str());
double h, m, s;
char duration_hhmmss[16];
if (duration_seconds >= 99 * 60 * 60) {
strcpy(duration_hhmmss, ">99h");
} else {
s = modf(duration_seconds/60, &m) * 60;
m = modf(m/60, &h) * 60;
sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
h, m, s
);
}
double size_bytes = atof(siz.c_str());
char bsize[32];
if (size_bytes < 1000) {
sprintf(bsize, "%.0f %s", size_bytes, _("B"));
} else if (size_bytes < 1000000 ) {
sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
} else if (size_bytes < 10000000) {
sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
} else if (size_bytes < 1000000000) {
sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
} else {
sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
}
/* see http://www.freesound.org/help/faq/#licenses */
char shortlicense[64];
if(!lic.compare(0, 42, "http://creativecommons.org/licenses/by-nc/")){
sprintf(shortlicense, "CC-BY-NC");
} else if(!lic.compare(0, 39, "http://creativecommons.org/licenses/by/")) {
sprintf(shortlicense, "CC-BY");
} else if(!lic.compare("http://creativecommons.org/licenses/sampling+/1.0/")) {
sprintf(shortlicense, "sampling+");
} else if(!lic.compare(0, 40, "http://creativecommons.org/publicdomain/")) {
sprintf(shortlicense, "PD");
} else {
snprintf(shortlicense, 64, "%s", lic.c_str());
shortlicense[63]= '\0';
}
TreeModel::iterator new_row = freesound_list->append();
TreeModel::Row row = *new_row;
row[freesound_list_columns.id ] = id;
row[freesound_list_columns.uri ] = uri;
row[freesound_list_columns.filename] = ofn;
row[freesound_list_columns.duration] = duration_hhmmss;
row[freesound_list_columns.filesize] = bsize;
row[freesound_list_columns.smplrate] = srt;
row[freesound_list_columns.license ] = shortlicense;
matches++;
}
}
if (freesound_search_cancel)
break;
} //page "for" loop
);
gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
freesound_progress_bar.set_fraction(0.0);
XMLTree doc;
doc.read_buffer( theString );
XMLNode *root = doc.root();
if (!root) {
error << "no root XML node!" << endmsg;
return;
}
if ( strcmp(root->name().c_str(), "response") != 0) {
error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
return;
}
// find out how many pages are available to search
int freesound_n_pages = 1;
XMLNode *res = root->child("num_pages");
if (res) {
string result = res->child("text")->content();
freesound_n_pages = atoi(result.c_str());
}
int more_pages = freesound_n_pages - freesound_page;
if (more_pages > 0) {
freesound_more_btn.set_sensitive(true);
freesound_more_btn.set_tooltip_text(string_compose(P_(
"%1 more page of 100 results available",
"%1 more pages of 100 results available",
more_pages), more_pages));
} else {
freesound_more_btn.set_sensitive(false);
freesound_more_btn.set_tooltip_text(_("No more results available"));
}
XMLNode *sounds_root = root->child("sounds");
if (!sounds_root) {
error << "no child node \"sounds\" found!" << endmsg;
return;
}
XMLNodeList sounds = sounds_root->children();
if (sounds.size() == 0) {
/* nothing found */
return;
}
XMLNodeConstIterator niter;
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;
break;
}
// node->dump(cerr, "node:");
XMLNode *id_node = node->child ("id");
XMLNode *uri_node = node->child ("serve");
XMLNode *ofn_node = node->child ("original_filename");
XMLNode *dur_node = node->child ("duration");
XMLNode *siz_node = node->child ("filesize");
XMLNode *srt_node = node->child ("samplerate");
XMLNode *lic_node = node->child ("license");
if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
std::string id = id_node->child("text")->content();
std::string uri = uri_node->child("text")->content();
std::string ofn = ofn_node->child("text")->content();
std::string dur = dur_node->child("text")->content();
std::string siz = siz_node->child("text")->content();
std::string srt = srt_node->child("text")->content();
std::string lic = lic_node->child("text")->content();
std::string r;
// cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
double duration_seconds = atof(dur.c_str());
double h, m, s;
char duration_hhmmss[16];
if (duration_seconds >= 99 * 60 * 60) {
strcpy(duration_hhmmss, ">99h");
} else {
s = modf(duration_seconds/60, &m) * 60;
m = modf(m/60, &h) * 60;
sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
h, m, s
);
}
double size_bytes = atof(siz.c_str());
char bsize[32];
if (size_bytes < 1000) {
sprintf(bsize, "%.0f %s", size_bytes, _("B"));
} else if (size_bytes < 1000000 ) {
sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
} else if (size_bytes < 10000000) {
sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
} else if (size_bytes < 1000000000) {
sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
} else {
sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
}
/* see http://www.freesound.org/help/faq/#licenses */
char shortlicense[64];
if(!lic.compare(0, 42, "http://creativecommons.org/licenses/by-nc/")){
sprintf(shortlicense, "CC-BY-NC");
} else if(!lic.compare(0, 39, "http://creativecommons.org/licenses/by/")) {
sprintf(shortlicense, "CC-BY");
} else if(!lic.compare("http://creativecommons.org/licenses/sampling+/1.0/")) {
sprintf(shortlicense, "sampling+");
} else if(!lic.compare(0, 40, "http://creativecommons.org/publicdomain/")) {
sprintf(shortlicense, "PD");
} else {
snprintf(shortlicense, 64, "%s", lic.c_str());
shortlicense[63]= '\0';
}
TreeModel::iterator new_row = freesound_list->append();
TreeModel::Row row = *new_row;
row[freesound_list_columns.id ] = id;
row[freesound_list_columns.uri ] = uri;
row[freesound_list_columns.filename] = ofn;
row[freesound_list_columns.duration] = duration_hhmmss;
row[freesound_list_columns.filesize] = bsize;
row[freesound_list_columns.smplrate] = srt;
row[freesound_list_columns.license ] = shortlicense;
matches++;
}
}
if (matches == 0) {
freesound_progress_bar.set_text(_("Search returned no results."));
} else {
@ -1100,6 +1107,7 @@ SoundFileBrowser::get_paths ()
} else {
#ifdef FREESOUND
typedef TreeView::Selection::ListHandle_Path ListPath;
Mootcher mootcher;
ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
@ -1113,7 +1121,7 @@ SoundFileBrowser::get_paths ()
gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
gdk_flush();
string str = mootcher->getAudioFile(ofn, id, uri, this);
string str = mootcher.getAudioFile(ofn, id, uri, this);
if (str != "") {
results.push_back (str);
}

View File

@ -149,6 +149,7 @@ class SoundFileBrowser : public ArdourWindow
FreesoundColumns freesound_list_columns;
Glib::RefPtr<Gtk::ListStore> freesound_list;
Gtk::Button freesound_more_btn;
Gtk::Button freesound_stop_btn;
public:
@ -173,21 +174,15 @@ class SoundFileBrowser : public ArdourWindow
Gtk::Entry freesound_entry;
Gtk::ComboBoxText freesound_sort;
Gtk::SpinButton freesound_page;
Gtk::Button freesound_search_btn;
Gtk::TreeView freesound_list_view;
Gtk::ProgressBar freesound_progress_bar;
bool freesound_search_cancel;
bool freesound_download_cancel;
void freesound_search();
#ifdef FREESOUND
Mootcher *mootcher;
#endif
protected:
bool resetting_ourselves;
int matches;
@ -228,7 +223,9 @@ class SoundFileBrowser : public ArdourWindow
void freesound_list_view_selected ();
void freesound_list_view_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn*);
void freesound_search_clicked ();
void freesound_more_clicked ();
void freesound_stop_clicked ();
int freesound_page;
void chooser_file_activated ();