http://qs1969.pair.com?node_id=896405


in reply to I need help about MP3::Tag and perl script.

Oh, and cover art is a whole different challenge. Here's how I do it (for ID3v2 and jpg images).

use constant COVERART_LOCATOR => "coverart"; use constant PICTURE_TYPE => "Cover (front)"; use constant PICTURE_COMMENT => "Cover Image"; use constant APIC => "APIC"; sub attach { # Find a suitable image and attach it to the suggested mp3 file my($track,$mp3_file,$image_file) = @_; return undef if(!defined $image_file); if(!-w $mp3_file) { # This shouldn't happen but... chmod 0755,$mp3_file; } if(!-w $mp3_file) { carp("Cannot write to $mp3_file"); return undef; } my $mp3 = MP3::Tag->new($mp3_file); if(!defined $mp3) { carp("Cannot read tags from $mp3_file"); return undef; } # Attempt to read the tags $mp3->get_tags(); if(!defined $mp3->{ID3v2}) { # Need to create a new set of tags $mp3->new_tag("ID3v2"); } if(!defined $mp3->{ID3v2}) { carp("Cannot create ID3v2 tags in $mp3_file"); return undef; } my($mime_type,$image_data) = read_image($image_file); return undef if(!defined $mime_type); my $encoding = 0; my @apic_parts = ($encoding, $mime_type, picture_type_idx(PICTURE_TYPE), PICTURE_COMMENT, $image_data); if(defined $mp3->{ID3v2}->get_frame(APIC)) { # Modifying an existing image $mp3->{ID3v2}->change_frame(APIC,@apic_parts); } else { # Create a new frame $mp3->{ID3v2}->add_frame(APIC,@apic_parts); } $mp3->{ID3v2}->write_tag(); return $image_file; } sub read_image { # Read the image file my($file_name) = @_; my $image_type; my $image_data; if(!-f $file_name) { error("Cannot read file \"$file_name\""); return; } if($file_name =~ /\.jpg$/i) { $image_type = "jpg"; my $ifh = IO::File->new($file_name); if(!defined $ifh) { error("Failed to open \"$file_name\""); return; } binmode $ifh; $image_data = ""; # This reads the data in 16k chunks, but the images should be +small anyway while(!$ifh->eof()) { my $c = $ifh->read($image_data,1024*16,length($image_data) +); } $ifh = undef; } if(!defined $image_type) { error("Does not yet support file type for \"$file_name\""); return; } if(!defined $image_data) { error("Cannot extract $image_type data from \"$file_name\""); return; } return("image/$image_type",$image_data); } sub picture_type_idx { # Given a picture type string convert it into a number suitable # for MP3::Tag my($picture_type) = @_; # The picture types that are currently understood (from MP3::Tag:: +ID3v2): my @picture_types = ("Other", "32x32 pixels 'file icon' (PNG only)", "Other file +icon", "Cover (front)", "Cover (back)", "Leaflet page", "Media (e.g. lable side of CD)", "Lead artist/lead performe +r/soloist" , "Artist/performer", "Conductor", "Band/Orchestra", "Compose +r", "Lyricist/text writer", "Recording Location", "During recor +ding", "During performance", "Movie/video screen capture", "A bright coloured fish", "Illustration", "Band/artist logo +type", "Publisher/Studio logotype"); # This approach is easy to understand for(my $i=0;$i<=$#picture_types;$i++) { if(lc($picture_type) eq lc($picture_types[$i])) { return chr($i); } } error("The picture type \"$picture_type\" is not valid"); return chr(3); }

Update: This defines a new subroutine called attach(). The first parameter has no affect (its important in my script but for your purposes you can ignore it). Suppose you want to attach a file "foo/cool.jpg" to an mp3 file called "1.mp3" as the front cover, you would just do (untested)

attach("","1.mp3","foo/cool.jpg");

This, of course, requires that you add the appropriate packages and copy the definition of the subroutine somewhere into your script.

Replies are listed 'Best First'.
Re^2: I need help about MP3::Tag and perl script.
by afoken (Chancellor) on Mar 31, 2011 at 09:10 UTC
    if(!-w $mp3_file) { # This shouldn't happen but... chmod 0755,$mp3_file; }

    Why do you try to make an MP3 file world executable if you can't read it? And why do you make it readable for group and world? Why do you even think about changing the mode of files that are not writeable?

    There are usually good reasons for chmod -w somefile and chmod go-rw somefile: I don't want to accidentally modify a file in the first case, and I don't want others to read my files in the second case. Your hardcoded chmod 0755 ignores both. To make things worse, it sets the executable flag, possibly creating a new vulnerability.

    I won't start with race conditions between stat (implied in -w) and open, because MP3::Tag has the same problem, so your code does not make it worse in this special case. Generally, one should not try to predict if open fails or succeeds by using stat. It can't work reliably (race condition), and it is not needed. open sets errno a.k.a. $! on error, and errno delivers sufficient information why open failed.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
      First of all thank you very much about sharing your experiences with me. But could you please try a simple method cuz I do not understand anything at all I am learning perl now. So If you wrilte down the script again with my needs that I mention before. It wil be awesome and I would learn one thing about perl too. Waiting your support..
        So If you wrilte down the script again with my needs

        I have absolutely no interest in such a project, so I won't write any code for free. Until you make the project interesting for me by stacking a lot of cash on my desk and sign a contract with me, you will have to either search for someone else to write code for you (rent-a-coder ...), or learn Perl.

        For learning Perl, perlmonks is the right place. But you must show substancial effort to learn. Repeating the same question over and over again, and begging for an instant solution is the wrong way.

        Regarding the style of your postings in this thread:

        For me (and perhaps many others around here), postings full of "leet speek", spelling errors, complete lack of formatting, wrong interpunction, written within 10 seconds and without any check for errors indicate lack of interest and lack of respect.

        I'm not saying that all of your postings are that bad, perhaps only a few or just the ones in this thread. But your posting was the straw that broke the camel's back.

        I know from my own experience that it is hard to write in a foreign language. But it is even harder to read such postings. I read and write on perlmonks for fun, in my free time, and I don't get money for that. So, why should I even consider reading a posting that looks more like line noise than english? There are about 100 postings a day, and most of them are easily readable. Reading them can be fun, finding the problem or knowing the right answer is even more fun.

        I have no problems with posting code fragments here or elsewhere, perhaps even a complete program. Sometimes, 10 lines of code are better than 1000 words. But I have a huge problem with being treated as the idiot that does your job or homework for free. So, no code for you. Especially not ready-to-run code.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re^2: I need help about MP3::Tag and perl script.
by osmy (Initiate) on Mar 30, 2011 at 15:34 UTC
    wow that's awesome thanks. But I don't know where to edit the code. I understand logically but not enough knowledge. I try to be simple. Where should I write file name artist album song title cover picture name and location. for example: 1.mp3 will be the mp3 file imported and edited , these are the fixed edits
    song title is : xyz
    artist name:xx
    album:tt
    cover picture: /cool.jpg so where should I write these datas on your script. Remember I will set a cron and run this script so mp3 file on my server will have id3tag changed or edited by me more clear and tidy mp3 =)