thingfish 0.5.0.pre20161103181816 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Procfile DELETED
@@ -1,4 +0,0 @@
1
- # Foreman procfile
2
- mongrel: m2sh.rb -c etc/mongrel2.sqlite start
3
- thingfish: ruby -Ilib:../Thingfish-Datastore-Filesystem/lib:../Mongrel2/lib bin/thingfish etc/thingfish.conf
4
-
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'thingfish/processordaemon'
4
-
5
- Thingfish::ProcessorDaemon.run( ARGV )
6
-
@@ -1,26 +0,0 @@
1
- ---
2
- logging:
3
- __default__: debug STDERR
4
- thingfish: info (color)
5
-
6
- # Thingfish specific configuration.
7
- #
8
- thingfish:
9
- datastore: memory
10
- metastore: memory
11
-
12
- # The path to the Mongrel2 config database.
13
- #
14
- mongrel2:
15
- configdb: example/mongrel2.sqlite
16
-
17
- # Strelka configuration knobs that influence Thingfish's handler.
18
- #
19
- app:
20
- devmode: false
21
- app_glob_pattern: '{apps,handlers}/**/*'
22
- local_data_dirs: data/*
23
- multipartparser:
24
- bufsize: 524288
25
- spooldir: /var/folders/1f/6ymhh79s0n3gjdw16fj7tp480000gp/T/strelka-mimeparts
26
-
@@ -1,167 +0,0 @@
1
- # -*- ruby -*-
2
- #encoding: utf-8
3
-
4
- require 'mp3info'
5
-
6
- require 'thingfish' unless defined?( Thingfish )
7
- require 'thingfish/processor' unless defined?( Thingfish::Processor )
8
-
9
-
10
- # Attach ID3 data to an mp3, along with any embedded album art as a related resource.
11
- class Thingfish::Processor::MP3 < Thingfish::Processor
12
- extend Loggability
13
-
14
- # Loggability API -- log to the :thingfish logger
15
- log_to :thingfish
16
-
17
- # The list of handled types
18
- handled_types 'audio/mpeg', 'audio/mpg', 'audio/mp3'
19
-
20
-
21
- # Null character
22
- NULL = "\x0"
23
-
24
- # Attached picture "PIC"
25
- # Frame size $xx xx xx
26
- # ---- mp3info is 'helpfully' cropping out frame size.
27
- # Text encoding $xx
28
- # Image format $xx xx xx
29
- # Picture type $xx
30
- # Description <textstring> $00 (00)
31
- # Picture data <binary data>
32
- PIC_FORMAT = 'h a3 h Z* a*'
33
-
34
- # Attached picture "APIC"
35
- # Text encoding $xx
36
- # MIME type <text string> $00
37
- # Picture type $xx
38
- # Description <text string according to encoding> $00 (00)
39
- # Picture data <binary data>
40
- APIC_FORMAT = 'h Z* h Z* a*'
41
-
42
-
43
- ### Synchronous processor API -- extract metadata from uploaded MP3s
44
- def on_request( request )
45
- mp3info = Mp3Info.new( request.body )
46
-
47
- mp3_metadata = self.extract_id3_metadata( mp3info )
48
- request.add_metadata( mp3_metadata )
49
-
50
- self.extract_images( mp3info ) do |imageio, metadata|
51
- metadata[:title] = "Album art for %s - %s" % mp3_metadata.values_at( 'mp3:artist', 'mp3:title' )
52
- request.add_related_resource( imageio, metadata )
53
- end
54
- end
55
-
56
-
57
- ### Normalize metadata from the MP3Info object and return it as a hash.
58
- def extract_id3_metadata( mp3info )
59
- self.log.debug "Extracting MP3 metadata"
60
-
61
- mp3_metadata = {
62
- 'mp3:frequency' => mp3info.samplerate,
63
- 'mp3:bitrate' => mp3info.bitrate,
64
- 'mp3:vbr' => mp3info.vbr,
65
- 'mp3:title' => mp3info.tag.title,
66
- 'mp3:artist' => mp3info.tag.artist,
67
- 'mp3:album' => mp3info.tag.album,
68
- 'mp3:year' => mp3info.tag.year,
69
- 'mp3:genre' => mp3info.tag.genre,
70
- 'mp3:tracknum' => mp3info.tag.tracknum,
71
- 'mp3:comments' => mp3info.tag.comments,
72
- }
73
-
74
- # ID3V2 2.2.0 has three-letter tags, so map those if the artist info isn't set
75
- if mp3info.hastag2?
76
- if mp3_metadata['mp3:artist'].nil?
77
- self.log.debug " extracting old-style ID3v2 info" % [mp3info.tag2.version]
78
-
79
- mp3_metadata.merge!({
80
- 'mp3:title' => mp3info.tag2.TT2,
81
- 'mp3:artist' => mp3info.tag2.TP1,
82
- 'mp3:album' => mp3info.tag2.TAL,
83
- 'mp3:year' => mp3info.tag2.TYE,
84
- 'mp3:tracknum' => mp3info.tag2.TRK,
85
- 'mp3:comments' => mp3info.tag2.COM,
86
- 'mp3:genre' => mp3info.tag2.TCO,
87
- })
88
- end
89
- end
90
-
91
- self.log.debug " raw metadata: %p" % [ mp3_metadata ]
92
- return sanitize_values( mp3_metadata )
93
- end
94
-
95
-
96
- ### Extract image data from ID3 information, supports both APIC (2.3) and the older style
97
- ### PIC (2.2). Return value is a hash with IO keys and mimetype values.
98
- ### {
99
- ### io => { format => 'image/jpeg' }
100
- ### io2 => { format => 'image/jpeg' }
101
- ### }
102
- def extract_images( mp3info )
103
- self.log.debug "Extracting embedded images"
104
- raise LocalJumpError, "no block given" unless block_given?
105
-
106
- unless mp3info.hastag2?
107
- self.log.debug "...no id3v2 tag, so no embedded images possible."
108
- return
109
- end
110
-
111
- self.log.debug "...id3v2 tag present..."
112
-
113
- if mp3info.tag2.APIC
114
- self.log.debug "...extracting APIC (id3v2.3+) image data."
115
-
116
- images = [ mp3info.tag2.APIC ].flatten
117
- images.each do |img|
118
- blob, mime = img.unpack( APIC_FORMAT ).values_at( 4, 1 )
119
- yield( StringIO.new(blob),
120
- :format => mime,
121
- :extent => blob.length,
122
- :relationship => 'album-art' )
123
- end
124
-
125
- elsif mp3info.tag2.PIC
126
- self.log.debug "...extracting PIC (id3v2.2) image data."
127
-
128
- images = [ mp3info.tag2.PIC ].flatten
129
- images.each do |img|
130
- blob, type = img.unpack( PIC_FORMAT ).values_at( 4, 1 )
131
- mime = Mongrel2::Config.mimetypes[ ".#{type.downcase}" ] or next
132
- yield( StringIO.new(blob),
133
- :format => mime,
134
- :extent => blob.length,
135
- :relationship => 'album-art' )
136
- end
137
-
138
- else
139
- self.log.debug "...no known image tag types in tags: %p" % [ mp3info.tag2.keys.sort ]
140
- end
141
- end
142
-
143
-
144
-
145
- #######
146
- private
147
- #######
148
-
149
- ### Strip NULLs from the values of the given +metadata_hash+ and return it.
150
- def sanitize_values( metadata_hash )
151
- metadata_hash.each do |k,v|
152
- case v
153
- when String
154
- metadata_hash[k] = v.chomp(NULL).strip
155
- when Array
156
- metadata_hash[k] = v.collect {|vv| vv.chomp(NULL).strip }
157
- when Numeric, TrueClass, FalseClass
158
- # No-op
159
- end
160
- end
161
-
162
- return metadata_hash.delete_if {|_,v| v.nil? }
163
- end
164
-
165
-
166
- end # class Thingfish::Processor::MP3
167
-
@@ -1,16 +0,0 @@
1
- # -*- ruby -*-
2
- #encoding: utf-8
3
-
4
- require 'zmq'
5
- require 'configurability'
6
- require 'loggability'
7
-
8
- require 'thingfish' unless defined?( Thingfish )
9
-
10
-
11
- # Currently just a placeholder for what will eventually be the runner for
12
- # async processors.
13
- class Thingfish::ProcessorDaemon
14
- end # class Thingfish::ProcessorDaemon
15
-
16
-