--- /dev/null
+/* soundcloud_export.cpp **********************************************************************\r
+\r
+ Adapted for Ardour by Ben Loftis, March 2012\r
+\r
+ Licence GPL:\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+\r
+\r
+*************************************************************************************/\r
+#include "soundcloud_export.h"\r
+\r
+#include "pbd/xml++.h"\r
+#include <pbd/error.h>\r
+//#include "pbd/filesystem.h"\r
+\r
+#include <sys/stat.h>\r
+#include <sys/types.h>\r
+#include <iostream>\r
+#include <glib/gstdio.h>\r
+\r
+#include "i18n.h"\r
+\r
+using namespace PBD;\r
+\r
+static const std::string base_url = "http://api.soundcloud.com/tracks/13158665?client_id=";\r
+\r
+size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)\r
+{\r
+ register int realsize = (int)(size * nmemb);\r
+ struct MemoryStruct *mem = (struct MemoryStruct *)data;\r
+\r
+ mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);\r
+\r
+ if (mem->memory) {\r
+ memcpy(&(mem->memory[mem->size]), ptr, realsize);\r
+ mem->size += realsize;\r
+ mem->memory[mem->size] = 0;\r
+ }\r
+ return realsize;\r
+}\r
+\r
+SoundcloudUploader::SoundcloudUploader()\r
+{\r
+ curl_handle = curl_easy_init();\r
+ multi_handle = curl_multi_init();\r
+}\r
+\r
+string\r
+SoundcloudUploader::Get_Auth_Token( string username, string password )\r
+{\r
+ struct MemoryStruct xml_page;\r
+ xml_page.memory = NULL;\r
+ xml_page.size = 0;\r
+\r
+ setcUrlOptions();\r
+ \r
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);\r
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &xml_page);\r
+\r
+ struct curl_httppost *formpost=NULL;\r
+ struct curl_httppost *lastptr=NULL;\r
+ \r
+ /* Fill in the filename field */ \r
+ curl_formadd(&formpost,\r
+ &lastptr,\r
+ CURLFORM_COPYNAME, "client_id",\r
+ CURLFORM_COPYCONTENTS, "e7ac891eef866f139773cf8102b7a719",\r
+ CURLFORM_END);\r
+ \r
+ curl_formadd(&formpost,\r
+ &lastptr,\r
+ CURLFORM_COPYNAME, "client_secret",\r
+ CURLFORM_COPYCONTENTS, "d78f34d19f09d26731801a0cb0f382c4",\r
+ CURLFORM_END);\r
+ \r
+ curl_formadd(&formpost,\r
+ &lastptr,\r
+ CURLFORM_COPYNAME, "grant_type",\r
+ CURLFORM_COPYCONTENTS, "password",\r
+ CURLFORM_END);\r
+ \r
+ curl_formadd(&formpost,\r
+ &lastptr,\r
+ CURLFORM_COPYNAME, "username",\r
+ CURLFORM_COPYCONTENTS, username.c_str(),\r
+ CURLFORM_END);\r
+ \r
+ curl_formadd(&formpost,\r
+ &lastptr,\r
+ CURLFORM_COPYNAME, "password",\r
+ CURLFORM_COPYCONTENTS, password.c_str(),\r
+ CURLFORM_END);\r
+ \r
+ struct curl_slist *headerlist=NULL;\r
+ headerlist = curl_slist_append(headerlist, "Expect:");\r
+ headerlist = curl_slist_append(headerlist, "Accept: application/xml");\r
+ curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headerlist);\r
+\r
+ /* what URL that receives this POST */ \r
+ std::string url = "https://api.soundcloud.com/oauth2/token";\r
+ curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());\r
+ curl_easy_setopt(curl_handle, CURLOPT_HTTPPOST, formpost);\r
+\r
+ curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);\r
+\r
+ // perform online request\r
+ CURLcode res = curl_easy_perform(curl_handle);\r
+ if( res != 0 ) {\r
+ std::cerr << "curl error " << res << " (" << curl_easy_strerror(res) << ")" << std::endl;\r
+ return "";\r
+ }\r
+\r
+ if(xml_page.memory){\r
+ //cheesy way to parse the json return value. find access_token, then advance 3 quotes\r
+\r
+ if ( strstr ( xml_page.memory , "access_token" ) == NULL) {\r
+ error << _("Upload to Soundcloud failed. Perhaps your email or password are incorrect?\n") << endmsg;\r
+ return "";\r
+ }\r
+ \r
+ string token = strtok( xml_page.memory, "access_token" );\r
+ token = strtok( NULL, "\"" );\r
+ token = strtok( NULL, "\"" );\r
+ token = strtok( NULL, "\"" );\r
+\r
+ free( xml_page.memory );\r
+ return token;\r
+ }\r
+\r
+ return "";\r
+}\r
+\r
+std::string\r
+SoundcloudUploader::Upload(string file_path, string title, string auth_token, bool ispublic, curl_progress_callback progress_callback, void *caller )\r
+{\r
+ int still_running;\r
+ \r
+ struct MemoryStruct xml_page;\r
+ xml_page.memory = NULL;\r
+ xml_page.size = 0;\r
+\r
+ setcUrlOptions();\r
+ \r
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);\r
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &xml_page);\r
+\r
+ struct curl_httppost *formpost=NULL;\r
+ struct curl_httppost *lastptr=NULL;\r
+ \r
+ /* Fill in the file upload field. This makes libcurl load data from\r
+ the given file name when curl_easy_perform() is called. */ \r
+ curl_formadd(&formpost,\r
+ &lastptr,\r
+ CURLFORM_COPYNAME, "track[asset_data]",\r
+ CURLFORM_FILE, file_path.c_str(),\r
+ CURLFORM_END);\r
+ \r
+ /* Fill in the filename field */ \r
+ curl_formadd(&formpost,\r
+ &lastptr,\r
+ CURLFORM_COPYNAME, "oauth_token",\r
+ CURLFORM_COPYCONTENTS, auth_token.c_str(),\r
+ CURLFORM_END);\r
+ \r
+ curl_formadd(&formpost,\r
+ &lastptr,\r
+ CURLFORM_COPYNAME, "track[title]",\r
+ CURLFORM_COPYCONTENTS, title.c_str(),\r
+ CURLFORM_END);\r
+ \r
+ curl_formadd(&formpost,\r
+ &lastptr,\r
+ CURLFORM_COPYNAME, "track[sharing]",\r
+ CURLFORM_COPYCONTENTS, ispublic ? "public" : "private",\r
+ CURLFORM_END);\r
+ \r
+ /* initalize custom header list (stating that Expect: 100-continue is not\r
+ wanted */ \r
+ struct curl_slist *headerlist=NULL;\r
+ static const char buf[] = "Expect:";\r
+ headerlist = curl_slist_append(headerlist, buf);\r
+ \r
+ \r
+ if(curl_handle && multi_handle) {\r
+ \r
+ /* what URL that receives this POST */ \r
+ string url = "https://api.soundcloud.com/tracks";\r
+ curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());\r
+ curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);\r
+ \r
+ curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headerlist);\r
+ curl_easy_setopt(curl_handle, CURLOPT_HTTPPOST, formpost);\r
+ \r
+ curl_easy_setopt (curl_handle, CURLOPT_NOPROGRESS, 0); // turn on the progress bar\r
+ curl_easy_setopt (curl_handle, CURLOPT_PROGRESSFUNCTION, progress_callback);\r
+ curl_easy_setopt (curl_handle, CURLOPT_PROGRESSDATA, caller);\r
+\r
+ curl_multi_add_handle(multi_handle, curl_handle);\r
+ \r
+ curl_multi_perform(multi_handle, &still_running);\r
+ \r
+\r
+ while(still_running) {\r
+ struct timeval timeout;\r
+ int rc; /* select() return code */ \r
+ \r
+ fd_set fdread;\r
+ fd_set fdwrite;\r
+ fd_set fdexcep;\r
+ int maxfd = -1;\r
+ \r
+ long curl_timeo = -1;\r
+ \r
+ FD_ZERO(&fdread);\r
+ FD_ZERO(&fdwrite);\r
+ FD_ZERO(&fdexcep);\r
+ \r
+ /* set a suitable timeout to play around with */ \r
+ timeout.tv_sec = 1;\r
+ timeout.tv_usec = 0;\r
+ \r
+ curl_multi_timeout(multi_handle, &curl_timeo);\r
+ if(curl_timeo >= 0) {\r
+ timeout.tv_sec = curl_timeo / 1000;\r
+ if(timeout.tv_sec > 1)\r
+ timeout.tv_sec = 1;\r
+ else\r
+ timeout.tv_usec = (curl_timeo % 1000) * 1000;\r
+ }\r
+ \r
+ /* get file descriptors from the transfers */ \r
+ curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);\r
+ \r
+ /* In a real-world program you OF COURSE check the return code of the\r
+ function calls. On success, the value of maxfd is guaranteed to be\r
+ greater or equal than -1. We call select(maxfd + 1, ...), specially in\r
+ case of (maxfd == -1), we call select(0, ...), which is basically equal\r
+ to sleep. */ \r
+ \r
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);\r
+ \r
+ switch(rc) {\r
+ case -1:\r
+ /* select error */ \r
+ break;\r
+ case 0:\r
+ default:\r
+ /* timeout or readable/writable sockets */ \r
+ curl_multi_perform(multi_handle, &still_running);\r
+ break;\r
+ }\r
+ } \r
+ \r
+ /* then cleanup the formpost chain */ \r
+ curl_formfree(formpost);\r
+ \r
+ /* free slist */ \r
+ curl_slist_free_all (headerlist);\r
+ }\r
+ \r
+ curl_easy_setopt (curl_handle, CURLOPT_NOPROGRESS, 1); // turn off the progress bar\r
+\r
+ if(xml_page.memory){\r
+\r
+std::cout << xml_page.memory << std::endl;\r
+\r
+ XMLTree doc;\r
+ doc.read_buffer( xml_page.memory );\r
+ XMLNode *root = doc.root();\r
+\r
+ if (!root) {\r
+ std::cout << "no root XML node!" << std::endl;\r
+ return "";\r
+ }\r
+\r
+ XMLNode *url_node = root->child("permalink-url");\r
+ if (!url_node) {\r
+ std::cout << "no child node \"permalink-url\" found!" << std::endl;\r
+ return "";\r
+ }\r
+ \r
+ XMLNode *text_node = url_node->child("text");\r
+ if (!text_node) {\r
+ std::cout << "no text node found!" << std::endl;\r
+ return "";\r
+ }\r
+ \r
+ free( xml_page.memory );\r
+ return text_node->content();\r
+ }\r
+\r
+ return "";\r
+};\r
+\r
+\r
+SoundcloudUploader:: ~SoundcloudUploader()\r
+{\r
+ curl_easy_cleanup(curl_handle);\r
+ curl_multi_cleanup(multi_handle);\r
+}\r
+\r
+\r
+void\r
+SoundcloudUploader::setcUrlOptions()\r
+{\r
+ // basic init for curl\r
+ curl_global_init(CURL_GLOBAL_ALL);\r
+ // some servers don't like requests that are made without a user-agent field, so we provide one\r
+ curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");\r
+ // setup curl error buffer\r
+ curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, errorBuffer);\r
+ // Allow redirection\r
+ curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);\r
+ \r
+ // Allow connections to time out (without using signals)\r
+ curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);\r
+ curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 30);\r
+\r
+ curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);\r
+ curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);\r
+}\r