This is a sleazy module for reading OGG Vorbis tags from files, without using C or libvorbis-perl.

 I wanted something standalone for my MP3/OGG streamer.

# # Sample usage: # # my $reader = gnump3d::oggtagreader->new( ); # my %tags = $reader->getTags($file); # print "File: $file\n"; # print "Title: " . $tags{'artist'} . "\n"; # # package gnump3d::oggtagreader; # must live in oggtagreader.pm # # Create a new instance of this class. # sub new { my $classname = shift; # What class are we constructing? my $self = {}; # Allocate new memory bless($self, $classname); # Mark it of the right type return $self; } # # Read and return a hash of all the tags found in the given file. # # This is a very simplistic algorithm, which may not work for you. # # sub getTags($) { my($self, $filename ) = (@_); open(OGG, "<$filename" ) or die "can't open $filename: $!" +; binmode(OGG); my $buff = ""; read(OGG, $buff, 2048); close( OGG ); my %TAGS = (); $TAGS{'artist'} = getTag( $buff, "artist" ); $TAGS{'title'} = getTag( $buff, "title" ); $TAGS{'album'} = getTag( $buff, "album" ); $TAGS{'comment'} = getTag( $buff, "comment" ); $TAGS{'genre'} = getTag( $buff, "genre" ); $TAGS{'track'} = getTag( $buff, "tracknumber" ); return( %TAGS ); } # # Find a given tag in the buffer read from the file in # our 'getTags' method # sub getTag( $ $ ) { my ( $buff, $tag ) = (@_); $buff =~ s/[[:^print:]]/=/g; if ( $buff =~ /$tag=([^=]+)/i ) { my $value = $1; return( $value ); } return( undef ); } # # End of module # 1;

Replies are listed 'Best First'.
Re: Ogg Vorbis tag parsing in pure perl
by Aristotle (Chancellor) on Dec 17, 2002 at 19:52 UTC
    Prototypes in Perl are not what you think they are. Leave them out unless you know why you should. Not to mention they're entirely useless here because there is (and can be) no prototype checking on method calls. You can also condense the code significantly.
    package gnump3d::oggtagreader; # untested sub new { bless \(undef), shift } sub get_tags { my($self, $filename) = @_; # using lexical filehandles is much safer # die()ing here is probably not the best way to handle failures he +re open(my ($fh), "<", $filename) or return; binmode $fh; read $fh, my ($buffer), 2048; $buffer =~ s/[[:^print:]]/=/g; my %info = map +($_ => /$_=([^=]+)/i), qw(artist title album comment genre tracknumber); $info{track} = delete $info{tracknumber} if exists $info{tracknumber}; return %info; } 1;
    It is probably still better to implement something that conforms to the docs (http://reactor-core.org/ogg-tag-standard.html, http://www.xiph.org/ogg/vorbis/doc/v-comment.html).

    Makeshifts last the longest.

       Thanks for the feedback, I like the trick with the map, I knew the tag finding could be done in a better manner - I don't know why I didn't see that earlier!

       I should really be using one of the real tag parsing packages; this code is meant to be a fallback position if OGG::Vorbis can't be found.

       (I prefer to have code running minimally rather than dying when modules aren't found; if at all possible)

      Steve
      ---
      steve.org.uk
      Aristotle,

      I don't understand the map syntax used in your code example.
      I know you marked this as untested, but thought I would ask for clarification
      in case this was not a typo of some sort and I was missing something.
      Does the "map +( )" syntax have a special purpose? I was unable to get the code to work as is,
      and I had to modify my version a bit to get it to work.

      my %info = map { $_ => $buffer =~ /$_=([^=]+)/i } qw(artist title albu +m genre comment);

      Any help is much appreciated, as always.
      Wonko.
        No real difference. The + is just there as a hint for Perl that what's in the parens should be map's expression, not a parenthesized list of arguments much like you might say print +($x + 1) * 3; to get the meaning of print(($x + 1) * 3); rather than the default parsing result of (print($x + 1)) * 3;. I've had success making it work that way for map, but apparently the rules are not quite so simple as I thought. Functionally, it's supposed to be just the equivalent to what you used. It just bugged me to have to use a BLOCK whenever I'm mapping an array to a hash.

        Makeshifts last the longest.

Re: OGG Vorbis tag parsing in pure perl
by benn (Vicar) on Dec 18, 2002 at 11:27 UTC
    And to make it shorter still, in true KISS fashion, dispense with the OO :) With a single method returning a hash, there's no need to be passing objects around. If the module gets fancy and extended and you want to read lots of files at the same time or something, then fine...but personally I'd say you just want a single sub.

    phew kids today eh? it's all 'object this' and 'class that'...when I were a lad, all this were procedures...
      Back when I were a lad all we had were goto's ;) Steve
      ---
      steve.org.uk
Re: Ogg Vorbis tag parsing in pure perl
by Aristotle (Chancellor) on Dec 31, 2002 at 18:03 UTC