Class: MrEko::Song
- Includes:
- Core
- Defined in:
- lib/mr_eko/song.rb
Overview
TODO: Refactor this so everything’s not in class methods
Constant Summary collapse
- REQUIRED_ID3_TAGS =
[:artist, :title]
Class Method Summary collapse
-
.catalog_via_enmfp(filename, opts = {}) ⇒ MrEko::Song, NilClass
Run local analysis (ENMFP) on the passed file, send that identifier code to EN and store the returned details in our DB.
-
.catalog_via_tags(filename, opts = {}) ⇒ MrEko::Song
Uses ID3 tags to query Echonest and then store the resultant data.
-
.create_from_file!(filename, opts = {}) ⇒ MrEko::Song
A wrapper which gets called by the bin file.
-
.enmfp_data(filename, md5) ⇒ Hash
Using the Echonest Musical Fingerprint lib in the hopes of sidestepping the mp3 upload process.
-
.get_datapoints_by_upload(filename) ⇒ Array
Returns the analysis and profile data from Echonest for the given track.
-
.parse_id3_tags(filename) ⇒ MrEko::TagParser::Result
Parses the file’s ID3 tags.
Instance Method Summary collapse
Methods included from Core
#before_create, #before_update, included
Class Method Details
.catalog_via_enmfp(filename, opts = {}) ⇒ MrEko::Song, NilClass
Run local analysis (ENMFP) on the passed file, send that identifier code to EN and store the returned details in our DB. If the local analysis fails, upload the MP3 to EN for server-side analysis.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/mr_eko/song.rb', line 38 def self.catalog_via_enmfp(filename, opts={}) md5 = opts[:md5] || MrEko.md5(filename) existing = where(:md5 => md5).first return existing unless existing.nil? return if file_too_big? filename log "Identifying with ENMFP code #{filename}" begin fingerprint_json = enmfp_data(filename, md5) profile = identify_from_enmfp_data(fingerprint_json) rescue MrEko::EnmfpError => e log %Q{Issues using ENMFP data "(#{e})" #{e.backtrace.join("\n")}} analysis, profile = get_datapoints_by_upload(filename) end create do |song| song.filename = File.(filename) song.md5 = md5 song.code = fingerprint_json ? fingerprint_json.code : nil song.tempo = profile.audio_summary.tempo song.duration = profile.audio_summary.duration song.key = profile.audio_summary[:key] song.mode = profile.audio_summary.mode song.loudness = profile.audio_summary.loudness song.time_signature = profile.audio_summary.time_signature song.echonest_id = profile.id song.bitrate = fingerprint_json ? fingerprint_json..bitrate : nil song.title = profile.title song.artist = profile.artist || profile.artist_name song.album = fingerprint_json ? fingerprint_json..release : profile.release song.danceability = profile.audio_summary.danceability song.energy = profile.audio_summary.energy end end |
.catalog_via_tags(filename, opts = {}) ⇒ MrEko::Song
Uses ID3 tags to query Echonest and then store the resultant data.
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/mr_eko/song.rb', line 90 def self.(filename, opts={}) = (filename) return unless .reject{ |k, v| v.blank? }.size >= REQUIRED_ID3_TAGS.size md5 = opts[:md5] || MrEko.md5(filename) begin analysis = MrEko.nest.song.search(:artist => .artist, :title => .title, :bucket => 'audio_summary', :limit => 1).songs.first rescue => e log "BAD TAGS? #{.inspect} #{filename}" log e. log e.backtrace.join("\n") return end create do |song| song.filename = File.(filename) song.md5 = md5 song.tempo = analysis.audio_summary.tempo song.duration = analysis.audio_summary.duration song.key = analysis.audio_summary['key'] song.mode = analysis.audio_summary.mode song.loudness = analysis.audio_summary.loudness song.time_signature = analysis.audio_summary.time_signature song.echonest_id = analysis.id song.title = .title song.artist = .artist song.album = .album song.danceability = analysis.audio_summary.danceability song.energy = analysis.audio_summary.energy # XXX: Won't have these from tags - worth getting from EN? # song.code = fingerprint_json.code # XXX: ID3Lib doesn't return these - worth parsing? # song.bitrate = profile.bitrate end if analysis end |
.create_from_file!(filename, opts = {}) ⇒ MrEko::Song
A wrapper which gets called by the bin file. By default will try to extract the needed song info from the ID3 tags and if fails, will analyze via ENMFP/upload.
17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/mr_eko/song.rb', line 17 def self.create_from_file!(filename, opts={}) md5 = MrEko.md5(filename) existing = where(:md5 => md5).first return existing unless existing.nil? if song = (filename, :md5 => md5) song elsif !opts[:tags_only] catalog_via_enmfp(filename, :md5 => md5) end end |
.enmfp_data(filename, md5) ⇒ Hash
Using the Echonest Musical Fingerprint lib in the hopes of sidestepping the mp3 upload process.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/mr_eko/song.rb', line 137 def self.enmfp_data(filename, md5) unless File.exists?(fp_location(md5)) log 'Waiting for ENMFP binary...' `#{MrEko.enmfp_binary} "#{File.(filename)}" > #{fp_location(md5)}` end begin raw_json = File.read fp_location(md5) hash = Hashie::Mash.new(JSON.parse(raw_json).first) hash.raw_data = raw_json if hash.keys.include?('error') raise MrEko::EnmfpError, "Errors returned in the ENMFP fingerprint data: #{hash.error.inspect}" end rescue JSON::ParserError => e raise MrEko::EnmfpError, e. end hash end |
.get_datapoints_by_upload(filename) ⇒ Array
Returns the analysis and profile data from Echonest for the given track.
163 164 165 166 167 168 169 |
# File 'lib/mr_eko/song.rb', line 163 def self.get_datapoints_by_upload(filename) log "Uploading data to EN for analysis" analysis = MrEko.nest.track.analysis(filename) profile = MrEko.nest.track.profile(:md5 => MrEko.md5(filename), :bucket => 'audio_summary').body.track return [analysis, profile] end |
.parse_id3_tags(filename) ⇒ MrEko::TagParser::Result
Parses the file’s ID3 tags
79 80 81 82 83 |
# File 'lib/mr_eko/song.rb', line 79 def self.(filename) log "Parsing ID3 tags" MrEko::TagParser.parse(filename) end |
Instance Method Details
#validate ⇒ Object
171 172 173 174 175 |
# File 'lib/mr_eko/song.rb', line 171 def validate super set_md5 # no Sequel callback for this? validates_unique :md5 end |