class Thingfish::Processor::MP3
Attach ID3 data to an mp3, along with any embedded album art as a related resource.
Constants
- APIC_FORMAT
Attached picture “APIC”
Text encoding $xx MIME type <text string> $00 Picture type $xx Description <text string according to encoding> $00 (00) Picture data <binary data>
- NULL
Null character
- PIC_FORMAT
Attached picture “PIC”
Frame size $xx xx xx ---- mp3info is 'helpfully' cropping out frame size. Text encoding $xx Image format $xx xx xx Picture type $xx Description <textstring> $00 (00) Picture data <binary data>
- REVISION
Version control revision
- VERSION
Package version
Public Instance Methods
extract_id3_metadata( mp3info )
click to toggle source
Normalize metadata from the MP3Info object and return it as a hash.
# File lib/thingfish/processor/mp3.rb, line 66 def extract_id3_metadata( mp3info ) self.log.debug "Extracting MP3 metadata" mp3_metadata = { 'mp3:frequency' => mp3info.samplerate, 'mp3:bitrate' => mp3info.bitrate, 'mp3:vbr' => mp3info.vbr, 'mp3:title' => mp3info.tag.title, 'mp3:artist' => mp3info.tag.artist, 'mp3:album' => mp3info.tag.album, 'mp3:year' => mp3info.tag.year, 'mp3:genre' => mp3info.tag.genre, 'mp3:tracknum' => mp3info.tag.tracknum, 'mp3:comments' => mp3info.tag.comments, } # ID3V2 2.2.0 has three-letter tags, so map those if the artist info isn't set if mp3info.hastag2? if mp3_metadata['mp3:artist'].nil? self.log.debug " extracting old-style ID3v2 info" % [mp3info.tag2.version] mp3_metadata.merge!({ 'mp3:title' => mp3info.tag2.TT2, 'mp3:artist' => mp3info.tag2.TP1, 'mp3:album' => mp3info.tag2.TAL, 'mp3:year' => mp3info.tag2.TYE, 'mp3:tracknum' => mp3info.tag2.TRK, 'mp3:comments' => mp3info.tag2.COM, 'mp3:genre' => mp3info.tag2.TCO, }) end end self.log.debug " raw metadata: %p" % [ mp3_metadata ] return sanitize_values( mp3_metadata ) end
extract_images( mp3info ) { |string_io, :format => mime, :extent => length, :relationship => 'album-art'| ... }
click to toggle source
Extract image data from ID3 information, supports both APIC (2.3) and the older style PIC (2.2). Return value is a hash with IO keys and mimetype values. {
io => { format => 'image/jpeg' } io2 => { format => 'image/jpeg' }
}
# File lib/thingfish/processor/mp3.rb, line 110 def extract_images( mp3info ) self.log.debug "Extracting embedded images" raise LocalJumpError, "no block given" unless block_given? unless mp3info.hastag2? self.log.debug "...no id3v2 tag, so no embedded images possible." return end self.log.debug "...id3v2 tag present..." if mp3info.tag2.APIC self.log.debug "...extracting APIC (id3v2.3+) image data." images = [ mp3info.tag2.APIC ].flatten images.each do |img| blob, mime = img.unpack( APIC_FORMAT ).values_at( 4, 1 ) yield( StringIO.new(blob), :format => mime, :extent => blob.length, :relationship => 'album-art' ) end elsif mp3info.tag2.PIC self.log.debug "...extracting PIC (id3v2.2) image data." images = [ mp3info.tag2.PIC ].flatten images.each do |img| blob, type = img.unpack( PIC_FORMAT ).values_at( 4, 1 ) mime = Mongrel2::Config.mimetypes[ ".#{type.downcase}" ] or next yield( StringIO.new(blob), :format => mime, :extent => blob.length, :relationship => 'album-art' ) end else self.log.debug "...no known image tag types in tags: %p" % [ mp3info.tag2.keys.sort ] end end
on_request( request )
click to toggle source
Synchronous processor API – extract metadata from uploaded MP3s
# File lib/thingfish/processor/mp3.rb, line 52 def on_request( request ) mp3info = Mp3Info.new( request.body ) mp3_metadata = self.extract_id3_metadata( mp3info ) request.add_metadata( mp3_metadata ) self.extract_images( mp3info ) do |imageio, metadata| metadata[:title] = "Album art for %s - %s" % mp3_metadata.values_at( 'mp3:artist', 'mp3:title' ) request.add_related_resource( imageio, metadata ) end end
Private Instance Methods
sanitize_values( metadata_hash )
click to toggle source
Strip NULLs from the values of the given metadata_hash
and return it.
# File lib/thingfish/processor/mp3.rb, line 158 def sanitize_values( metadata_hash ) metadata_hash.each do |k,v| case v when String metadata_hash[k] = v.chomp(NULL).strip when Array metadata_hash[k] = v.collect {|vv| vv.chomp(NULL).strip } when Numeric, TrueClass, FalseClass # No-op end end return metadata_hash.delete_if {|_,v| v.nil? } end