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
coverList.getThumb Worked, Now Crashes
Moderators: jiri, drakinite, Addon Administrators
Re: coverList.getThumb Worked, Now Crashes
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?
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
How to attach PICTURE/SCREENSHOTS to forum posts
Peke
MediaMonkey Team lead QA/Tech Support guru
Admin of Free MediaMonkey addon Site HappyMonkeying
How to attach PICTURE/SCREENSHOTS to forum posts
-
- Posts: 32
- Joined: Sat Feb 23, 2013 11:38 pm
Re: coverList.getThumb Worked, Now Crashes
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`
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`
Re: coverList.getThumb Worked, Now Crashes
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.
Now, the file path that is returned will be something like this:
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:
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:
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
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);
});
});
});
Code: Select all
file:///temp/Thumbs/9D/TIPIRNYZ6UR75JW2-200px.jpg
Code: Select all
var sett = window.settings.get('System');
sett.System.TempDir // returns your temp folder
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);
})
});
});
});
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
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.
-
- Posts: 32
- Joined: Sat Feb 23, 2013 11:38 pm
Re: coverList.getThumb Worked, Now Crashes
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)
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)
Re: coverList.getThumb Worked, Now Crashes
I'm happy to help!
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.
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.
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.
Re: coverList.getThumb Worked, Now Crashes
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.
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.
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.