Class: Thingfish::Processor::MP3

Inherits:
Thingfish::Processor
  • Object
show all
Extended by:
Loggability
Defined in:
lib/thingfish/processor/mp3.rb

Overview

Attach ID3 data to an mp3, along with any embedded album art as a related resource.

Constant Summary collapse

VERSION =

Package version

'0.1.0'
REVISION =

Version control revision

%q$Revision: b0c42d67ea2f $
NULL =

Null character

"\x0"
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>
'h a3 h Z* a*'
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>
'h Z* h Z* a*'

Instance Method Summary collapse

Instance Method Details

#extract_id3_metadata(mp3info) ⇒ Object

Normalize metadata from the MP3Info object and return it as a hash.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/thingfish/processor/mp3.rb', line 67

def ( mp3info )
	self.log.debug "Extracting 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:artist'].nil?
			self.log.debug "   extracting old-style ID3v2 info" % [mp3info.tag2.version]

			.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" % [  ]
	return sanitize_values(  )
end

#extract_images(mp3info) ⇒ Object

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' }

}

Raises:

  • (LocalJumpError)


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/thingfish/processor/mp3.rb', line 111

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) ⇒ Object

Synchronous processor API – extract metadata from uploaded MP3s



53
54
55
56
57
58
59
60
61
62
63
# File 'lib/thingfish/processor/mp3.rb', line 53

def on_request( request )
	mp3info = Mp3Info.new( request.body )

	 = self.( mp3info )
	request.(  )

	self.extract_images( mp3info ) do |imageio, |
		[:title] = "Album art for %s - %s" % .values_at( 'mp3:artist', 'mp3:title' )
		request.add_related_resource( imageio,  )
	end
end