Picard 2.3 Release Candidate and call for translation

We have published a release candidate for the MusicBrainz Picard 2.3. After the beta was received very well we had only a couple of fixes but thanks to @rdswift also a couple of nifty new scripting functions.

More details in the blog post:

We plan to release the final version early next week. I expect no changes to the release candidate, but we will update translations again before the final release. It would be great to have some help in checking and improving the translations till February 17th.

The French, German, Dutch, Finnish and Italian translations are already complete. Hebrew is basically complete as well (it is only missing translations of some languages in the “Translate artist names” dropdown). The Chinese (Taiwan) translations is nearly there as well.

If you speak a language other then English and want to help it would be great if you could start looking into the translations to your language at the Picard translation pages. The blog post also has some details on how to do this. And of course the easiest way is to first try the Picard 2.3 Release Candidate in your language first.

9 Likes

For those that want to try the new functions out before the official release, following is a bit of documentation on how to use them:

$reverse(text)

Returns text in reverse order.

$substr(text,start,end)

Returns the substring beginning with the character at the start index, up to (but not including) the character at the end index. Indexes are zero-based. Negative numbers will be counted back from the end of the string. If the start or end indexes are left blank, they will default to the start and end of the string respectively.

$find(haystack,needle)

Finds the location of one string within another. Returns the index of the first occurrance of needle in haystack, or -1 if needle was not found.

$lenmulti(name,separator="; ")

Returns the number of elements in the multi-value tag name. A literal value representing a multi-value can be substituted for name, using the separator (or "; " if not passed) to coerce the value into a proper multi-valued tag.

$getmulti(name,index,separator="; ")

Gets the element at index from the multi-value tag name. A literal value representing a multi-value can be substituted for name, using the separator (or "; " if not passed) to coerce the value into a proper multi-valued tag.

$slice(name,start,end,separator="; ")

Returns a multi-value variable containing the elements between the start and end indexes from the multi-value tag name. A literal value representing a multi-value can be substituted for name, using the separator (or "; " if not passed) to coerce the value into a proper multi-valued tag. Indexes are zero based. Negative numbers will be counted back from the end of the list. If the start or end indexes are left blank, they will default to the start and end of the list respectively.

For example, the following will create a multi-value variable with all artists in %artists% except the first, which can be used to create a “feat.” list.

$setmulti(supporting_artists,$slice(%artists%,1,))

$join(name,text,separator="; ")

Joins all elements in name, placing text between each element, and returns the result as a string.

$map(name,code,separator="; ")

Iterates over each element found in the multi-value tag name and updates the value of the element to the value returned by code, returning the updated multi-value tag. For each loop, the element value is first stored in the tag _loop_value and the count is stored in the tag _loop_count. This allows the element or count value to be accessed within the code script.

$foreach(name,code,separator="; ")

Iterates over each element found in the multi-value tag name, executing code. For each loop, the element value is first stored in the tag _loop_value and the count is stored in the tag _loop_count. This allows the element or count value to be accessed within the code script. A literal value representing a multi-value can be substituted for name, using the separator (or "; " if not passed) to coerce the value into a proper multi-valued tag.

$while(condition,code)

Standard ‘while’ loop. Executes code repeatedly until condition no longer evaluates to True. For each loop, the count is stored in the tag _loop_count. This allows the element or count value to be accessed within the code script. The function limites the maximum number of iterations to 1000 as a safeguard against accidentally creating an infinite loop.

$datetime(format=“%Y-%m-%d %H:%M:%S”)

Returns the current date and time in the specified format, which is based on the standard Python strftime format codes. If no format is specified the date/time will be returned in the form ‘2020-02-05 14:26:32’.

9 Likes

Looking great.
But speaking of ‘call for translations’; I really hope somebody can translate the explanations for each function to English. :wink:
I tried to understand what all these new function do, but most of it is like reading cuneiform to me.

And what really would help: One or two real world script examples for each one.
That would do wonders for understanding why and how you should use these functions.

3 Likes

They look like English to me - at least, the sort of English that is usually used to describe coding functions. I agree that a few more examples would be nice, but I think they are great additions. Hopefully people will build some useful scripts with them, so the examples will be there.
I can see that, as well as making some functions possible through scripts that would previously have required plugins, one can make more use of a script to run strictly after a plugin (getting one plugin to run after another is pretty difficult).

2 Likes

I’ve tried to put together an example to illustrate the use of some of the more difficult to understand (multi-value variable) functions. Note that there is currently a bug in the code for the new $slice function that prevents the following from running, but I tested it with a patched version locally (and submitted the fix to include in the production release of Picard 2.3). The code is intentionally not optimized to better show how each function is used.

EDIT: The bug I thought I found, I now can’t reproduce. Apparently it works fine. Argh!

Problem: You would like the artist (or albumartist) tags to be formatted in a special way, showing all artists after the first one as “feat.” artists, separated by commas and the final one separated by an ampersand (&). Also, you don’t want the list to get too long, so if there are more than 5 artists you want to truncate the list and show “plus N others”, such as:

  • 1 artist: “Ann”
  • 2 artists: “Ann feat. Bob”
  • 3 artists: “Ann feat. Bob & Cat”
  • 4 artists: “Ann feat. Bob, Cat & Don”
  • 5 artists: “Ann feat. Bob, Cat, Don & Eve”
  • 6 artists: “Ann feat. Bob, Cat, Don, and 2 others”
  • 20 artists: “Ann feat. Bob, Cat, Don, and 16 others”

Solution: All cases of this can be handled using the following script, with no additional plugins required.

$if($eq($lenmulti(%artists%),1),
	$noop( Single Artist
			- No need to change 'artist' tag
	),
    $if($eq($lenmulti(%artists%),2),
		$noop( Two Artists
				- Get the first artist [index 0] and save to 'artist' tag.
				- Add " feat. " to 'artist' tag.
				- Get the second artist [index 1] and add to 'artist' tag.
		)
        $set(artist,$getmulti(%artists%,0) feat. $getmulti(%artists%,1)),
        $if($lt($lenmulti(%artists%),6),
			$noop( Three to Five Artists
					- Get the first artist [index 0] and save to 'artist' tag.
					- Add " feat. " to 'artist' tag.
					- Get list of all artists except the first and last.
					- Combine list into a string with artists separated by ", ".
					- Add combined list to 'artist' tag.
					- Add " & " to 'artist' tag.
					- Get last artist [index -1] and add to 'artist' tag.
			)
            $set(_temp,$join($slice(%artists%,1,-1),\, ))
            $set(artist,$getmulti(%artists%,0) feat. %_temp% & $getmulti(%artists%,-1)),

			$noop( More than Five Artists
					- Get the total number of artists and subtract 4 to get the number of "others".
					- Get the first artist [index 0] and save to 'artist' tag.
					- Add " feat. " to 'artist' tag.
					- Get list of the second to forth artists.
					- Combine list into a string with artists separated by ", ".
					- Add combined list to 'artist' tag.
					- Add ", plus " to 'artist' tag.
					- Add the count of "others" to 'artist' tag.
					- Add "others" to 'artist' tag.
			)
            $set(_count,$sub($lenmulti(%artists%),4))
            $set(_temp,$join($slice(%artists%,1,4),\, ))
            $set(artist,$getmulti(%artists%,0) feat. %_temp%\, plus %_count% others)
        )
    )
)
2 Likes

Should it work like this? (it doesn’t) :
$set(updated,%datetime%)

Nope. Try $set(updated,$datetime())

Thanks!

(now you see what you are dealing with here? :wink: )

(btw, I did try $set(updated,$datetime) , but that was refused as a valid script)

1 Like

Add to that list English (UK), English (Canada) and English (Australia). Also complete.

To keep it clearer only those words and phrases needing translation get translation from English(US) to English, that means it will never show “100%” in the stats.

(Any idea how to add NOTES to Transflex? It is such an anonymous area that I would like to add a note to those three languages that explain why so many of the strings are left untouched \ (US). Mainly so if any of those dozen previous editors suddenly appeared they would know not to trash the work I have done since.)

The lack of feedback in the app when it is busy on Windows is a little weird. Today I have five albums in Picard all part of a boxset and all FLAC. Picard is being VERY slow at updating these files. 100MB FLACs with embedded artwork.

Missing: Why is the old “wait” cursor not enabled? I still have a pointer, but the app is way too busy to let me do anything. When such a slow set of edits is happening it would be good to get some clearer “I am busy, go away” message on screen. Or just change to the old fashioned BUSY cursor.

If I click on the app while in this state, it will “white out” and go “not responding” in the task bar.

BUG: The app then minimises to the task tray and looses the progress colours on the icon. After a short period those colours restart forgetting how far it has gone.

The (Not responding) state appears in Windows when an app is busy, but many users will assume this means it has crashed and not wait.

BUG: The status bar is stuck on the first track name. It is not updating when the files are being edited.

NOTE: These were clearly badly encoded FLAC files. Next time I hit SAVE in Picard it has whizzed through the lot in seconds. Nice that a Bonus Feature of Picard is to fix dodgy FLAC frames. :smiling_face_with_three_hearts:

1 Like

Yes, the performance issues on saving are well known, see e.g. PICARD-598, PICARD-744 and related issue. This is most notable when saving large files (like in your case) or saving on slow filesystems. Basically there are two things: 1) Saving progress is slower than it ought to be in theory and 2) the UI becomes very sluggish while saving. For this release there haven’t been any optimizations in this regard.

I can’t reproduce this. Is this happening for you when Picard is not busy?

The cause for what you experiences is most likely something else: The new tags you wrote contained more data then what was available in the tag sections of the files (because you wrote more data then what was present in the files). If this happens the entire file needs to be rewritten, which with large FLAC files can be a significant amount of data. Usually the files contain some blank space (aka padding) between the existing metadata and the rest of the file to accommodate newly written data, but that’s often not enough if the file previously only contained very basic tags. The second time you save the files only the tag block needs to be written, making the process much faster. But your files are fine, that’s just normal tag handling.

3 Likes

You’ve missed the point of the report. :slight_smile: I am not commenting on the slow writing on bad FLACs. That is expected. Totally understand why so much data to be rewritten then naturally causes a CPU load. That is not the issue I was trying to show. It is just that cruddy files cause the real issue to show up.

It would be so much better if there was something on screen for the impatient. Otherwise it looks like it has crashed. If a rewrite of the FLACs are being needed - whack a modal dialog box in the middle of the middle of the screen with a “please wait… processing” on top of everything else.

This process must have taken about five minutes on the test data. (Again I can offer those cruddy files for testing purposes if required)

ALL of this test report was written while Picard was locked up processing the heap of bad FLACs. I also was awkward and did click on it a few times, minmised it, harrassed it. Thinking like a dumb ID-10T user who is impatient. There was not crash doing this, but it did show the constantly stuck track name on the status bar. And that strange restarting of the progress colours on the task bar icon.

Once the files had all been re-written the status bar text went away.

Yes, I know I stress your app out in weird ways. But it is for the love of Picard that I give it a good kicking. And it always stands up well. It certainly did a good job of surviving the beating I gave it.

Edit: just to add some notes after reading those tickets. My test data is on the same Windows PC. OS, Apps and Music files are stored on three separate hard disks. All NTFS. Therefore all local to the running app. In those tickets I see people editing over networks and other distant locations. They would also benefit from the “Please wait… I’m busy” message popping up on screen when heavy processing like that starts.

Ok, got it. I think our preferred solution would be to keep the UI responsive enough to be usable, blocking the UI with a notice seems like a crutch. But I’ll consider this. The tricky part here is to decide when to show this dialog. I definitely don’t want Picard to block the UI whenever it is doing some task.

2 Likes

Absolutely agree that would be the ideal dream. But see this as a way to buy you the dev a bit of time while a speedier backend is created. You can’t magically fix the writing speed overnight, but the message box to give more feedback to the user can be used as a warning for now.

(Especially think of those mad people who throw thousands files at Picard and expect it to handle them…)

As to “when to show the dialog”? if you have more than five tracks, and the first track takes longer than a few seconds or is triggering a specific “re-write that file” function, then up comes the “Please Wait 'cos I am working really hard” box.

I am guessing you know the kind of routines that cause more work. :slight_smile:

1 Like