|
require 'nokogiri' |
|
|
|
file = ARGV[0] |
|
|
|
xml = Nokogiri::XML(File.read(file)) |
|
|
|
title = xml.css('title').text |
|
content = xml.css('lyrics').text |
|
|
|
def to_lines(content) |
|
file_lines = content.split("\n") |
|
lines = [] |
|
|
|
pair = [] |
|
|
|
file_lines.each do |line| |
|
if pair.any? |
|
pair << line[1..-1] |
|
pair[1] ||= "" |
|
lines << pair |
|
pair = [] |
|
elsif line[0] == '.' && pair.empty? |
|
pair = [line[1..-1]] |
|
elsif line[0] == ' ' && pair.empty? |
|
pair = [] |
|
lines << ["", line] |
|
elsif line =~ /\[V(\d*)\]/ |
|
pair = [] |
|
lines << ["", "Verse #{$1}:"] |
|
elsif line =~ /\[C(\d*)\]/ |
|
pair = [] |
|
number = $1.length != 0 ? " #{$1}" : "" |
|
lines << ["", "Chorus#{number}:"] |
|
elsif line =~ /\[PC(\d*)\]/ |
|
pair = [] |
|
number = $1.length != 0 ? " #{$1}" : "" |
|
lines << ["", "Prechorus#{number}:"] |
|
elsif line =~ /\[B(\d*)\]/ |
|
pair = [] |
|
number = $1.length != 0 ? " #{$1}" : "" |
|
lines << ["", "Bridge#{number}:"] |
|
elsif line.strip == "" |
|
pair = [] |
|
lines << ["", ""] |
|
else |
|
pair = [] |
|
end |
|
end |
|
|
|
lines |
|
end |
|
|
|
def get_chord_positions(chord_line) |
|
positions = [] |
|
|
|
chord = "" |
|
start_pos = 0 |
|
|
|
(0..chord_line.length - 1).each do |i| |
|
if chord_line[i] == ' ' && chord != "" |
|
positions << [chord, start_pos] |
|
chord = "" |
|
start_pos = 0 |
|
end |
|
|
|
if chord_line[i] != ' ' |
|
start_pos = i if chord == "" |
|
chord << chord_line[i] |
|
end |
|
end |
|
|
|
if chord != "" |
|
positions << [chord, start_pos] |
|
end |
|
|
|
positions |
|
end |
|
|
|
def interpolate_line(chord_positions, lyrics) |
|
output = lyrics.dup |
|
|
|
offset = 0 |
|
|
|
chord_positions.each do |chord, position| |
|
insert_string = "[#{chord}]" |
|
if output.length < (position + offset) |
|
output << (" " * (position + offset - output.length)) |
|
end |
|
output.insert(position + offset, insert_string) |
|
offset += insert_string.length |
|
end |
|
|
|
output.strip |
|
end |
|
|
|
lines = to_lines(content) |
|
onsong = lines.map { |chords, lyrics| [get_chord_positions(chords), lyrics] }.map{ |chord_positions, lyrics| interpolate_line(chord_positions, lyrics) } |
|
|
|
key = get_chord_positions(lines.find { |chords, lyrics| chords.length != 0 }[0])[0][0] rescue nil |
|
|
|
puts title |
|
puts "Key: [#{key}]" if key |
|
onsong.each do |line| |
|
puts line |
|
end |