SoundCloud for Developers

Discover, connect and build

Backstage Blog RSS

  • June 8th, 2015 Announcements API New playlist representations By Erik Michaels-Ober

    Requests for playlists have always included the full track objects contained within. This representation may be convenient for playlists with ten or twenty tracks but can cause problems for playlists that contain hundreds or thousands of tracks. Requesting such large playlists could result in requests that take a long time to respond and that eventually timeout.

    Today, we introduce two new representations for the /playlists resource: compact and id.

    If you add representation=compact to a playlist request, the request will return only the playlist itself, without any of the tracks it contains. This representation may be useful if you're purely interested in data about the playlist itself and not the tracks contained within.

    Alternatively, if you set the representation=id parameter, it will return the playlist along with IDs of the tracks contained within, without all the associated track meta data (artist, artwork, duration, etc.) If necessary, you can then individually fetch additional information about each track by filling those IDs into the /tracks resource. This allows for greater parallelization and can help make your application more responsive when working with large playlists.

    By default, requests for playlists will continue to include all the contained tracks. There is no need to update your application but we encourage you to take advantage of these new, more efficient representations of playlists.

  • May 18th, 2015 Announcements API Apple's June 1 64-bit deadline By Erik Michaels-Ober

    In October 2014, Apple announced that all submissions to the App Store must include 64-bit support by June 1, 2015. The SoundCloud API for Cocoa contains 32-bit dependencies and will not be updated, because it has been discontinued. Anyone using the SoundCloud API for Cocoa will need to will need to migrate away from it if they wish to update their app after June 1.

    To ease this transition we have built a sample app that demonstrates how to authorize a user via OAuth using only built-in Foundation libraries.

    Once an access_token has been obtained via OAuth, you can make GET requests like so:

    let urlSession = NSURLSession.sharedSession()
    let urlString = "https://api.soundcloud.com/me"
    let urlComponents = NSURLComponents(string: urlString)!
    urlComponents.queryItems = [ NSURLQueryItem(name: "oauth_token", value: "insert an OAuth token here")]
    let url = urlComponents.URL!
    
    let dataTask = urlSession.dataTaskWithRequest(NSURLRequest(URL: url)) { (data, response, error) -> Void in
       if let jsonOutput = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as? [String:AnyObject] {
           // do stuff with JSON
       }
    }
    
    dataTask.resume()
    

    POST requests that contain multipart data (e.g. uploading a track) look like this:

    import UIKit
    
    class ViewController: UIViewController {
        func uploadTrack(title: String, trackPath: String) {
            let urlSession = NSURLSession.sharedSession()
            let urlRequest = getURLRequest(title, audioPath: trackPath)
            let task = urlSession.dataTaskWithRequest(urlRequest) { (data, response, error) -> Void in
                if let httpResponse = response as? NSHTTPURLResponse {
                    println("returned \(httpResponse.statusCode)")
                }
                if data != nil, let response = NSString(data: data, encoding: NSUTF8StringEncoding) {
                    println(response)
                }
                if let err = error {
                    println(err)
                }
            }
            task.resume()
        }
    
        func getURLRequest(title: String, audioPath: String) -> NSURLRequest {
            let boundary = NSUUID().UUIDString
            let request = NSMutableURLRequest(URL: NSURL(string: "https://api.soundcloud.com/tracks")!)
            request.HTTPMethod = "POST"
            request.HTTPBody = getPostData("insert an OAuth token here", boundary: boundary, title: title, audioPath: audioPath)
            let contentType = "multipart/form-data; boundary=" + boundary
            request.setValue(contentType, forHTTPHeaderField: "Content-Type")
            return request
        }
    
        func getPostData(token: String, boundary: String, title: String, audioPath: String) -> NSData {
            let boundaryStart = "--\(boundary)\r\n"
            let boundaryEnd = "\r\n--\(boundary)--\r\n"
            let bodyData : NSMutableData = NSMutableData()
    
            // add the token
            var tokenSection = boundaryStart
            tokenSection += "Content-Disposition: form-data; name=\"oauth_token\"\r\n\r\n"
            tokenSection += "\(token)\r\n"
            bodyData.appendData(tokenSection.dataUsingEncoding(NSUTF8StringEncoding)!)
    
            // add the track title
            var titleSection = boundaryStart
            titleSection += "Content-Disposition: form-data; name=\"track[title]\"\r\n\r\n"
            titleSection += "\(title)\r\n"
            bodyData.appendData(titleSection.dataUsingEncoding(NSUTF8StringEncoding)!)
    
            // add the audio file
            let trackData = NSData(contentsOfFile: audioPath)!
            var trackSection = boundaryStart
            trackSection += "Content-Disposition: form-data; name=\"track[asset_data]\"; "
            trackSection += "filename=\"\(audioPath.lastPathComponent)\"\r\n"
            trackSection += "Content-Type: application/octet-stream\r\n"
            trackSection += "\r\n"
            bodyData.appendData(trackSection.dataUsingEncoding(NSUTF8StringEncoding)!)
            bodyData.appendData(trackData)
            bodyData.appendData(boundaryEnd.dataUsingEncoding(NSUTF8StringEncoding)!)
            return bodyData
        }
    }
    

    Note: This example assumes access tokens will never expire, however, we encourage you not to make this assumption in your production code. Instead, build your app assuming that tokens will periodically expire and can be refreshed using a refresh token. For details on how to use a refresh token, see Section 1.5 of the OAuth 2.0 specification.

  • February 2nd, 2015 Announcements API Linked partitioning to replace offset-based pagination By Erik Michaels-Ober

    The SoundCloud API will be dropping support for offset-based pagination on March 2, 2015, in favor of linked partitioning.

    To page through a JSON response, pass the linked_partitioning=1 parameter along with your request and it will return a collection, along with a next_href property if there are additional results. To fetch the next page of results, simply follow that URI. If the response does not contain a next_href property, you have reached the end of the results.

    You can read more about linked partitioning in the Pagination section of our HTTP API Guide, including code examples in JavaScript, PHP, Python, and Ruby.

    The limit parameter continues to be supported with linked partitioning. The default limit is 50 with a maximum value of 200.

    Please update your code to replace the offset parameter with linked_partitioning. If you have any questions about this update, please notify us via email.

  • January 26th, 2015 Announcements Open Source Monitoring Go Prometheus: Monitoring at SoundCloud By Julius Volz, Bj√∂rn Rabenstein

    In previous blog posts, we discussed how SoundCloud has been moving towards a microservice architecture. Soon we had hundreds of services, with many thousand instances running and changing at the same time. With our existing monitoring set-up, mostly based on StatsD and Graphite, we ran into a number of serious limitations. What we really needed was a system with the following features:

    • A multi-dimensional data model, so that data can be sliced and diced at will, along dimensions like instance, service, endpoint, and method.

    • Operational simplicity, so that you can spin up a monitoring server where and when you want, even on your local workstation, without setting up a distributed storage backend or reconfiguring the world.

    • Scalable data collection and decentralized architecture, so that you can reliably monitor the many instances of your services, and independent teams can set up independent monitoring servers.

    • Finally, a powerful query language that leverages the data model for meaningful alerting (including easy silencing) and graphing (for dashboards and for ad-hoc exploration).

    All of these features existed in various systems. However, we could not identify a system that combined them all until a colleague started an ambitious pet project in 2012 that aimed to do so. Shortly thereafter, we decided to develop it into SoundCloud's monitoring system: Prometheus was born.

    Read more...

  • December 2nd, 2014 Scalding Hadoop SoundCloud in Scalding case study by Concurrent Inc. By Josh Devins

    Recently we teamed up with Concurrent Inc., the backers of the data-processing framework Cascading, to do a case study of how we use Scalding for some of our data-driven products such as Search. Scalding enables us to iterate quickly, test easily, and it allows for loose coupling of some of our data-processing pipelines.

    Check back for future posts about our use of other data-processing tools, and frameworks such as Spark.