int cmd_playlist_add_track(int argc, char **argv) { sp_link *plink, *tlink; sp_track *t; sp_playlist *pl; int i; struct pl_update_work *puw; if(argc < 4) { printf("add [playlist uri] [position] [track uri] <[track uri]>...\n"); return 1; } plink = sp_link_create_from_string(argv[1]); if (!plink) { fprintf(stderr, "%s is not a spotify link\n", argv[1]); return -1; } if(sp_link_type(plink) != SP_LINKTYPE_PLAYLIST) { fprintf(stderr, "%s is not a playlist link\n", argv[1]); sp_link_release(plink); return -1; } puw = malloc(sizeof(struct pl_update_work)); puw->position = atoi(argv[2]); puw->tracks = malloc(sizeof(sp_track *) * argc - 3); puw->num_tracks = 0; for(i = 0; i < argc - 3; i++) { tlink = sp_link_create_from_string(argv[i + 3]); if(tlink == NULL) { fprintf(stderr, "%s is not a spotify link, skipping\n", argv[i + 3]); continue; } if(sp_link_type(tlink) != SP_LINKTYPE_TRACK) { fprintf(stderr, "%s is not a track link, skipping\n", argv[i + 3]); continue; } t = sp_link_as_track(tlink); sp_track_add_ref(t); puw->tracks[puw->num_tracks++] = t; sp_link_release(tlink); } pl = sp_playlist_create(g_session, plink); if(!apply_changes(pl, puw)) { // Changes applied directly, we're done sp_playlist_release(pl); sp_link_release(plink); return 1; } fprintf(stderr, "Playlist not yet loaded, waiting...\n"); sp_playlist_add_callbacks(pl, &pl_update_callbacks, puw); sp_link_release(plink); return 0; }
void Spotify::changeCurrentlyPlayingSong() { sp_track * track; const char * uri = currentURI.toLocal8Bit().constData(); fprintf(stderr, "Spotify: Playing %s\n", uri); sp_link * link = sp_link_create_from_string(uri); if (!link) { fprintf(stderr, "Spotify: failed to parse URI (%s)\n", uri); currentURI.clear(); return; } switch (sp_link_type(link)) { case SP_LINKTYPE_LOCALTRACK: case SP_LINKTYPE_TRACK: track = sp_link_as_track(link); if (!track) { fprintf(stderr, "Link is not a track\n"); break; } nextTrack = track; sp_track_add_ref(track); tryLoadTrack(); break; default: qDebug() << "URI is not a track:" << currentURI; break; } sp_link_release(link); }
PHP_METHOD(Spotify, getArtistByURI) { zval *uri, temp, *object = getThis(); int timeout = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &uri) == FAILURE) { return; } spotify_object *p = (spotify_object*)zend_object_store_get_object(object TSRMLS_CC); sp_link *link = sp_link_create_from_string(Z_STRVAL_P(uri)); if (NULL == link) { RETURN_FALSE; } if (SP_LINKTYPE_ARTIST != sp_link_type(link)) { RETURN_FALSE; } sp_artist *artist = sp_link_as_artist(link); object_init_ex(return_value, spotifyartist_ce); SPOTIFY_METHOD2(SpotifyArtist, __construct, &temp, return_value, object, artist); sp_link_release(link); }
sp_playlist * sp_playlistcontainer_add_playlist(sp_playlistcontainer *pc, sp_link *link) { sp_playlist *playlist = NULL; switch (sp_link_type(link)) { case SP_LINKTYPE_PLAYLIST: case SP_LINKTYPE_STARRED: playlist = (sp_playlist *)sp_mock_registry_find(link->data); break; default: return NULL; } if (playlist) { sp_playlistcontainer_playlist_t container_playlist; container_playlist.playlist = playlist; container_playlist.type = SP_PLAYLIST_TYPE_PLAYLIST; sp_mock_playlistcontainer_insert(pc, sp_playlistcontainer_num_playlists(pc), container_playlist); } return playlist; }
QString Spotify::songNameFromUri(const QString &uriString) { const char * uri = uriString.toLocal8Bit().constData(); sp_link * link = sp_link_create_from_string(uri); if (!link) { fprintf(stderr, "Spotify: failed to parse URI (%s)\n", uri); return QString(); } sp_track * track; QString song; switch (sp_link_type(link)) { case SP_LINKTYPE_LOCALTRACK: case SP_LINKTYPE_TRACK: track = sp_link_as_track(link); if (!track) { fprintf(stderr, "Link is not a track\n"); break; } song = QString(sp_track_name(track)); break; default: qDebug() << "URI is not a track:" << uriString; break; } sp_link_release(link); return song; }
PHP_METHOD(Spotify, getAlbumByURI) { zval *uri, temp, *object = getThis(); int timeout = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &uri) == FAILURE) { return; } spotify_object *p = (spotify_object*)zend_object_store_get_object(object TSRMLS_CC); sp_link *link = sp_link_create_from_string(Z_STRVAL_P(uri)); if (NULL == link) { RETURN_FALSE; } if (SP_LINKTYPE_ALBUM != sp_link_type(link)) { RETURN_FALSE; } sp_album *album = sp_link_as_album(link); while (!sp_album_is_loaded(album)) { sp_session_process_events(p->session, &timeout); } object_init_ex(return_value, spotifyalbum_ce); SPOTIFY_METHOD2(SpotifyAlbum, __construct, &temp, return_value, object, album); sp_link_release(link); }
sp_playlist * sp_playlist_create(sp_session *UNUSED(session), sp_link *link) { sp_linktype type = sp_link_type(link); if (type != SP_LINKTYPE_PLAYLIST && type != SP_LINKTYPE_STARRED) { return NULL; } return sp_mock_registry_find(link->data); }
int luasp_link_type(lua_State *L) { // link_type = spotify.link_type(link) if (lua_gettop(L) != 1 || !lua_isuserdata(L, 1)) { lua_pushstring(L, "incorrect argument to link_create_from_string(...)"); lua_error(L); } lua_pushinteger(L, sp_link_type((sp_link*)lua_touserdata(L, 1)) ); return 1; }
void command_link(sp_session *session, const struct command * const command) { sp_link *l = sp_link_create_from_string(command->search_string); if(l == NULL || sp_link_type(l) == SP_LINKTYPE_INVALID) { sock_send_str(command->sockfd, "Not a valid link.\n"); return; } else if(sp_link_type(l) == SP_LINKTYPE_TRACK) { sp_track *t = sp_link_as_track(l); queue_add_track(t); sock_send_str(command->sockfd, "Added track to queue.\n"); } else { sock_send_str(command->sockfd, "Link is valid but its type is not supported. Only links to tracks are supported.\n"); } sp_link_release(l); }
static void _spotify_play(sp_session *session, std::string uri) { assert(pthread_equal(pthread_self(),g_spotify_tid)); sp_link *l = sp_link_create_from_string(uri.c_str()); sp_error err; int offset; if(!l || sp_link_type(l) != SP_LINKTYPE_TRACK) { return; } sp_track *t = sp_link_as_track_and_offset(l,&offset); try_play(session,t,offset); sp_link_release(l); return; }
void QSpotifySession::handleUri(QString uri) { qDebug() << "QSpotifySession::handleUri"; if (!m_isLoggedIn) { m_uriToOpen = uri; return; } sp_link *link = sp_link_create_from_string(uri.toLatin1().data()); sp_linktype link_type = sp_link_type(link); if (link_type == SP_LINKTYPE_TRACK) { sp_track *track = sp_link_as_track(link); std::shared_ptr<QSpotifyTrack> q_track(new QSpotifyTrack(track, nullptr)); enqueue(q_track); play(q_track, true); } }
// ---------------------------------------------------------------------------- // sp_linktype SpotifyEngine::getTrackLink( sp_track* track, CString& spotify_link ) { spotify_link.Empty(); sp_link* link = sp_link_create_from_track( track, 0 ); if ( link == NULL ) return SP_LINKTYPE_INVALID; LPSTR spotify_link_ptr = spotify_link.GetBufferSetLength( 512 ); sp_link_as_string ( link, spotify_link_ptr, 512 ); sp_linktype link_type = sp_link_type( link ); sp_link_release( link ); return link_type; }
int cmd_browse(int argc, char **argv) { sp_link *link; if (argc != 2) { browse_usage(); return -1; } link = sp_link_create_from_string(argv[1]); if (!link) { fprintf(stderr, "Not a spotify link\n"); return -1; } switch(sp_link_type(link)) { default: fprintf(stderr, "Can not handle link"); sp_link_release(link); return -1; case SP_LINKTYPE_ALBUM: sp_albumbrowse_create(g_session, sp_link_as_album(link), browse_album_callback, NULL); break; case SP_LINKTYPE_ARTIST: sp_artistbrowse_create(g_session, sp_link_as_artist(link), browse_artist_callback, NULL); break; case SP_LINKTYPE_TRACK: track_browse = sp_link_as_track(link); metadata_updated_fn = track_browse_try; sp_track_add_ref(track_browse); track_browse_try(); break; case SP_LINKTYPE_PLAYLIST: browse_playlist(sp_playlist_create(g_session, link)); break; } sp_link_release(link); return 0; }
bool json_to_track(json_t *json, sp_track **track) { if (!json_is_string(json)) return false; sp_link *link = sp_link_create_from_string(json_string_value(json)); if (link == NULL) return false; if (sp_link_type(link) != SP_LINKTYPE_TRACK) { sp_link_release(link); return false; } *track = sp_link_as_track(link); return *track != NULL; }
static PyObject * Link_type(Link * self) { return Py_BuildValue("i", sp_link_type(self->_link)); }
int cmd_playlist_offline(int argc, char **argv) { sp_link *plink; sp_playlist *pl; int on; if (argc == 2 && !strcmp(argv[1], "status")) { printf("Offline status\n"); printf(" %d tracks to sync\n", sp_offline_tracks_to_sync(g_session)); printf(" %d offline playlists in total\n", sp_offline_num_playlists(g_session)); return 1; } if (argc != 3) { printf("offline status | <playlist uri> <on|off>\n"); return 1; } plink = sp_link_create_from_string(argv[1]); if (!plink) { fprintf(stderr, "%s is not a spotify link\n", argv[1]); return -1; } if (sp_link_type(plink) != SP_LINKTYPE_PLAYLIST) { fprintf(stderr, "%s is not a playlist link\n", argv[1]); sp_link_release(plink); return -1; } pl = sp_playlist_create(g_session, plink); if (argc == 3) { if (!strcasecmp(argv[2], "on")) on = 1; else if (!strcasecmp(argv[2], "off")) on = 0; else { fprintf(stderr, "Invalid mode: %s\n", argv[2]); return -1; } sp_playlist_set_offline_mode(g_session, pl, on); } else { sp_playlist_offline_status s; s = sp_playlist_get_offline_status(g_session, pl); printf("Offline status for %s (%s)\n", argv[1], sp_playlist_name(pl)); printf(" Status: %s\n", offlinestatus[s]); if (s == SP_PLAYLIST_OFFLINE_STATUS_DOWNLOADING) printf(" %d%% Complete\n", sp_playlist_get_offline_download_completed(g_session, pl)); } sp_playlist_release(pl); sp_link_release(plink); return 1; }
static void restore_state(session_callback_type type, gpointer data, gpointer user_data) { JsonParser* jp = NULL; JsonReader* jr = NULL; const gchar* sqs; saved_state* s = NULL; GError* err = NULL; /* Is it the callback we're interested in? */ if (type != SPOP_SESSION_LOGGED_IN) return; /* First disable the callback so it's not called again */ session_remove_callback(restore_state, NULL); g_debug("savestate: reading saved state..."); s = g_new0(saved_state, 1); /* Read and parse state file */ jp = json_parser_new(); if (!json_parser_load_from_file(jp, g_state_file_path, &err)) { g_warning("savestate: error while reading state file: %s", err->message); goto restorestate_error; } jr = json_reader_new(json_parser_get_root(jp)); /* Read basic state */ if (!json_reader_read_member(jr, "status")) goto restorestate_jr_error; sqs = json_reader_get_string_value(jr); json_reader_end_member(jr); if (strcmp(sqs, "stopped")) s->qs = STOPPED; else if (strcmp(sqs, "playing")) s->qs = PLAYING; else if (strcmp(sqs, "paused")) s->qs = PAUSED; else { g_warning("savestate: bad value for queue status: %s", sqs); goto restorestate_error; } if (!json_reader_read_member(jr, "repeat")) goto restorestate_jr_error; s->repeat = json_reader_get_boolean_value(jr); json_reader_end_member(jr); if (!json_reader_read_member(jr, "shuffle")) goto restorestate_jr_error; s->shuffle = json_reader_get_boolean_value(jr); json_reader_end_member(jr); if (!json_reader_read_member(jr, "current_track")) goto restorestate_jr_error; s->cur_track = json_reader_get_int_value(jr); json_reader_end_member(jr); /* Now read tracks URIs */ if (!json_reader_read_member(jr, "tracks")) goto restorestate_jr_error; if (!json_reader_is_array(jr)) { g_warning("savestate: error while parsing JSON: tracks is not an array"); goto restorestate_error; } gint tracks = json_reader_count_elements(jr); if (s->cur_track >= tracks) { g_warning("savestate: incoherent state file: cur_track >= tracks"); goto restorestate_error; } s->tracks = g_array_sized_new(FALSE, FALSE, sizeof(sp_track*), tracks); if (!s->tracks) g_error("Can't allocate array of %d tracks.", tracks); size_t i; gboolean can_restore_now = TRUE; for (i=0; i < tracks; i++) { json_reader_read_element(jr, i); const gchar* uri = json_reader_get_string_value(jr); json_reader_end_element(jr); sp_link* lnk = sp_link_create_from_string(uri); sp_linktype lt = sp_link_type(lnk); if (lt != SP_LINKTYPE_TRACK) { g_warning("savestate: invalid link type for track %zu: %d", i, lt); sp_link_release(lnk); goto restorestate_error; } sp_track* tr = sp_link_as_track(lnk); sp_track_add_ref(tr); sp_link_release(lnk); g_array_append_val(s->tracks, tr); if (!sp_track_is_loaded(tr)) can_restore_now = FALSE; } /* If possible, restore now, else wait for all tracks to be loaded */ if (can_restore_now) really_restore_state(s); else { g_timeout_add(100, (GSourceFunc) really_restore_state, s); g_debug("savestate: waiting for all tracks to be loaded before restoring saved state..."); } /* Add a notification callback */ if (!interface_notify_add_callback(savestate_notification_callback, NULL)) g_error("Could not add savestate callback."); goto restorestate_clean; restorestate_jr_error: err = (GError*) json_reader_get_error(jr); g_warning("savestate: error while parsing JSON: %s", err->message); restorestate_error: if (s) { if (s->tracks) g_array_free(s->tracks, TRUE); g_free(s); } restorestate_clean: if (jp) g_object_unref(jp); if (jr) g_object_unref(jr); }
// Request dispatcher static void handle_request(struct evhttp_request *request, void *userdata) { evhttp_connection_set_timeout(request->evcon, 1); evhttp_add_header(evhttp_request_get_output_headers(request), "Server", "[email protected]/spotify-api-server"); // Check request method int http_method = evhttp_request_get_command(request); switch (http_method) { case EVHTTP_REQ_GET: case EVHTTP_REQ_PUT: case EVHTTP_REQ_POST: break; default: evhttp_send_error(request, HTTP_NOTIMPL, "Not Implemented"); return; } struct state *state = userdata; sp_session *session = state->session; char *uri = evhttp_decode_uri(evhttp_request_get_uri(request)); char *entity = strtok(uri, "/"); if (entity == NULL) { evhttp_send_error(request, HTTP_BADREQUEST, "Bad Request"); free(uri); return; } // Handle requests to /user/<user_name>/inbox if (strncmp(entity, "user", 4) == 0) { char *username = strtok(NULL, "/"); if (username == NULL) { evhttp_send_error(request, HTTP_BADREQUEST, "Bad Request"); free(uri); return; } char *action = strtok(NULL, "/"); handle_user_request(request, action, username, session); free(uri); return; } // Handle requests to /playlist/<playlist_uri>/<action> if (strncmp(entity, "playlist", 8) != 0) { evhttp_send_error(request, HTTP_BADREQUEST, "Bad Request"); free(uri); return; } char *playlist_uri = strtok(NULL, "/"); if (playlist_uri == NULL) { switch (http_method) { case EVHTTP_REQ_PUT: case EVHTTP_REQ_POST: put_playlist(NULL, request, session); break; default: send_error(request, HTTP_BADREQUEST, "Bad Request"); break; } free(uri); return; } sp_link *playlist_link = sp_link_create_from_string(playlist_uri); if (playlist_link == NULL) { send_error(request, HTTP_NOTFOUND, "Playlist link not found"); free(uri); return; } if (sp_link_type(playlist_link) != SP_LINKTYPE_PLAYLIST) { sp_link_release(playlist_link); send_error(request, HTTP_BADREQUEST, "Not a playlist link"); free(uri); return; } sp_playlist *playlist = sp_playlist_create(session, playlist_link); sp_link_release(playlist_link); if (playlist == NULL) { send_error(request, HTTP_NOTFOUND, "Playlist not found"); free(uri); return; } sp_playlist_add_ref(playlist); // Dispatch request char *action = strtok(NULL, "/"); // Default request handler handle_playlist_fn request_callback = ¬_implemented; void *callback_userdata = session; switch (http_method) { case EVHTTP_REQ_GET: { if (action == NULL) { // Send entire playlist request_callback = &get_playlist; } else if (strncmp(action, "collaborative", 13) == 0) { request_callback = &get_playlist_collaborative; } else if (strncmp(action, "subscribers", 11) == 0) { request_callback = &get_playlist_subscribers; } } break; case EVHTTP_REQ_PUT: case EVHTTP_REQ_POST: { if (strncmp(action, "add", 3) == 0) { request_callback = &put_playlist_add_tracks; } else if (strncmp(action, "remove", 6) == 0) { request_callback = &put_playlist_remove_tracks; } else if (strncmp(action, "patch", 5) == 0) { callback_userdata = state; request_callback = &put_playlist_patch; } } break; } if (sp_playlist_is_loaded(playlist)) { request_callback(playlist, request, callback_userdata); } else { // Wait for playlist to load register_playlist_callbacks(playlist, request, request_callback, &playlist_state_changed_callbacks, callback_userdata); } free(uri); }
static void put_playlist_patch(sp_playlist *playlist, struct evhttp_request *request, void *userdata) { struct state *state = userdata; struct evbuffer *buf = evhttp_request_get_input_buffer(request); size_t buflen = evbuffer_get_length(buf); if (buflen == 0) { send_error(request, HTTP_BADREQUEST, "No body"); return; } // Read request body json_error_t loads_error; json_t *json = read_request_body_json(request, &loads_error); if (json == NULL) { send_error(request, HTTP_BADREQUEST, loads_error.text ? loads_error.text : "Unable to parse JSON"); return; } if (!json_is_array(json)) { json_decref(json); send_error(request, HTTP_BADREQUEST, "Not valid JSON array"); return; } // Handle empty array int num_tracks = json_array_size(json); if (num_tracks == 0) { send_reply(request, HTTP_OK, "OK", NULL); return; } sp_track **tracks = calloc(num_tracks, sizeof (sp_track *)); int num_valid_tracks = 0; for (int i = 0; i < num_tracks; i++) { json_t *item = json_array_get(json, i); if (!json_is_string(item)) { json_decref(item); continue; } char *uri = strdup(json_string_value(item)); sp_link *track_link = sp_link_create_from_string(uri); free(uri); if (track_link == NULL) continue; if (sp_link_type(track_link) != SP_LINKTYPE_TRACK) { sp_link_release(track_link); continue; } sp_track *track = sp_link_as_track(track_link); if (track == NULL) continue; tracks[num_valid_tracks++] = track; } json_decref(json); // Bail if no tracks could be read from input if (num_valid_tracks == 0) { send_error(request, HTTP_BADREQUEST, "No valid tracks"); free(tracks); return; } tracks = realloc(tracks, num_valid_tracks * sizeof (sp_track *)); // Apply diff apr_pool_t *pool = state->pool; svn_diff_t *diff; svn_error_t *diff_error = diff_playlist_tracks(&diff, playlist, tracks, num_valid_tracks, pool); if (diff_error != SVN_NO_ERROR) { free(tracks); svn_handle_error2(diff_error, stderr, false, "Diff"); send_error(request, HTTP_BADREQUEST, "Search failed"); return; } svn_error_t *apply_error = diff_playlist_tracks_apply(diff, playlist, tracks, num_valid_tracks, state->session); if (apply_error != SVN_NO_ERROR) { free(tracks); svn_handle_error2(apply_error, stderr, false, "Updating playlist"); send_error(request, HTTP_BADREQUEST, "Could not apply diff"); return; } if (!sp_playlist_has_pending_changes(playlist)) { free(tracks); get_playlist(playlist, request, NULL); return; } free(tracks); register_playlist_callbacks(playlist, request, &get_playlist, &playlist_update_in_progress_callbacks, NULL); }
void AudioHTTPServer::sid( QxtWebRequestEvent* event, QString a ) { qDebug() << QThread::currentThreadId() << "HTTP" << event->url.toString() << a; if( !SpotifySession::getInstance()->Playback()->trackIsOver() ) { SpotifySession::getInstance()->Playback()->endTrack(); } // the requested track QString uid = a.replace( ".wav", ""); // qDebug() << QThread::currentThreadId() << "Beginning to stream requested track:" << uid; if( uid.isEmpty() || !sApp->hasLinkFromTrack( uid ) ) { qWarning() << "Did not find spotify track UID in our list!" << uid; sendErrorResponse( event ); return; } // get the sp_track sp_link* link = sApp->linkFromTrack( uid ); sp_track* track = sp_link_as_track( link ); if( !track ) { qWarning() << QThread::currentThreadId() << "Uh oh... got null track from link :(" << sp_link_type( link ); sendErrorResponse( event ); return; } if( !sp_track_is_loaded( track ) ) { qWarning() << QThread::currentThreadId() << "uh oh... track not loaded yet! Asked for:" << sp_track_name( track ); m_savedEvent = event; m_savedTrack = track; QTimer::singleShot( 250, this, SLOT( checkForLoaded() ) ); return; } else { startStreamingResponse( event, track ); } }