Class: PhishDotNetClient::Setlist
- Inherits:
-
Object
- Object
- PhishDotNetClient::Setlist
- Defined in:
- lib/phish_dot_net_client/setlist.rb
Overview
This class represents the parsed data from the ‘setlistdata’ field.
Instance Attribute Summary collapse
-
#footnotes ⇒ Object
readonly
Returns the value of attribute footnotes.
-
#sets ⇒ Object
readonly
Returns the value of attribute sets.
Class Method Summary collapse
-
.augment_songs(tokens, songs, footnotes) ⇒ void
private
Adds footnotes to their associated songs and adds transition information between songs.
-
.parse_setlistdata(setlistdata) ⇒ Array<(Array<Set>, Hash)>
private
Does the work of parsing the setlistdata.
-
.tokenize_transitions_text(transitions_text, existing_tokens = []) ⇒ Array<Hash<Symbol, Object>>
private
Tokenizes the html-stripped setlistdata text.
Instance Method Summary collapse
-
#initialize(setlistdata) ⇒ Setlist
constructor
private
A new instance of Setlist.
-
#songs ⇒ Array<Song>
All songs in the setlist.
Constructor Details
#initialize(setlistdata) ⇒ Setlist
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of Setlist.
19 20 21 |
# File 'lib/phish_dot_net_client/setlist.rb', line 19 def initialize(setlistdata) @sets, @footnotes = self.class.parse_setlistdata(setlistdata) end |
Instance Attribute Details
#footnotes ⇒ Object (readonly)
Returns the value of attribute footnotes.
14 15 16 |
# File 'lib/phish_dot_net_client/setlist.rb', line 14 def footnotes @footnotes end |
#sets ⇒ Object (readonly)
Returns the value of attribute sets.
10 11 12 |
# File 'lib/phish_dot_net_client/setlist.rb', line 10 def sets @sets end |
Class Method Details
.augment_songs(tokens, songs, footnotes) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Adds footnotes to their associated songs and adds transition information between songs.
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 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/phish_dot_net_client/setlist.rb', line 103 def self.augment_songs(tokens, songs, footnotes) songs = Array.new(songs) # make a copy get_song_by_title = lambda do |title,instance| songs.each do |song| if song.title == title && song.instance == instance return song end end raise "no song with that title ('#{title}')" end tokens.each_index do |i| prev_i = i >= 1 ? i - 1 : nil next_i = i < tokens.size - 1 ? i + 1 : nil token = tokens[i] case token[:type] when :note_ref prev_token = tokens[prev_i] song = get_song_by_title.call(prev_token[:title], prev_token[:instance]) num = token[:number] footnotes[num][:song] = song song.footnotes << num when :transition prev_token = tokens[prev_i] if prev_token[:type] == :note_ref prev_token = tokens[prev_i-1] end next_token = tokens[next_i] from_song = get_song_by_title.call(prev_token[:title], prev_token[:instance]) to_song = get_song_by_title.call(next_token[:title], next_token[:instance]) PhishDotNetClient::SongTransition.new(token[:transition_type], from_song, to_song) end end end |
.parse_setlistdata(setlistdata) ⇒ Array<(Array<Set>, Hash)>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Does the work of parsing the setlistdata.
35 36 37 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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/phish_dot_net_client/setlist.rb', line 35 def self.parse_setlistdata(setlistdata) doc = Nokogiri::HTML(setlistdata) footnotes = {} footnotes_text = doc.css('.pnetfootnotes').first if footnotes_text footnotes_text = footnotes_text.content.split(/(?=\[\d+\])/) footnotes_text.each do |note| note.sub!(/\[(?<num>\d+)\]/, '').strip! num = $~[:num] footnotes[num.to_i] = { text: note } end end sets = [] all_songs = [] transitions_tokens = [] slug_instances = {} setnodes = doc.css(".pnetset") position_in_show = 0 setnodes.each_with_index do |n,set_index| setname = n.css(".pnetsetlabel").first.content set = Set.new(:name => setname.sub!(/:\z/, ''), :position => set_index) songs_doc = n.css("a") songs_doc.each_with_index do |song,song_index| position_in_set = song_index title = song.content url = song.attr('href') slug = URI.parse(url).path slug.sub!(/\A\/song\//, '') slug_instances[slug] ||= 0 slug_instances[slug] += 1 song = Song.new(:title => title, :url => url, :slug => slug, :instance => slug_instances[slug], :position_in_set => position_in_set, :position_in_show => position_in_show) set.songs << song all_songs << song position_in_show += 1 end transitions_text = n.content # strips html tags transitions_tokens += tokenize_transitions_text(transitions_text, transitions_tokens) sets << set end augment_songs(transitions_tokens, all_songs, footnotes) return sets, footnotes end |
.tokenize_transitions_text(transitions_text, existing_tokens = []) ⇒ Array<Hash<Symbol, Object>>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Tokenizes the html-stripped setlistdata text.
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 208 209 210 211 212 213 214 215 216 |
# File 'lib/phish_dot_net_client/setlist.rb', line 151 def self.tokenize_transitions_text(transitions_text, existing_tokens=[]) rules = [] # Account for multiple songs with the same title in a song list song_title_counts = {} existing_tokens.each do |token| if token[:type] == :song title = token[:title] song_title_counts[title] ||= 0 song_title_counts[title] += 1 end end rules.push(/\A[a-z0-9\s]+:/i => lambda do |match| return { type: :set_name, name: match.to_s.strip.sub(':', '') } end) rules.push(/\A[äa-z0-9\-?\.!:\/'\s\(\)]+[a-z0-9\)?!']/i => lambda do |match| title = match.to_s.strip song_title_counts[title] ||= 0 song_title_counts[title] += 1 return { type: :song, title: title, instance: song_title_counts[title] } end) rules.push(/\A\[(?<num>\d+)\]/ => lambda do |match| return { type: :note_ref, number: match[:num].to_i } end) rules.push(/\A,/ => lambda do |match| return { type: :transition, transition_type: :no_segue } end) rules.push(/\A>/ => lambda do |match| return { type: :transition, transition_type: :segue } end) rules.push(/\A->/ => lambda do |match| return { type: :transition, transition_type: :deep_segue } end) rules.push(/\A\s+/ => lambda do |match| return nil end) parsed_set = [] until transitions_text.empty? matched = false # keeps track of whether the transitions_text matched # any rule. raise error if there no match. rules.each do |rule| rule_regex, processor = rule.keys.first, rule.values.first if transitions_text.slice!(rule_regex) matched = true token = processor.call($~) parsed_set.push(token) if token break end end raise "could not parse: '#{transitions_text}'" unless matched end return parsed_set end |
Instance Method Details
#songs ⇒ Array<Song>
Returns all songs in the setlist.
24 25 26 |
# File 'lib/phish_dot_net_client/setlist.rb', line 24 def songs return @sets.map(&:songs).reduce([]){|memo,songs| memo += songs } end |