Class: MusicTrack

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
LastfmRequest
Defined in:
app/models/music_track.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from LastfmRequest

included, #lastfm_request

Instance Attribute Details

#artist_mbidObject

Returns the value of attribute artist_mbid.



58
59
60
# File 'app/models/music_track.rb', line 58

def artist_mbid
  @artist_mbid
end

#do_not_syncObject

Returns the value of attribute do_not_sync.



58
59
60
# File 'app/models/music_track.rb', line 58

def do_not_sync
  @do_not_sync
end

#release_is_lpObject

Returns the value of attribute release_is_lp.



58
59
60
# File 'app/models/music_track.rb', line 58

def release_is_lp
  @release_is_lp
end

Class Method Details

.by_artist_and_name(tracks) ⇒ Object



35
36
37
38
39
40
41
42
43
44
# File 'app/models/music_track.rb', line 35

def self.by_artist_and_name(tracks)
  criteria, values = [], []
  
  tracks.each do |track|
    criteria << '(LOWER(artist_name) = ? AND LOWER(name) = ?)'
    values += [track.first.downcase.strip, track.last.downcase.strip]
  end
  
  without_slaves.where(criteria.join(' OR '), *values)
end

.enrich_metadata(tracks_input) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'app/models/music_track.rb', line 127

def self.(tracks_input)
  primitive_tracks = []
  
  tracks_input = if tracks_input.is_a? Hash
    list = []
    tracks_input.each {|index, track| list << track }
    list
  else
    tracks_input
  end
  
  tracks_input.each do |track|
    primitive_tracks << [track['artist_name'].downcase.strip, track['name'].downcase.strip]
  end
  
  primitive_tracks.uniq!
  tracks = MusicTrack.by_artist_and_name(primitive_tracks).limit(500).offset(0)
  primitive_voluntary_tracks = tracks.map{|t| [t.artist_name.downcase.strip, t.name.downcase.strip]}
  
  unique_primitive_voluntary_tracks = primitive_voluntary_tracks.select{|t1| primitive_voluntary_tracks.select{|t2| t2 == t1 }.length == 1 }
  ambiguous_primitive_voluntary_tracks = primitive_voluntary_tracks.select{|t1| primitive_voluntary_tracks.select{|t2| t2 == t1 }.length > 1 }
  
  new_tracks, already_existing_tracks = [], []
  
  # make tracks uniq this way because tracks.uniq removes not persisted tracks
  tracks.each do |track|
    primitive_track = [track.artist_name.downcase, track.name.downcase]
    
    next if already_existing_tracks.include?(primitive_track)
    
    already_existing_tracks << primitive_track
  end
  
  primitive_tracks.select{|t| !unique_primitive_voluntary_tracks.include?(t) }.each do |track|
    track_input = tracks_input.select{|t| t['artist_name'].downcase.strip == track.first && t['name'].downcase.strip == track.last}.first
    track = MusicTrack.new(artist_name: track_input['artist_name'], name: track_input['name'])
    track.set_spotify_track_id
    sleep 1
    tracks << track
  end
  
  tracks.map do |track| 
    hash = { 
      artist_name: track.artist_name, name: track.name
    } 
    
    if track.persisted?
      hash[:ambiguous] = ambiguous_primitive_voluntary_tracks.include?([track.artist_name.strip.downcase, track.name.strip.downcase])
    
      if track.release_name == '[Bonus Tracks]'
        hash[:bonus_track] = true
      else
        hash[:bonus_track] = false
      end
    else
      hash[:ambiguous] = nil
      hash[:bonus_track] = nil
    end
    
    if track.mbid.blank? && track.persisted?
      hash[:draft] = true
    elsif track.mbid.present?
      hash[:draft] = false
    else
      hash[:draft] = nil
    end
    
    if hash[:ambiguous]
      hash.merge({
        id: nil, artist_id: nil, mbid: nil, spotify_id: nil, release_id: nil, release_name: nil, listeners: nil, 
        plays: nil, duration: nil, released_at: nil
      })
    else
      hash.merge({
        id: track.id, artist_id: track.artist_id, mbid: track.mbid, spotify_id: track.spotify_track_id, 
        release_id: track.release_id, release_name: track.release_name, listeners: track.listeners, 
        plays: track.plays, duration: track.duration, released_at: track.released_at
      })
    end
  end
end

.format_name(value) ⇒ Object



97
98
99
100
101
# File 'app/models/music_track.rb', line 97

def self.format_name(value)
  return value if value.nil?
  
  value.gsub(/’|´/, "'").gsub(/\(Album version\)|\(Single version\)|\(Remastered\)|\(clean\)/i, '').strip
end

.name_included_in_blacklist?(name) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
106
107
108
109
# File 'app/models/music_track.rb', line 103

def self.name_included_in_blacklist?(name)
  if name =~ /\[credits|data track|encore break|untitled|photo gallery|interview\]/i
    true
  else
    false
  end
end

.name_included_in_bonustrack_blacklist?(name) ⇒ Boolean

Returns:

  • (Boolean)


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'app/models/music_track.rb', line 111

def self.name_included_in_bonustrack_blacklist?(name)
  if name_included_in_blacklist?(name)
    true
  elsif name =~ /^intro|introduction|outro|credits|interview$/i
    true
  elsif name =~ /\[intro|outro|introduction\]/i 
    true
  elsif name =~ /medley|megamix|mega mix|mastermix|master mix|acoustic/i
    true
  elsif name =~ /\(/
    true
  else
    false
  end
end

.search_on_musicbrainz(artist_mbid, name) ⇒ Object



86
87
88
89
90
91
92
93
94
95
# File 'app/models/music_track.rb', line 86

def self.search_on_musicbrainz(artist_mbid, name)
  results = []
  tracks = MusicBrainz::Recording.search(artist_mbid, name)

  tracks.each do |track|
    results << track if results.select{|t| t[:title].downcase == name.downcase.strip }.none?
  end
  
  results
end

Instance Method Details

#create_bonus_track(working_mbid) ⇒ Object



279
280
281
282
283
284
285
# File 'app/models/music_track.rb', line 279

def create_bonus_track(working_mbid)
  self.name = MusicTrack.format_name(name)
  self.mbid = working_mbid
  self.release_id = artist.bonus_tracks_release.id
  self.save
  self.import_metadata!
end

#create_draft_track(name) ⇒ Object



287
288
289
290
291
# File 'app/models/music_track.rb', line 287

def create_draft_track(name)
  self.release_id = artist.bonus_tracks_release.id
  self.name = MusicTrack.format_name(name)
  self.save
end

#formatted_durationObject



293
294
295
# File 'app/models/music_track.rb', line 293

def formatted_duration
  Time.at(duration / 1000).strftime('%M:%S') if duration.present?
end

#is_bonus_track?Boolean

Returns:

  • (Boolean)


246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'app/models/music_track.rb', line 246

def is_bonus_track?
  return false if ::MusicTrack.name_included_in_bonustrack_blacklist?(name)
  
  tracks = MusicBrainz::Recording.search(artist_mbid ? artist_mbid : artist.mbid, name, limit: 100).select{|t| MusicTrack.format_name(t[:title]).downcase == name.downcase.strip }
  
  tracks.map do |t| 
    (t[:releases] || []).select do |r| 
      r[:status] == 'Official' && !(r[:artists] || []).map{|a| a[:name]}.include?('Various Artists') &&
      (r[:release_group][:secondary_types] || []).select{|st| MusicRelease::SECONDARY_TYPES_BLACKLIST.include?(st)}.none?
    end.map{|r| (r[:release_group] || {})[:id] }
  end.flatten.uniq.each do |release_group_mbid|
    next if release_group_mbid.nil?
    
    release_group = MusicBrainz::ReleaseGroup.find(release_group_mbid)
    
    next if release_group.releases.select{|r| r.status == 'Official' && (r.media.map(&:format).none? || r.media.map(&:format).select{|f| ['DVD-Video', 'DVD'].include?(f) }.none?) }.none?
    next unless ['Album', 'EP'].include?(release_group.primary_type)
  
    self.release_name = release_group.title
    self.release_is_lp = release_group.type == 'Album'
    
    break
  end

  if self.release_name.blank?
    self.released_at = tracks.map{|t| (t[:releases] || []).select{|r| !r[:date].nil?}.map{|r| r[:date]}}.flatten.uniq.sort.first
    
    true
  else
    false
  end
end

#set_spotify_track_idObject



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'app/models/music_track.rb', line 209

def set_spotify_track_id
  return if spotify_track_id.present?

  response = nil
  
  begin
    response = JSON.parse(
      HTTParty.get("https://api.spotify.com/v1/search?q=track%3A%22#{URI.encode(name, /\W/)}%22+artist%3A%22#{URI.encode(artist_name, /\W/)}%22&type=track").body
    )
  rescue JSON::ParserError
  end
  
  return if response.nil?
  
  response['tracks']['items'].each do |item|
    next unless item['name'].downcase == name.downcase
    
    artist_found = false
    
    item['artists'].each do |working_artist|
      if working_artist['name'].downcase == artist_name.downcase
        artist_found = true
        
        break
      end
    end
    
    next unless artist_found
    
    self.spotify_track_id = item['id']

    break if item['artists'].length == 1
  end
  
  save if persisted? && spotify_track_id.present?
end