3 # Web Chord v1.1 - A CGI script to convert a ChordPro file to HTML
4 # Copyright 1998-2003 Martin Vilcans (martin@mamaviol.org)
7 # chopro - This parameter can be submitted by a form as a text field or file
11 # 1998-07-20 Version 1.0
12 # 2003-08-03 Version 1.1 Uses stylesheets
13 # 2014-02-05 Added things particular to my implementation of Songbook at
14 # http://defaria.com/songbook
18 use CGI qw(:standard);
19 use CGI::Carp qw (fatalsToBrowser);
22 my ($chopro, $output, $i);
24 my $documentRoot = "/web";
25 my $debug = param ('debug');
26 my $infile = param ('chordpro');
29 $infile = '/opt/songbook/Andrew/' . $infile;
32 $infile = '/web/xmas/' . param ('chordpro');
35 print "Unable to open $infile";
46 print "<font color=red><b>Debug:</b></font> $msg<br>";
56 print "<font color=orange><b>Warning</b></font> $msg<br>";
64 print "<html><head><title>Web Chord: Error</title></head>" .
65 "<body><h1>Error</h1><p>\n$msg\n</p>" .
71 sub musicFileExists ($) {
74 debug "ENTER musicFileExists ($song)";
76 my $title = fileparse ($song, qr/\.pro/);
77 my $musicfile = "/opt/media/$title.mp3";
84 debug "Could not find $musicfile";
90 sub updateMusicpath ($$) {
91 my ($chopro, $song) = @_;
93 my $title = musicFileExists $song;
95 # If there's no corresponding music file then do nothing
98 # If the .pro file already has musicpath then do nothing
99 if ($chopro =~ /\{musicpath:.*\}/) {
100 debug "$song already has musicpath";
103 return if $chopro =~ /\{musicpath:.*\}/;
105 # Otherwise append the musicpath
108 open $songfile, '>>', $song
111 unless (defined $songfile) {
112 my $msg = "Unable to open $song for append - $!<br>";
113 $msg .= "<br>Please notify <a href=\"mailto:adefaria\@gmail.com?subject=Please chmod 666 $song\">Andrew DeFaria</a> so this can be corrected.<br>";
114 $msg .= "<br>Thanks";
120 my $songbase = '/sdcard';
122 print $songfile "{musicpath:$songbase/SongBook/Media/$title.mp3}\n";
129 # Outputs the HTML code of the chordpro file in the first parameter
130 sub chopro2html ($$) {
131 my ($chopro, $song) = @_;
133 $chopro =~ s/\</\</g; # replace < with <
134 $chopro =~ s/\>/\>/g; # replace > with >
135 $chopro =~ s/\&/\&/g; # replace & with &
137 my $title = "ChordPro Song";
138 my $artist = "Unknown";
140 if (($chopro =~ /^{title:(.*)}/mi) || ($chopro =~ /^{t:(.*)}/mi)) {
144 if (($chopro =~ /^{subtitle:(.*)}/mi) || ($chopro =~ /^{st:(.*)}/mi)) {
151 <title>$title</title>
152 <link rel="stylesheet" type="text/css" href="songbook.css">
153 <link rel="stylesheet" type="text/css" href="question.mark.css">
154 <script src="songbook.js"></script>
155 <script src="question.mark.js"></script>
161 $title = musicFileExists $song;
164 updateMusicpath $chopro, $song;
171 <td align="left"><a href="/songbook"><img src="/Icons/Home.png" alt="Home"></a></td>
172 <td><div id="title">$title</div>
173 <div id="artist"><a href="/songbook/displayartist.php?artist=$artist">$artist</a></div></td>
174 <td align="right" width="300px">
175 <audio id="song" controls autoplay style="padding:0; margin:0">
176 <source src="https://defaria.com/Media/$title.mp3" style="padding:0; margin:0" type='audio/mp3'>
177 Your user agent does not support the HTML5 Audio element.
179 <p align="center" <font size=-1><b>Mark A:</b></font>
180 <font size=-1 color=#666><span id="a"><i>not set</i></span></font>
181 <font size=-1><b>Mark B:</b></font>
182 <font size=-1 color=#666><span id="b">not set</span></font></p>
189 my $mode = 0; # mode defines which class to use
192 # normal chorus normal+tab chorus+tab
193 my @lClasses = ('lyrics', 'lyrics_chorus', 'lyrics_tab', 'lyrics_chorus_tab' );
194 my @cClasses = ('chords', 'chords_chorus', 'chords_tab', 'chords_chorus_tab' );
196 while($chopro ne '') {
197 $chopro =~ s/(.*)\n?//; # extract and remove first line
201 if (/^#(.*)/) { # a line starting with # is a comment
202 print "<!--$1-->\n"; # insert as HTML comment
203 } elsif (/{(.*)}/) { # this is a command
205 if (/^start_of_chorus/i || /^soc/i) { # start_of_chorus
207 } elsif (/^end_of_chorus/i || /^eoc/i) { # end_of_chorus
209 } elsif (/^comment:/i || /^c:/i) { # comment
210 print "<span class=\"comment\">($')</span>\n";
211 } elsif (/^comment_italic:/i || /^ci:/i) { # comment_italic
212 print "<span class=\"comment_italic\">($')</span>\n";
213 } elsif (/^comment_box:/i || /^cb:/i) { # comment_box
214 print "<P class=\"comment_box\">$'</P>\n";
215 } elsif (/^start_of_tab/i || /^sot/i) { # start_of_tab
217 } elsif (/^end_of_tab/i || /^eot/i) { # end_of_tab
220 print "<!--Unsupported command: $_-->\n";
222 } else { # this is a line with chords and lyrics
226 s/\s/\ /g; # replace spaces with hard spaces
227 while(s/(.*?)\[(.*?)\]//) {
229 push(@chords,$2 eq '\'|' ? '|' : $2);
231 push(@lyrics,$_); # rest of line (after last chord) into @lyrics
233 if ($lyrics[0] eq "") { # line began with a chord
234 shift(@chords); # remove first item
235 shift(@lyrics); # (they are both empty)
238 if (@lyrics==0) { # empty line?
240 } elsif (@lyrics==1 && $chords[0] eq "") { # line without chords
241 print "<div class=\"$lClasses[$mode]\">$lyrics[0]</div>\n";
243 print "<table cellpadding=0 cellspacing=0>";
246 for($i = 0; $i < @chords; $i++) {
247 print "<td class=\"$cClasses[$mode]\">$chords[$i]</td>";
249 print "</tr>\n<tr>\n";
250 for($i = 0; $i < @lyrics; $i++) {
251 print "<td class=\"$lClasses[$mode]\">$lyrics[$i]</td>";
253 print "</tr></table>\n";
265 error "No chordpro parameter";
268 open my $file, '<', $infile
269 or error "Unable to open file $infile - $!";
276 chopro2html ($chopro, $infile);