libspotify: sometimes created playlists get no names - api

I am using the latest version of the libspotify API (12.1.51). And I am coding using C# and libspotify.NET (a simple interop wrapper library for libspotify). I have built a program that creates playlists using the libspotify API. I am using the latest native Spotify client for Windows for checking my created playlists.
I have built a program that waits for a playlist name and a list of track URIs or one album URI and creates the corresponding playlist. If an album URI is supplied then all the tracks from the album will be added to the new playlist otherwise the supplied list of track URIs will be used to create the new playlist. The program waits until the callback
playlist_update_in_progress
is called and the done parameter equals true before accepting new playlists to create.
It works well except that sometimes the playlists are created with no names but do have all the tracks. I can just tell the program to create the exact same playlist that got no name and it might work the second time. It happens randomly but I have noticed that if I create about 200 playlists then maybe 5-10 playlists get no names. I can see the playlists being added in your Spotify client as the program is running and creating the playlists and randomly seeing playlists with no names. The playlists appear almost at the same time the callback is called and done equals true (not always of course, there might be a delay). I tried manually renaming the playlists in the Spotify client for Windows with no problems (the playlist name length was 0 or an empty string if you will). The native Spotify client does not even allow empty playlist names.
I use:
sp_playlistcontainer_add_new_playlist
to add a new playlist and I have tried using IntPtr and a C# string to pass to it. Tried both:
[DllImport("libspotify")]
public static extern IntPtr sp_playlistcontainer_add_new_playlist(IntPtr playlistContainerPtr, string name);
[DllImport("libspotify")]
public static extern IntPtr sp_playlistcontainer_add_new_playlist(IntPtr playlistContainerPtr, IntPtr namePtr);
And I have also tried
sp_playlist_rename
to rename the playlist several times (as some sort of fix) with no success. I do not know exactly what happens at the server when the playlists are created. Is this a bug or what is going on?
I have really tried a lot of hacks to make this work, but to no avail.
More info about the program:
First it connects to Spotify and then waits for some console input.
It checks the input for the following strings:
To create a playlist using a name and a list of tracks:
createplaylistfromtracks "Tracks playlist" spotify:track:36MuLw248uzLPtrJ6073ZR spotify:track:5WPkvx0MARhlWhXp1sJg4k spotify:track:1VrdbSFVU9wJkuDM2sWYVe spotify:track:66RG0BBwpQqHxZs06UUyeo spotify:track:0zp3uPuhnARR1XYsgg5JLV
and to create a playlist using a name and a list of tracks from an album URI:
createplaylistfromalbum "Album playlist" spotify:album:5rVwDKRKa1FjDlLofDZyRb
And then the program parses the input and creates the playlist and settings a flag Busy = true so that the console will not read any input until Busy = false, which occurs when the playlist_update_in_progress callback is called and done is true. Then it reads input again...
Any help would be highly appreciated.

We have many applications running libspotify both internally and externally and we've had no problems like this with the library, which would suggest this isn't a bug in libspotify.
A few pointers that might cause this to happen:
Make sure you're managing threads properly. When you get a notify_main_thread() call (which arrives on some background thread), you must asynchronously call sp_sesion_process_events() from the main thread, so you need to make sure you're marshalling this over to the main thread properly. If this process isn't working properly, stuff will start acting weird.
Since you're doing many operations, make sure libspotify has time to synchronise all of your changes with the service. The playlist_update_in_progress is designed to notify you when multiple mutations are happening to the playlist, and is typically useful when changes are coming in from elsewhere. Instead, playlist_state_changed is what you need for listening to changes like that (typically, after a rename, I believe the playlists goes into a "loading" state while the change is applied, then back out (that is, sp_playlist_is_loading returns false again) once it's done.
Also, when you're exiting your application, make sure you perform a sp_session_logout() call and wait until the logged_out callback is fired before exiting. If you don't, some changes might not be synchronised with the service.

Related

How to queue requests in React Native without Redux?

Let's say I have a notes app. I want to enable the user to make changes while he is offline, save the changes optimistically in a Mobx store, and add a request to save the changes (on the server) to a queue.
Then when the internet connection is re-established I want to run the requests in the queue one by one so the data in the app syncs with data on the server.
Any suggestions would help.
I tried using react-native-job-queue but it doesn't seem to work.
I also considered react-native-queue but the library seems to be abandoned.
You could create a separate store (or an array in AsyncStorage) for pending operations, and add the operations to an array there when the network is disconnected. Tell your existing stores to look there for data, so you can render it optimistically. Then, when you detect a connection, run the updates in array order, and clear the array when done.
You could also use your existing stores, and add something like pending: true to values that haven't posted to your backend. However, you'll have less control over the order of operations, which sounds like it is important.
As it turns out I was in the wrong. The react-native-job-queue library does work, I just made a mistake by trying to pass a function reference (API call) to the Worker instead of just passing an object that contains the request URL and method and then just implement the Worker to make the API call based on those parameters.

What´s the specific function to fully change a players name?

I´ve been looking around the Internet for a week trying to discover a useable function that I can use to change a players name in my Plugin, and since most information is waaaaay to old, I was unsuccessful to find anything.
This is what I have tried already:
player.setCustomName(args[0]);
player.setDisplayName(args[0]);
player.setPlayerListName(args[0]);
getConfig().set(player.getName(),args[0]);
Its not like I receive a Error or something, its just that not much happens to the player names (but the function is actually called, I checked).
Simply, you cannot change your full name that you entered in the client settings.
These methods you are trying to use will only change the name of the in-game server for the player object. These also affect the names of the chat, tablist and possibly scoreboard teams. There is a solution that can be used to change the player name for a given player in half, but it will not affect other servers or the client either. Using GameProfile from Mojang, you can change its name and UUID, but this requires creating a new instance and adding it to the existing PlayerInfoData list. If you don't have Spigot/Paper or some software attached to your project, you'll need to use Java Reflections to modify the values/list and everything else, especially in PacketPlayOutPlayerInfo. Or, if you want to avoid Java Reflections, you can use the PlayerProfile interface implemented by Paper, using the Player#getPlayerProfile method.
An example code using Reflections:
Player player = ...; // Your player object here
GameProfile gameProfile = new GameProfile(player.getUniqueId(), "newPlayerNameHere");
// packet is the new instance of PacketPlayOutPlayerInfo
// infoList is the list retrieved from PacketPlayOutPlayerInfo
// playerInfoDataConstr is the PacketPlayOutPlayerInfo constructor
// ping is the amount of ping the player have currently
// gameMode is the EnumGameMode object of the player
// text is the text parsed to IChatBaseComponent
((List<Object>) infoList.get(packet)).add(playerInfoDataConstr.newInstance(packet, gameProfile, ping, gameMode, getAsIChatBaseComponent(text)));
// Send the packet object to every online player on the server
For accessing to GameProfile class you'll need com.mojang.authlib dependency.
Using Paper API is kinda easy to implement.

Asynchronous Pluggable Protocol for CID: (email), how to handle duplicate URLs

This is somewhat a duplicate of this question, but that question has no (valid) answer and is 1.5 years old so asking my own with hopes people have more info now.
If you are using multiple instances of a WebBrowser control, MSHTML, IHTMLDocument, or whatever... from inside the APP instance, mostly IInternetProtocol::Start, is there a way to know which instance is loading the resource? Or is there a way to use a different APP for each instance of the control, maybe by providing one via IDocHostUIHandler or ICustomDoc or otherwise? I'm currently using IInternetSession::RegisterNameSpace to make it process wide.
Optional reading below, don't feel you need to read it unless above isn't clear.
I'm working on a legacy (Win32 C++) email client that uses the MS ActiveX WebBrowser control (MSHTML or other names it goes by) to display HTML emails. It was saving everything to temp files, updating the cid: URLs, and then having the control load that. Now I want to do it the correct way, using APP. I've got it all working with some test code that just uses static variables/globals and loads one email.
My problem now is, the app might have several instances of the control all loading different emails (and other stuff) at the same time... not really multiple threads so much, just the asynchronous nature of the control. I can give each instance of the control a unique URL to load the email, say, cid:email-GUID, and then in my APP code I can use that URL to know which email to load. However, when it comes to loading any content inside the email, like attached images using src="cid:", those will not always be unique so I will not always know which image it is, for which email. I'd like to avoid having to modify the URLs of the HTML before displaying it (I'm doing that now for the temp file thing, but want to do it a better way).
IInternetBindInfo::GetBindString can return the referrer, BINDSTRING_XDR_ORIGIN, or the root URL, BINDSTRING_ROOTDOC_URL, but those require newer versions of IE and my legacy app must support older XP installs that might even have IE6 or IE7, so I'd rather not use these.
Tagged as TWebBrowser because that is actually what I'm using (Borland Builder 6 C++), but don't need answers specific to that platform.
As the Asynchronous Pluggable Protocol Handler us very low level, you cannot attach handlers individually to different rendering controls.
Here is a way to get the referrer:
Obtain BINDSTRING_HEADERS
Extract the referrer by parsing the line Referer: http://....
See also How can I add an extra http header using IHTTPNegotiate?
Here is another crazy way:
Create another Asynchronous Pluggable Protocol Handler by calling RegisterMimeFilter.
Monitor text/plain and text/html
Scan the incoming email source (content comes incrementally) and parse store all image links in a dictionary
In NameSpaceHandler you can use this dictionary to find the reference of any image resources.

NAudio asynchronous audio

I want to be able to dump sound files to the audio output asynchronously throughout the life of the application. I need to be able to request a file to be played and have it mixed in with any files already playing. The same file may be called multiple times. Is WaveMixerStream the way to go?
Is it safe/recommended to keep a player and mixer stream open for the life of the application or will that cause performance problems?
//globals
IWavePlayer _Context;
WaveMixerStream32 _Mixer;
//constructor
_Context = new DirectSoundOut();
_Mixer = new WaveMixerStream32();
_Context.Init( Instance._Mixer );
_Context.Play();
//asynchronous sound output, on demand from user interface
_Mixer.AddInputStream( sound.FileWaveStream );
There are several ways you could do this, but here's one option. Create a player and mixer open all the time. I would use the MixingSampleProvider as the mixer, passing it through a SampleToWaveProvider or SampleToWaveProvider16 as the input to the player.
To ensure that playback never stops you would either need to customise MixingSampleProvider so that Read always returns the number of samples asked for even if there are no active inputs, or add a dummy input which is a never-ending stream of silence.
Now to play a sound, just pass an ISampleProvider (e.g. AudioFileReader) into your mixer's AddMixerInput and it will play it. It auto-removes inputs when they reach the end.
An alternative is to create a new player object for each sound to play. The disadvantage is working out a way to keep the player object alive until playback stops (probably by storing in a dictionary and then Disposing and taking it out when the PlaybackStopped event fires). The advantage is that you aren't keeping the sound device open when you don't need to, and you can easily play sounds at different sample rates / number of channels.

Best multithreading approach in Objective C?

I'm developing an iPad-app and I'm currently struggling with finding the best approach to multithreading. Let me illustrate this with a simplified example:
I have a view with 2 subviews, a directory picker and a gallery with thumbnails of all the images in the selected directory. Since 'downloading' and generating these thumbnails can take quite a while I need multithreading so the interaction and updating of the view doesn't get blocked.
This is what I already tried:
[self performSelectorInBackground:#selector(displayThumbnails:) withObject:currentFolder];
This worked fine because the users interactions didn't get blocked, however it miserably fails when the user taps on another folder while the first folder is still loading. Two threads are trying to access the same view and variables which results in messing up each others proper execution. When the users taps another folder, the displayThumbnails of the currently loading folder should get aborted. I didn't find any way to do this..
NSThreads
I tried this but struggled with almost the same problems as with the first method, I didn't find a (easy) way to cancel the ongoing method. (Yes, I know about [aThread cancel] but didn't find a way to 'resume' the thread). Maybe I should subclass NSThread and implement my own isRunning etc methods? But isn't there any better way or a third (or even fourth and fifth) option I'm overlooking?
I think this is a fairly simple example and I think there is perhaps a better solution without subclassing NSThread. So, what would you do? Your opinions please!
NSOperationQueue should work well for this task.
Another option would be plain GCD, however, if you've never worked with it, NSOperationQueue is probably the better choice since it pretty much automatically guides you to implementing things "the right way", has obvious ways for cancellation, etc.
You want to use Concurrent NSOperations to download and process images in the background. These would be managed by an NSOperationsQueue. Essentially these operations would be configured to fetch one image per operation, process it, save it in the file system, then message back to the main app in the main thread that the image is available.
There are several projects on github that you can look at that show how to do this - just search github using "Concurrent" or "NSOperation".
iOS has a really nice facility for doing background work. Grand Central Dispatch (GCD) and Blocks, but those don't let you have an object using delegate callbacks - thus NSOperation.
So you need to read up on blocks, GCD, and then look at some open source Concurrent NSOperations code. Using Concurrent NSOperations is not as simple as using blocks.
If I had this problem, I would probably go for an approach like this:
a single thread that will load the images, and causes the main thread to display results (I'm not a big fan of having thread mess around with GUI objects)
when a new directory is requested... well, it depends on how you want to manage things. Basically, a standard queue construct (condition variable and array) could be used for the main thread to tell the thread that "this directory will be needed" by passing it the path name; the thread will check the queue even when it's loading images (like after every image or so), and switch to the new directory whenever one shows up
you could make a directory-reader object that keeps all the state, and store this indexed by the path into a dictionary. When a new directory is requested, check that dictionary first, and only create a new object if there's none for this directory. That way, partially loaded directories would stick around until they are needed again, and can continue to load instead of having to start from scratch.
Pseudocode for the thread:
while (forever)
new element = nil
if we have an active directory loader
tell directory loader to load one image
if false then make directory loader inactive
lock queue condition
if queue has elements
new element = retrieve LAST element (we aren't interested in the others)
empty queue
unlock with status "empty"
else
unlock queue
else
lock queue on condition "has elements"
new element = retrieve last element
empty queue
unlock with status "empty"
if new element != nil
if directory loader for new path does not exist
setup new directory loader for new path
store in dictionary
make it the "active" one
else
make the current one the "active"
As for the directory loader, it might look something like this:
read one image:
if there are still images to read:
read, process and store one
return true
else
performSelectorOnMainThread with an "update GUI" method and the image list as parameter
return false;
This is just a quick sketch; there's some code duplication in the thread, and the way I wrote it will only update the GUI after all images have been read, instead of making them appear as we read them. You'll have to copy the current image list, or add synchronization if you want to do that.