diff options
Diffstat (limited to 'src/playlist/SoundCloudPlaylistPlugin.cxx')
-rw-r--r-- | src/playlist/SoundCloudPlaylistPlugin.cxx | 157 |
1 files changed, 69 insertions, 88 deletions
diff --git a/src/playlist/SoundCloudPlaylistPlugin.cxx b/src/playlist/SoundCloudPlaylistPlugin.cxx index f6797b14d..50a9cb214 100644 --- a/src/playlist/SoundCloudPlaylistPlugin.cxx +++ b/src/playlist/SoundCloudPlaylistPlugin.cxx @@ -24,7 +24,8 @@ #include "ConfigData.hxx" #include "InputStream.hxx" #include "Song.hxx" -#include "tag/Tag.hxx" +#include "tag/TagBuilder.hxx" +#include "util/StringUtil.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" #include "Log.hxx" @@ -45,7 +46,8 @@ static constexpr Domain soundcloud_domain("soundcloud"); static bool soundcloud_init(const config_param ¶m) { - soundcloud_config.apikey = param.GetBlockValue("apikey", ""); + // APIKEY for MPD application, registered under DarkFox' account. + soundcloud_config.apikey = param.GetBlockValue("apikey", "a25e51780f7f86af0afa91f241d091f8"); if (soundcloud_config.apikey.empty()) { LogDebug(soundcloud_domain, "disabling the soundcloud playlist plugin " @@ -62,19 +64,20 @@ soundcloud_init(const config_param ¶m) * @return Constructed URL. Must be freed with g_free. */ static char * -soundcloud_resolve(const char* uri) { +soundcloud_resolve(const char* uri) +{ char *u, *ru; - if (g_str_has_prefix(uri, "http://")) { + if (StringStartsWith(uri, "https://")) { u = g_strdup(uri); - } else if (g_str_has_prefix(uri, "soundcloud.com")) { - u = g_strconcat("http://", uri, nullptr); + } else if (StringStartsWith(uri, "soundcloud.com")) { + u = g_strconcat("https://", uri, nullptr); } else { /* assume it's just a path on soundcloud.com */ - u = g_strconcat("http://soundcloud.com/", uri, nullptr); + u = g_strconcat("https://soundcloud.com/", uri, nullptr); } - ru = g_strconcat("http://api.soundcloud.com/resolve.json?url=", + ru = g_strconcat("https://api.soundcloud.com/resolve.json?url=", u, "&client_id=", soundcloud_config.apikey.c_str(), nullptr); g_free(u); @@ -105,15 +108,16 @@ struct parse_data { char* title; int got_url; /* nesting level of last stream_url */ - std::forward_list<SongPointer> songs; + std::forward_list<DetachedSong> songs; }; -static int handle_integer(void *ctx, - long +static int +handle_integer(void *ctx, + long #ifndef HAVE_YAJL1 - long + long #endif - intval) + intval) { struct parse_data *data = (struct parse_data *) ctx; @@ -128,26 +132,25 @@ static int handle_integer(void *ctx, return 1; } -static int handle_string(void *ctx, const unsigned char* stringval, +static int +handle_string(void *ctx, const unsigned char* stringval, #ifdef HAVE_YAJL1 - unsigned int + unsigned int #else - size_t + size_t #endif - stringlen) + stringlen) { struct parse_data *data = (struct parse_data *) ctx; const char *s = (const char *) stringval; switch (data->key) { case Title: - if (data->title != nullptr) - g_free(data->title); + g_free(data->title); data->title = g_strndup(s, stringlen); break; case Stream_URL: - if (data->stream_url != nullptr) - g_free(data->stream_url); + g_free(data->stream_url); data->stream_url = g_strndup(s, stringlen); data->got_url = 1; break; @@ -158,13 +161,14 @@ static int handle_string(void *ctx, const unsigned char* stringval, return 1; } -static int handle_mapkey(void *ctx, const unsigned char* stringval, +static int +handle_mapkey(void *ctx, const unsigned char* stringval, #ifdef HAVE_YAJL1 - unsigned int + unsigned int #else - size_t + size_t #endif - stringlen) + stringlen) { struct parse_data *data = (struct parse_data *) ctx; @@ -181,7 +185,8 @@ static int handle_mapkey(void *ctx, const unsigned char* stringval, return 1; } -static int handle_start_map(void *ctx) +static int +handle_start_map(void *ctx) { struct parse_data *data = (struct parse_data *) ctx; @@ -191,7 +196,8 @@ static int handle_start_map(void *ctx) return 1; } -static int handle_end_map(void *ctx) +static int +handle_end_map(void *ctx) { struct parse_data *data = (struct parse_data *) ctx; @@ -206,21 +212,16 @@ static int handle_end_map(void *ctx) /* got_url == 1, track finished, make it into a song */ data->got_url = 0; - Song *s; - char *u; + char *u = g_strconcat(data->stream_url, "?client_id=", + soundcloud_config.apikey.c_str(), nullptr); - u = g_strconcat(data->stream_url, "?client_id=", - soundcloud_config.apikey.c_str(), nullptr); - s = Song::NewRemote(u); - g_free(u); - - Tag *t = new Tag(); - t->time = data->duration / 1000; + TagBuilder tag; + tag.SetTime(data->duration / 1000); if (data->title != nullptr) - t->AddItem(TAG_NAME, data->title); - s->tag = t; + tag.AddItem(TAG_NAME, data->title); - data->songs.emplace_front(s); + data->songs.emplace_front(u, tag.Commit()); + g_free(u); return 1; } @@ -249,12 +250,9 @@ static int soundcloud_parse_json(const char *url, yajl_handle hand, Mutex &mutex, Cond &cond) { - char buffer[4096]; - unsigned char *ubuffer = (unsigned char *)buffer; - Error error; - InputStream *input_stream = InputStream::Open(url, mutex, cond, - error); + InputStream *input_stream = InputStream::OpenReady(url, mutex, cond, + error); if (input_stream == nullptr) { if (error.IsDefined()) LogError(error); @@ -262,12 +260,13 @@ soundcloud_parse_json(const char *url, yajl_handle hand, } mutex.lock(); - input_stream->WaitReady(); yajl_status stat; int done = 0; while (!done) { + char buffer[4096]; + unsigned char *ubuffer = (unsigned char *)buffer; const size_t nbytes = input_stream->Read(buffer, sizeof(buffer), error); if (nbytes == 0) { @@ -318,80 +317,62 @@ soundcloud_parse_json(const char *url, yajl_handle hand, * soundcloud://playlist/<playlist-id> * soundcloud://url/<url or path of soundcloud page> */ - static SongEnumerator * soundcloud_open_uri(const char *uri, Mutex &mutex, Cond &cond) { - char *s, *p; - char *scheme, *arg, *rest; - s = g_strdup(uri); - scheme = s; - for (p = s; *p; p++) { - if (*p == ':' && *(p+1) == '/' && *(p+2) == '/') { - *p = 0; - p += 3; - break; - } - } - arg = p; - for (; *p; p++) { - if (*p == '/') { - *p = 0; - p++; - break; - } - } - rest = p; - - if (strcmp(scheme, "soundcloud") != 0) { - FormatWarning(soundcloud_domain, - "incompatible scheme for soundcloud plugin: %s", - scheme); - g_free(s); - return nullptr; - } + assert(memcmp(uri, "soundcloud://", 13) == 0); + uri += 13; char *u = nullptr; - if (strcmp(arg, "track") == 0) { - u = g_strconcat("http://api.soundcloud.com/tracks/", + if (memcmp(uri, "track/", 6) == 0) { + const char *rest = uri + 6; + u = g_strconcat("https://api.soundcloud.com/tracks/", rest, ".json?client_id=", soundcloud_config.apikey.c_str(), nullptr); - } else if (strcmp(arg, "playlist") == 0) { - u = g_strconcat("http://api.soundcloud.com/playlists/", + } else if (memcmp(uri, "playlist/", 9) == 0) { + const char *rest = uri + 9; + u = g_strconcat("https://api.soundcloud.com/playlists/", rest, ".json?client_id=", soundcloud_config.apikey.c_str(), nullptr); - } else if (strcmp(arg, "url") == 0) { + } else if (memcmp(uri, "user/", 5) == 0) { + const char *rest = uri + 5; + u = g_strconcat("https://api.soundcloud.com/users/", + rest, "/tracks.json?client_id=", + soundcloud_config.apikey.c_str(), nullptr); + } else if (memcmp(uri, "search/", 7) == 0) { + const char *rest = uri + 7; + u = g_strconcat("https://api.soundcloud.com/tracks.json?q=", + rest, "&client_id=", + soundcloud_config.apikey.c_str(), nullptr); + } else if (memcmp(uri, "url/", 4) == 0) { + const char *rest = uri + 4; /* Translate to soundcloud resolver call. libcurl will automatically follow the redirect to the right resource. */ u = soundcloud_resolve(rest); } - g_free(s); if (u == nullptr) { LogWarning(soundcloud_domain, "unknown soundcloud URI"); return nullptr; } - yajl_handle hand; struct parse_data data; - data.got_url = 0; data.title = nullptr; data.stream_url = nullptr; #ifdef HAVE_YAJL1 - hand = yajl_alloc(&parse_callbacks, nullptr, nullptr, (void *) &data); + yajl_handle hand = yajl_alloc(&parse_callbacks, nullptr, nullptr, + &data); #else - hand = yajl_alloc(&parse_callbacks, nullptr, (void *) &data); + yajl_handle hand = yajl_alloc(&parse_callbacks, nullptr, &data); #endif int ret = soundcloud_parse_json(u, hand, mutex, cond); g_free(u); yajl_free(hand); - if (data.title != nullptr) - g_free(data.title); - if (data.stream_url != nullptr) - g_free(data.stream_url); + g_free(data.title); + g_free(data.stream_url); if (ret == -1) return nullptr; |