[vlc-devel] [PATCH] soundcloud.lua: Rewrite to support playlist and user tracks

Mario Rodas rodasmario2 at gmail.com
Wed Dec 14 18:15:18 CET 2016


---
 share/lua/playlist/soundcloud.lua | 116 ++++++++++++++++----------------------
 1 file changed, 49 insertions(+), 67 deletions(-)

diff --git a/share/lua/playlist/soundcloud.lua b/share/lua/playlist/soundcloud.lua
index d22c45b..71df917 100644
--- a/share/lua/playlist/soundcloud.lua
+++ b/share/lua/playlist/soundcloud.lua
@@ -26,85 +26,67 @@ function probe()
     local path = vlc.path
     path = path:gsub("^www%.", "")
     return ( vlc.access == "http" or vlc.access == "https" )
-        and string.match( path, "^soundcloud%.com/.+/.+" )
+        and string.match( path, "^soundcloud%.com/.+" )
 end
 
-function fix_quotes( value )
-    if string.match( value, "^\"" ) then
-        return "" -- field was really empty string
-    end
+function parse_json(url)
+    vlc.msg.dbg("Trying to parse JSON from " .. url)
+    local json = require ("dkjson")
 
-    -- TODO: handle escaped backslashes and others
-    return string.gsub( value, "\\\"", "\"" )
-end
+    -- Use vlc.stream to grab a remote json file, place it in a string,
+    -- decode it and return the decoded data.
+    local stream = vlc.stream(url)
+    local string = ""
+    local line   = ""
+
+    if not stream then return false end
 
--- Parse function.
-function parse()
     while true do
-        line = vlc.readline()
+        line = stream:read(65536)
         if not line then break end
 
-        -- Parameters for API call
-        if not track then
-            track = string.match( line, "soundcloud:tracks:(%d+)" )
-        end
-
-        -- For private tracks
-        if not secret then
-            secret = string.match( line, "[\"']secret_token[\"'] *: *[\"'](.-)[\"']" )
-        end
+        string = string .. line
+    end
 
-        -- Metadata
-        if not name then
-            name = string.match( line, "[\"']title[\"'] *: *\"(.-[^\\])\"" )
-            if name then
-                name = fix_quotes( name )
-            end
-        end
+    return json.decode(string)
+end
 
-        if not description then
-            description = string.match( line, "[\"']artwork_url[\"'] *:.-[\"']description[\"'] *: *\"(.-[^\\])\"" )
-            if description then
-                description = fix_quotes( description )
-            end
-        end
+-- Create a playlist item from a soundcloud track resource
+function create_track(item, client_id)
+    local url = item.downloadable and item.download_url or item.stream_url
+    return { path = url .. "?client_id=" .. client_id,
+             name = item.user.username .. " - " .. item.title,
+             title = item.title,
+             artist = item.user.username,
+             date = item.created_at,
+             genre = item.genre,
+             arturl = item.artwork_url or item.user.avatar_url,
+             rating = item.favoritings_count,
+             copyright = item.license,
+             description = item.description }
+end
 
-        if not artist then
-            artist = string.match( line, "[\"']username[\"'] *: *\"(.-[^\\])\"" )
-            if artist then
-                artist = fix_quotes( artist )
-            end
+-- Parse function.
+function parse()
+    local client_id = "fDoItMDbsbZz8dY16ZzARCZmzgHBPotA"
+    local response = parse_json(vlc.access .. "://api.soundcloud.com/resolve?url=" .. vlc.access .. "://" .. vlc.path .. "&_status_code_map[302]=200&_status_format=json&client_id=" .. client_id)
+    local data = parse_json(response.location)
+    local playlist = {}
+    if not data.kind then
+        for _, track in ipairs(data) do
+            table.insert(playlist, create_track(track, client_id))
         end
-
-        if not arturl then
-            arturl = string.match( line, "[\"']artwork_url[\"'] *: *[\"'](.-)[\"']" )
+    elseif data.kind == "track" then
+        table.insert(playlist, create_track(data, client_id))
+    elseif data.kind == "user" then
+        local tracks = parse_json(vlc.access .. "://api.soundcloud.com/users/" .. data.id .. "/tracks" .. "?client_id=" .. client_id)
+        for _, track in ipairs(tracks) do
+            table.insert(playlist, create_track(track, client_id))
         end
-    end
-
-    if track then
-        -- API magic
-        local client_id = "fDoItMDbsbZz8dY16ZzARCZmzgHBPotA"
-        -- app_version is not required by the API but we send it anyway
-        -- to remain unconspicuous
-        local app_version = "1480607078"
-
-        local api = vlc.stream( vlc.access.."://api.soundcloud.com/i1/tracks/"..track.."/streams?client_id="..client_id.."&app_version="..app_version..( secret and "&secret_token="..secret or "" ) )
-
-        if api then
-            local streams = api:readline() -- data is on one line only
-            -- For now only quality available is 128 kbps (http_mp3_128_url)
-            path = string.match( streams, "[\"']http_mp3_%d+_url[\"'] *: *[\"'](.-)[\"']" )
-            if path then
-                -- FIXME: do this properly
-                path = string.gsub( path, "\\u0026", "&" )
-            end
+    elseif data.kind == "playlist" then
+        for _, track in ipairs(data.tracks) do
+            table.insert(playlist, create_track(track, client_id))
         end
     end
-
-    if not path then
-        vlc.msg.err( "Couldn't extract soundcloud audio URL, please check for updates to this script" )
-        return { }
-    end
-
-    return { { path = path, name = name, description = description, artist = artist, arturl = arturl } }
+    return playlist
 end
-- 
2.10.2



More information about the vlc-devel mailing list