soundcloud upload - initial copy of files from Mixbus.
authorColin Fletcher <colin.m.fletcher@googlemail.com>
Mon, 12 Aug 2013 13:50:37 +0000 (14:50 +0100)
committerColin Fletcher <colin.m.fletcher@googlemail.com>
Mon, 7 Oct 2013 11:23:00 +0000 (12:23 +0100)
gtk2_ardour/soundcloud_export.cc [new file with mode: 0644]
gtk2_ardour/soundcloud_export.h [new file with mode: 0644]

diff --git a/gtk2_ardour/soundcloud_export.cc b/gtk2_ardour/soundcloud_export.cc
new file mode 100644 (file)
index 0000000..e97f6ab
--- /dev/null
@@ -0,0 +1,334 @@
+/* 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
diff --git a/gtk2_ardour/soundcloud_export.h b/gtk2_ardour/soundcloud_export.h
new file mode 100644 (file)
index 0000000..2a5f51f
--- /dev/null
@@ -0,0 +1,47 @@
+/*soundcloud_export.h****************************************************************************\r
+\r
+       Adapted for Ardour by Ben Loftis, March 2012\r
+\r
+*****************************************************************************/\r
+\r
+#include <string>\r
+#include <fstream>\r
+#include <iostream>\r
+#include <stdio.h>\r
+#include <cstring>\r
+#include <string>\r
+#include <sstream>\r
+#include <vector>\r
+#include <gtkmm/progressbar.h>\r
+//#include <ctime>\r
+\r
+#include "curl/curl.h"\r
+\r
+//--- struct to store XML file\r
+struct MemoryStruct {\r
+       char *memory;\r
+       size_t size;\r
+};\r
+\r
+\r
+class SoundcloudUploader\r
+{\r
+public:\r
+       SoundcloudUploader();\r
+       ~SoundcloudUploader();\r
+\r
+       std::string Get_Auth_Token( std::string username, std::string password );\r
+       std::string Upload( std::string file_path, std::string title, std::string auth_token, bool ispublic, curl_progress_callback, void* caller );\r
+\r
+private:\r
+\r
+       void            setcUrlOptions();\r
+\r
+       CURL *curl_handle;\r
+       CURLM *multi_handle;\r
+       char errorBuffer[CURL_ERROR_SIZE];      // storage for cUrl error message\r
+\r
+       std::string basePath;\r
+       std::string xmlLocation;\r
+};\r
+\r