Perl: How to retrieve album metadata from MusicBrainz? - perl

I am creating a Perl script which will move a mp3 file to my music folder in format artist/album/mp3file. Now it is possible that some of my mp3 files don't have an album tag so I thought of querying the MusicBrainz database to retrieve album metadata given track title & artist.
I am using WebService::MusicBrainz Perl module for this task, but I am not able to see any method that gives album metadata info. My current code is:
use WebService::MusicBrainz::Track;
my $ws = WebService::MusicBrainz::Track->new();
my $response = $ws->search({ ARTIST => 'Ryan Adams', TITLE => 'when the stars go blue' });
my $track = $response->track();
print $track->title(), " - ", $track->artist()->name(), "\n";
say $track->id();
So, how do I get my the album info for a given track using MusicBrainz and if it is not possible what are my alternative options?

First of all, what you want is adding metadata to mp3s which is the most common usage scenario people have. The "normal" way is to use a Musicbrainz Tagger, open these files there and work with the interface to attach the correct metadata.
The suggested (gui) tool is Musicbrain Picard
I also want to state that the Perl module is using the now deprecated Web Service Version 1 of MusicBrainz.
That Web Service has a couple of problems because it was made for another database scheme than the one used now at MusicBrainz.
However, the current Web Service Version 2 has only a python library available: python-musicbrainzngs.
You can still work with the Perl module, but if you run into "weird" problems, this might be the reason.
This is how the Web Service works in general (and how it should apply directly for the Perl module as a wrapper for this web service):
Your search gives this:
http://musicbrainz.org/ws/1/track/?artist=%22Ryan%20Adams%22&title=%22when%20the%20stars%20go%20blue%22
There you get a list of recordings of this track. These recodings occur on multiple releases (ReleaseList).
You can disregard many of these, as they are of the type "compilation". You probably want the "album" releases.
You probably ask yourself why there are multiple album releases with the same name in the list.
This is because a "release" on MusicBrainz is a combination of a release-event and a couple of mediums.
You might have an US release and a german deluxe edition and so on.
All of these releases are in one "release group".
You probably want the name of this "release group", which mostly is also the name of every release in this group.
You might want to read a bit on how the MusicBrainz Database is structured.
This is only the basic use case of course.
You might run into misspellings in artist/title, multiple or missing album release groups and other things.
However, altogether it should work and you can just drop the "problem" cases in a special directory and work with them in Picard.
Picard also has other means of identifying files per "musical analysis" (PUIDs, Acoustids)
EDIT:
my #tracklist = $response->track_list();
foreach my $track ( #tracklist ) {
print $track->title(), " - ", $track->artist()->name(), "\n";
my #releaselist = $track->release_list();
foreach my $release ( #releaselist ) {
print " ", $release->title(), " - ", $release->type();
}
}
Should work in general, but it doesn't. It gives you all tracks of the response, but somehow it can't extract releases from release_list(). Possibly because the schema changed or because the perl module is broken.

Check out our perl modules for accessing the Cover Art Archive:
http://metacpan.org/pod/Net::CoverArtArchive
More info on our archive is here, including specs:
http://coverartarchive.org/
Good luck!

Related

Migrating from itext2 to itext7

Years ago, I wrote a small app in itext2 to gather reports on a weekly basis and concatenate them into one PDF. The app used com.lowagie.text.pdf.PdfCopy to copy and merge the PDFs. And it worked fine. Performed exactly as expected.
A few weeks ago I looked into migrating the application to itex7. To that end, I used the copyPagesTo method of com.itextpdf.kernel.pdf.PdfDocument. When run on the same file set, this produces warnings like:
WARN PdfNameTree - Name "section.1" already exists in the name tree; old value will be replaced by the new one.
When I click on the link to "section.1" in the first document of the merged PDF, I am taken to "section.1" of the last document. Not what I expected and not what happens when using the itext2 app. In the PDF's produced by itext2, if I click on the link to "section.1" of the first document in the combined PDF, I am taken to section 1 of the first document.
There is a hint in Javadocs for copyPagesTo saying
If outlines destination names are the same in different documents, all
such outlines will lead to a single location in the resultant
document. In this case iText will log a warning. This can be avoided
by renaming destinations names in the source document.
There is however, no explanation of how this should be done. I find it odd that this should be necessary in itext7, although it wasn't in itext2.
Is there a simple way to get around his problem?
I've also tried the Sejda desktop app and it produces correct results, but I would prefer to automate the process through a batch script.
My guess is iText 2 didn't even know it might be a problem.
If iText can't deduplicate destination names, the procedure is roughly:
Follow /Catalog -> /Names -> /Dests in each document to find the destination name tree.
Deduplicate the names, by adding suffixes. Remember that a name with a suffix added might be equal to an existing name in the same or another document. Be careful!
Now you can rewrite the destination name trees. Since you have only used suffixes, you can do this in place - the lexicographic ordering of the names is unaltered so the search tree structure is not broken.
Now, rewrite destination links in each PDF for the new names. For example any dictionary entry with key /Dest, or any /D in a /GoTo action.
Now, after all this preprocessing, the files will merge without name clashes.
(I know all this because I've just implemented it for my own PDF software. It's slightly hairy stuff, but not intractable.)
If you like, I can provide a devel version of cpdf with this functionality, if you would like to test it.

Modifying MP3 file header text info

Is there a method I can use in a program to access and modify ripped music CD-MP3 file(s) header text?
There is a method available in the MusicMatch jukeboks music player, but with 2000 files ripper from 50 CD's, the job is quite formidable and the tool "supertagging' is cumbersome to use.
What I see for me is more like the visual representation of Excel, where I would have just the three fields Artist name, Song title and Album name. displayed.
The Artist field would have the option of repeating the top field down for all the song titles, Album would always be repeted for all song titles.
Song titles wil of course have to be entered for each item.
In the ripped files, every file has the fields track#, artist, album + some of less importance.
Just let me know if I am at the wrong forum for my search. I just don't know anywhere else that I might go.
For programming I might use Visual Foxpro and/or assembler. I haven't used C since early 1980's.
If you really want to develop it yourself, at least use an ID3 library, don't write the functionality yourself!
A good one is at http://id3lib.sourceforge.net/. I haven't tried it recently, but I'm sure you can call it from VFP somehow.
If you just want something that is better for tagging a shed-load of files, look at MediaMonkey.
If you want to work solely in VFP then you should use the VFP low-level utilities
FOPEN()
FCHSIZE( )
FCLOSE( )
FCREATE( )
FEOF( )
FFLUSH( )
FGETS( )
FPUTS( )
FREAD( )
FSEEK( )
FWRITE( )
These are pretty well documented within the VFP Help system and there are numerous examples on the web.
With them you can get the 'raw' data from the MP3 file, identify what you are looking for, change it, and write it back again.
The downside is that specific 'fields' (e.g. Artist name, Song title and Album name, etc.) will not be readily recognized. You would need to write code to identify these and then identify where the values reside.
Good Luck

How to use bugzilla API in existing bugzilla code?

Well, at the moment i have two goals.
User don't have Edit bug rights in bugzilla, but he/she should write/post comments on that bug. I think this could be possible by the following API, but I am not sure, since I am new in bugzilla and Perl. http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService/Bug.html#add_comment
I want to import bugs by using importxml.pl, but I don't want new entries in DB. I just want to modify some fields of existing bugs of bugzilla, on the base of bug.xml file which contains bug info.
i.e. perl -T C:\bugzilla\bugzilla\importxml.pl -v C:\bugzilla\bugzilla\mybugs\bug.xml
Might be following API could be helpful, but I am not sure.
http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService/Bug.html#update
So, what are possible ways to achieve these goals ??
As I am thinking, may be i should use the methods of these APIs into existing bugzilla code and my dreams are:
comments would be enabled for the user who don't have bug-edit right.
I'll run the importxml.pl script from command line by passing some parameters and I'll modify some fields of existing bugs.
But I am not sure, either I am thinking right or wrong. I also don't know how to use the method of these APIs??
The email_in.pl script can do the types of things you are asking. However, you will need to create a user that does have permissions to make the changes and you will need to transform the data into a form that email_in.pl understands.
http://www.bugzilla.org/docs/4.2/en/html/api/email_in.html
I can help with the first point:
Here's an excerpt from a a svn_bz_append.pl script (http://www.telegraphics.com.au/svn/svn_bz/trunk/) that I've modified that I use to update bugzilla comments on svn commits. Note that I have this script running on the same machine as the Bugzilla install, as it uses modules from within the Bugzilla directory. I have this working for Bugzilla v 4.2.3.
I've omitted quite a bit of this script to pull out the excerpt below:
use strict;
use warnings;
use Bugzilla;
use Bugzilla::Config;
use Bugzilla::Bug;
use Data::Dumper;
... create/fetch the userid and some bug Ids to work on ...
eg:
my $userid = 1;
my #bugs = ( 1, 2, 3 );
my $message = 'Say something here';
... now loop through the bug ids and add the comment...
foreach my $bugId (#bugs) {
my $user = new Bugzilla::User({ id => $userid})
|| ThrowUserError('invalid_username', { id => $userid}); #get the user from bugzilla
print STDERR 'user: '. Dumper($user); #pretty prints the user object
Bugzilla->set_user($user); #this authenticates the user so that you may perform actions on bugs that the user has permissions to.
my $bug = Bugzilla::Bug->check($bugId); #gets the bug
print STDERR 'bug: '. Dumper($bug); #pretty prints the bug object
$bug->add_comment($message); #adds a comment to the bug
$bug->update(); #updated the bug - don't forget to do this!
}
Please note that the Dumper functions are just using the excellent Data::Dumper module: http://perldoc.perl.org/Data/Dumper.html - you don't need them except for debugging.
The log in info came from: How can I authenticate when using the Bugzilla Perl API in a script?

Selenium WebDriver with Perl

I am trying to run the Selenium driver with Perl bindings, and due to the lack of examples and documentation, I am running into some roadblocks. I have figured out how to do some basic things, but I seem to be running into some issues with other simple things like validating the text on a page using Remote::Driver package.
If I try to do something like this:
$sel->get("https://www.yahoo.com/" );
$ret = $sel->find_element("//div[contains( text(),'Thursday, April 26, 2012')]");
I get a message back that the element couldn't be found. I am using xpath because the driver package doesn't appear to have a sub specific for finding text.. at least not that I've found.
If my xpath setup is wrong or if someone knows a better way, that would be extremely helpful. I'm having problems with some button clicking too.. but this seems like it should be easier and is bugging me.
Finding text on a web page and comparing that text to some "known good value" using Selenium::Remote::Driver can be implemented as follows:
File: SomeWebApp.pm
package SomeWebApp;
sub get_text_present {
my $self = shift;
my $target = shift;
my $locator = shift;
my $text = $self->{driver}->find_element($target, $locator)->get_text();
return $text;
}
Somewhere in your test script: test.pl
my $text = $some_web_app->get_text_present("MainContent_RequiredFieldValidator6", "id");
The above finds the element identified by $target using the locating scheme identified by $locator and stores it in the variable $text. You can then use that to compare / validate as required / needed.
https is a tad slower loading than http. Although WebDriver is pretty good about waiting until it's figured out that the requested page is fully loaded, maybe you need to give it a little help here. Add a sleep(2); after the get() call and see if it works. If it does, try cutting down to 1 second. You can also do a get_title call to see if you've loaded the page you think you have.
The other possibility is that your text target isn't quite exactly the same as what's on the page. You could try looking first for one word, such as "April", and see if you get a hit, and then expand until you find the mismatch (e.g., does this string actually have a newline or break within it? How about an HTML entity such as a non-breaking space?). Also, you are looking for that bit of text anywhere under a div (all child text supposedly is concatenated, and then the search done). That would more likely cast too wide a net than not get anything at all, but it's worth knowing.

list elements by activity

I'm working on automated builds and need to be able to list elements that were worked on under particular activities. I'm new to ClearCase so I apologise for naiivety ...
My downstream build process works fine and I now need to populate a 'pre-build' area by identifying the (checked-in) files associated with one or more activities, labels etc (in fact any combination the change/release manager wants) by listing the candidate files for a build and then copying them from the M: drive (Windows). We are using CC 7.1 with a back end on AIX and Win XP Pro desktops. We'll use ccperl to drive the find+copy process.
I have battled with 'find' to no avail - can someone lend a hand? All help gratefully received.
Cliff.
For "label" (I suppose "UCM Baselines" since you mention "activities", which exist only with UCM):
The easiest way would be to configure a config spec for a dynamic view:
element * MY_BASELINE
in order to quickly access the right files.
For activities, you could (if there is not too much files involved), list the exact versions of each activities you want:
cleartool descr -l activity:my_actity#\pvob
and parse the result to grep/awk only what you need.
You need only to do this within a dynamic view (any dynamic view): the activity will contain a list of extended pathnames, meaning you will be able to access and copy each version through that myFile##/main/myBranch/myVersion path.