coverList.getThumb Worked, Now Crashes

To discuss development of addons / skins / customization of MediaMonkey.

Moderators: jiri, drakinite, Addon Administrators

crutchcorn
Posts: 32
Joined: Sat Feb 23, 2013 11:38 pm

coverList.getThumb Worked, Now Crashes

Post by crutchcorn »

Hey, y'all. I'm working on a MediaMonkey plugin that allows me to write the currently playing music to a text file (and image file in the case of album artwork) in order to show up on my Twitch overlay. I intend on making this code OSS and sharing as a plugin with everyone

I've got some code that used to work until an unrelated crash, and now breaks every time I've tried to run since then.

I have the following code to get the album artwork:

```
player.getCurrentTrack().coverList.getValue(0).getThumb(100, 100)
```

(I'm in early stages of testing for this, in the final version I'd be doing checks to see `coverList.size` and doing `coverList.filterBySearchPhrase` to find `Front` of some kind before falling back to `0`)

This code worked perfectly fine for me on the debug build of MediaMonkey 5.0.2.2506 using Chrome's inspector until at some point (due to some unrelated bone-headed coding on my end) MediaMonkey crashed.

Ever since I've had to force close MediaMonkey, this code no longer functions as intended. Now when I run that code (on the same file), I get the following error:

```
Read lock not acquired! (D:\Delphi\MediaMonkeyClean\HTML5Monkey\BaseShared.pas, line 3898)
```

Two interesting things of note:

1) I don't have the `Delphi` folder on my `D:\` drive
2) This is a portable instance of MediaMonkey in `C:\\tools\MediaMonkey5Debug`, why is it reading from another drive?

This persists even on a clean installation of MediaMonkey5Debug (AKA just deleting the old portable folder, installing a new portable instance)

When I run:

```
player.getCurrentTrack().coverList.count
```

It's inconsistent with what it returns. Occasionally it returns `1` (which is correct for the file) or `0` (incorrect). However, even if it reads `1` this error still occurs

I've tested this code against the same file as before the crash (when it was still working) and on a different file. Issue persists regardless

I've sent a log using the built-in form and linked to this forum post URL as the text to find easier, but let me know if I can attach the log in a different way.

I'm currently stuck on developing this plugin until this is resolved
Peke
Posts: 17484
Joined: Tue Jun 10, 2003 7:21 pm
Location: Earth
Contact:

Re: coverList.getThumb Worked, Now Crashes

Post by Peke »

Hi,
Can you test latest MM5.0.1.2433 release build installed as portable to see if it is teh regression introduced in new 5.0.2 builds?
Best regards,
Peke
MediaMonkey Team lead QA/Tech Support guru
Admin of Free MediaMonkey addon Site HappyMonkeying
Image
Image
Image
How to attach PICTURE/SCREENSHOTS to forum posts
crutchcorn
Posts: 32
Joined: Sat Feb 23, 2013 11:38 pm

Re: coverList.getThumb Worked, Now Crashes

Post by crutchcorn »

Not a regression.

Issue persists in portable debug build from stable `5.0.1.2431` that I got from this thread:

viewtopic.php?p=485590

Even occurs when `count` was `1`
drakinite
Posts: 965
Joined: Tue May 12, 2020 10:06 am
Contact:

Re: coverList.getThumb Worked, Now Crashes

Post by drakinite »

Hi there!
I haven't properly documented how to use SharedLists yet (because I didn't properly understand them when writing the current MM5 developer documentation on the wiki). The reason you're getting that crash is because the "coverList" track property is a SharedList.
They are native objects, controlled by the native Delphi code in MediaMonkey's backend. You can find documentation on their main properties here: https://www.mediamonkey.com/docs/api/cl ... dList.html
The native SharedLists are used because they are tied natively to the database, they are shared across multiple windows, and because when you modify one, they'll automatically update throughout the whole UI. [[Note: when I say "multiple windows" I don't mean multiple instances. When you open a dialog (e.g. Tools > Options), the dialog is its own window - it has its own document tree and everything. SharedLists are shared across those multiple internal windows.]]

The main takeaway is that in order to use the getValue() method (and a few others) of a SharedList, you need to enter a read lock. This is done with the locked() function, in which you specify a callback to be executed during the read lock.

Code: Select all

var currentTrack = player.getCurrentTrack();
var coverList = currentTrack.loadCoverListAsync();
// Wait for the coverList to asynchronously load
coverList.whenLoaded().then(function () {
    // Enter a read lock
    coverList.locked(function () {
        // Now you can get the cover object
        var cover = coverList.getValue(0);
        // Get the thumbnail asynchronously
        cover.getThumbAsync(100, 100, function (path) {
            console.log(path);
        });
    });
});
Now, the file path that is returned will be something like this:

Code: Select all

file:///temp/Thumbs/9D/TIPIRNYZ6UR75JW2-200px.jpg
And you'll notice that if you load that into a web browser, you won't get anything. That's because "temp" is a "virtual" directory, which MM interprets and serves files from the appropriate temp directory. It may be frustrating in this context when you want the full file path, but it simplifies the development process and avoids collisions when MediaMonkey is installed in different directories (also portable vs. non-portable mode). So you'll want to replace the file path with the appropriate temp folder. Luckily, you can get that with window.settings:

Code: Select all

var sett = window.settings.get('System');
sett.System.TempDir // returns your temp folder
And to copy your file to a known place, you can use app.filesystem.copyFileAsync: https://www.mediamonkey.com/docs/api/cl ... yFileAsync

All together:

Code: Select all

var fs = app.filesystem;
var sett = window.settings.get('System');
var currentTrack = player.getCurrentTrack();
var coverList = currentTrack.loadCoverListAsync();
// Wait for the coverList to asynchronously load
coverList.whenLoaded().then(function () {
    // Enter a read lock
    coverList.locked(function () {
        // Now you can get the cover object
        var cover = coverList.getValue(0);
        // Get the thumbnail asynchronously
        cover.getThumbAsync(100, 100, function (path) {
            path = path.replace('file:///temp', sett.System.TempDir).replace(/\\/g, '/').replace(/\/\//g, '/');
            var destFile = (fs.getDataFolder() + '/currentCoverArt.jpg').replace(/\\/g, '/').replace(/\/\//g, '/');
            fs.copyFileAsync(path, destFile)
            .then(function () {
                console.log('Success, file is now located at: ' + destFile);
            })
        });
    });
});
The reason for the .replace(/\\/g, '/').replace(/\/\//g, '/'); is to first replace backslashes (\) with forward slashes (/) (to keep it consistent), then to remove any duplicate slashes in case something got messed up.

This will place a file currentCoverArt.jpg into your MediaMonkey 5 data folder (If you're in non portable mode, you can access it via typing %appdata%/MediaMonkey5 in the File Explorer top bar, and if you're in portable mode, you can find it in the Portable subfolder of the install directory.

Btw, I also created an addon for a friend a few months ago that outputs the currently playing track to a file, as we were waiting for SMG to add support for MediaMonkey 5. If you're having trouble with that part as well, feel free to use it as a reference: https://1drv.ms/u/s!AqHzUrf30uprqIxN6QPbm-9VlYnOTg

Hope this helps :wink:
Image
Student electrical-computer engineer, web programmer, part-time MediaMonkey developer, full-time MediaMonkey enthusiast
I uploaded many addons to MM's addon page, but not all of those were created by me. "By drakinite, Submitted by drakinite" means I made it on my own time. "By Ventis Media, Inc., Submitted by drakinite" means it may have been made by me or another MediaMonkey developer, so instead of crediting/thanking me, please thank the team. You can still ask me for support on any of our addons.
crutchcorn
Posts: 32
Joined: Sat Feb 23, 2013 11:38 pm

Re: coverList.getThumb Worked, Now Crashes

Post by crutchcorn »

This is EXTREMELY helpful, holy cow!

Sure enough, your code worked right-off-the-bat first try, thank you!

Is there any way I can help with MM docs, by any chance? There's a fair number of improvements I think could be made (especially to the Wiki). I would make a PR if it were a GH repo, but am unfamiliar with the process required to make suggested changes to the Wiki or reference API docs page

Also, any chance to team is open to suggested code changes within MM itself? I, er, may have spent some time decompiling it to understand how the skin process worked (as I couldn't find that in depth of docs on it) and have some thoughts about how it could be improved without an "API" change of any kind.

Are those allowed threads? (It would be useful to include MM code to talk about exactly how the changes I'd suggest would be implemented, so I want to check first)
drakinite
Posts: 965
Joined: Tue May 12, 2020 10:06 am
Contact:

Re: coverList.getThumb Worked, Now Crashes

Post by drakinite »

I'm happy to help! :grinning:

And if you'd be willing to help me with adding to the Wiki docs, I'd be glad to accept your suggestions/assistance! Writing isn't my strong suit, and I haven't had much spare time to add to the docs. We could connect on Discord or Skype and I can add your suggestions to the wiki.

As for discussing MediaMonkey code on the forum: I'll get back to you on that soon.
Image
Student electrical-computer engineer, web programmer, part-time MediaMonkey developer, full-time MediaMonkey enthusiast
I uploaded many addons to MM's addon page, but not all of those were created by me. "By drakinite, Submitted by drakinite" means I made it on my own time. "By Ventis Media, Inc., Submitted by drakinite" means it may have been made by me or another MediaMonkey developer, so instead of crediting/thanking me, please thank the team. You can still ask me for support on any of our addons.
drakinite
Posts: 965
Joined: Tue May 12, 2020 10:06 am
Contact:

Re: coverList.getThumb Worked, Now Crashes

Post by drakinite »

Regarding discussing MediaMonkey code on the forum: The JavaScript, LESS, and HTML code that's provided with MediaMonkey is freely visible to the public and covered under the Ventis Reciprocal License, and you're welcome to discuss that code publicly, including attaching snippets on the forum. The license gives you limited rights to those files in order to create derivative works, such as addons and skins. (For example: You are welcome to create and distribute a new skin based on one of our sample skins, as long as it follows the license conditions.)

On the other hand, since the native Delphi code is closed source (and not covered by the Ventis Reciprocal License), we ask that if you do decompile or reverse-engineer the native code, that you don't share it publicly. But we (the devs) are always open to discuss it privately in that case.
Image
Student electrical-computer engineer, web programmer, part-time MediaMonkey developer, full-time MediaMonkey enthusiast
I uploaded many addons to MM's addon page, but not all of those were created by me. "By drakinite, Submitted by drakinite" means I made it on my own time. "By Ventis Media, Inc., Submitted by drakinite" means it may have been made by me or another MediaMonkey developer, so instead of crediting/thanking me, please thank the team. You can still ask me for support on any of our addons.
Post Reply