From: Andrew DeFaria Date: Mon, 13 Nov 2017 02:29:47 +0000 (-0800) Subject: Major fixes for Song page X-Git-Url: https://defaria.com/gitweb/?a=commitdiff_plain;h=4b532d27ad4ad7d71bb190f7974b3129ee114b22;p=songbook.git Major fixes for Song page . Changed history link to point to github. . On the song page, the heading is now fixed to the top part of the page. Included in the heading is the home button, the title of the song and artist (not linked to show all of the artist's songs) and the HTML5 Audio player. . The bottom part contains the song itself as before. I may add an auto scroll option later. It'd be really cool if I could tag the various lines and chorus such that the playback syncs with the words but I'm not sure I can do that. . I've added JavaScript to allow the space bar to play/pause playback. . Added additional keyboard shortcuts for: . r - return to start (initially start is 0 but can be set by the "a" command) . b - rewind back 10 seconds. I choose 10 because that seemed to be a good amount to rew/ff. Hit b or f multiple times to go forward or backward by 10 secs increments. . f - Fast forward 10 seconds. . a - Mark start. Say you are listening and playing/singing along with a song and you want to practice that part just before the second chorus. Well mark that spot with the "a" key. Then play/sing along. Didn't get it right? Hit either "r" or the space bar to start at the marked position again. . c - Clear start. If you don't want that start position anymore clear it with "c". Then "r" or space bar will start from 0. . ? - Hit "?" to see the keyboard short cuts. --- diff --git a/web/index.php b/web/index.php index 43742c7..bd5ede6 100644 --- a/web/index.php +++ b/web/index.php @@ -21,7 +21,7 @@ include_once "songbook.php"; - + diff --git a/web/question.mark.css b/web/question.mark.css new file mode 100644 index 0000000..37b5663 --- /dev/null +++ b/web/question.mark.css @@ -0,0 +1,155 @@ +.help-underlay * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.help-underlay { + position: absolute; + background: #555; + background: rgba(0,0,0,0.5); + visibility: hidden; + opacity: 0; + -webkit-transition: opacity .2s linear; + -moz-transition: opacity .2s linear; + -o-transition: opacity .2s linear; + transition: opacity .2s linear; + left: 0; right: 0; top: 0; bottom: 0; +} + +.ie8 .help-underlay { + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(opacity=95)"; /* for IE8 in IE7 mode */ + filter: alpha(opacity=95); /* for IE8 */ + visibility: hidden; +} + +.help-modal { + position: fixed; + z-index: 99999; + left: 0; right: 0; top: 0; bottom: 0; + width: 80%; + margin: auto; + background: #fff; + color: #676767; + max-height: 80%; + overflow: auto; + font-family: Arial, sans-serif; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 4px 12px rgba(0,0,0,.4), inset 0 1px 0 rgba(255,255,255,.5); + box-shadow: 0 4px 12px rgba(0,0,0,.4), inset 0 1px 0 rgba(255,255,255,.5); + -webkit-transition: width .2s linear; + -moz-transition: width .2s linear; + -o-transition: width .2s linear; + transition: width .2s linear; +} + + .help-modal-content { + padding: 0 20px; + } + + .help-close { + position: absolute; + top: .4em; + right: .5em; + font-size: 1.8em; + cursor: pointer; + -webkit-transition: color .2s linear; + -moz-transition: color .2s linear; + -o-transition: color .2s linear; + transition: color .2s linear; + } + + .help-close:hover { + color: #000; + } + +.help-modal h1 { + text-align: center; + margin: .5em; + font-size: 1.5em; + padding-bottom: .4em; + border-bottom: solid 2px #ccc; + font-weight: normal; +} + + .help-modal h1 .help-key { + float: none; + line-height: 1.5; + position: relative; + bottom: 4px; + } + +.help-isVisible { + opacity: 1; + visibility: visible; + height: auto; + z-index: 8888; +} + +.ie8 .help-underlay.help-isVisible { + visibility: visible; +} + +.help-list-wrap { + overflow: hidden; + margin: 0 auto; + -webkit-transition: width .2s linear; + -moz-transition: width .2s linear; + -o-transition: width .2s linear; + transition: width .2s linear; +} + +.help-list { + list-style: none; + margin: 0; + padding: 0 0 10px 0; + overflow: hidden; + float: left; + width: 280px; +} + + .help-list li { + margin-right: 40px; + } + +.help-key-unit { + line-height: 1.8; + margin-right: 2em; + padding: 5px 0; +} + +.help-key { + min-width: 60px; + float: left; + clear: left; + position: relative; + bottom: 2px; +} + +.help-key span { + font-size: 15px; + color: #555; + display: inline-block; + padding: 0 8px; + text-align: center; + background-color: #eee; + background-repeat: repeat-x; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#eee)); + background-image: -webkit-linear-gradient(#f5f5f5 0%, #eee 100%); + background-image: -moz-linear-gradient(#f5f5f5 0%, #eee 100%); + background-image: -o-linear-gradient(#f5f5f5 0%, #eee 100%); + background-image: linear-gradient(#f5f5f5 0%, #eee 100%); + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 0 #ccc; + box-shadow: inset 0 1px 0 #fff, 0 1px 0 #ccc; +} + +.help-key-def { + display: inline-block; + margin-left: 1em; +} \ No newline at end of file diff --git a/web/question.mark.html b/web/question.mark.html new file mode 100644 index 0000000..3e2b4aa --- /dev/null +++ b/web/question.mark.html @@ -0,0 +1,51 @@ +
+
+

Keyboard Shortcuts ?

+
×
+ +
+ +
+ + + +
    + +
  • + space + Pause/Play +
  • +
  • + r + Return to start +
  • +
  • + b + Rewind 10 secs +
  • +
  • + f + Fast forward 10 secs +
  • +
  • + a + Mark start +
  • +
  • + c + Clear start +
  • + +
+ +
+ +
+
+
\ No newline at end of file diff --git a/web/question.mark.js b/web/question.mark.js new file mode 100644 index 0000000..0c9dcd1 --- /dev/null +++ b/web/question.mark.js @@ -0,0 +1 @@ +(function(){"use strict";function e(e){e.className=e.className.replace(/help-isVisible*/g,"");e.className=e.className.trim()}function t(){var e=window,t=document,n=t.documentElement,r=t.getElementsByTagName("body")[0],i=e.innerWidth||n.clientWidth||r.clientWidth;return i}function n(){var e=document;return Math.max(e.body.scrollHeight,e.documentElement.scrollHeight,e.body.offsetHeight,e.documentElement.offsetHeight,e.body.clientHeight,e.documentElement.clientHeight)}function r(e){e.helpColsTotal=0;for(e.i=0;e.i630&&e.helpColsTotal>2){e.helpColsTotal=2;e.maxHeight=e.maxHeight*e.helpColsTotal}if(t()<=630){e.maxHeight=e.maxHeight*e.helpColsTotal;e.helpColsTotal=1}e.helpListWrap.style.offsetWidth=e.helpList.offsetWidth*e.helpColsTotal+"px";e.helpListWrap.style.height=e.maxHeight+"px";e.helpModal.style.width=e.helpList.offsetWidth*e.helpColsTotal+60+"px";e.helpModal.style.height=e.maxHeight+100+"px"}function i(e){e=e||window.event;var t=e.keyCode||e.which;return t}function s(){var t=document.getElementById("helpUnderlay"),s=document.getElementById("helpModal"),o=document.getElementById("helpClose"),u=null,a={i:null,maxHeight:null,helpListWrap:document.getElementById("helpListWrap"),helpList:document.querySelector(".help-list"),helpLists:document.querySelectorAll(".help-list"),helpModal:s,helpColsTotal:null,helpListsHeights:[]},f;r(a);document.addEventListener("keypress",function(e){if(i(e)===63){f=document.getElementById("helpUnderlay").className;if(f.indexOf("help-isVisible")===-1){document.getElementById("helpUnderlay").className+=" help-isVisible"}}t.style.height=n()+"px"},false);document.addEventListener("keyup",function(n){if(i(n)===27){e(t)}},false);t.addEventListener("click",function(){e(t)},false);s.addEventListener("click",function(e){e.stopPropagation()},false);o.addEventListener("click",function(){e(t)},false);window.onresize=function(){if(u!==null){clearTimeout(u)}u=setTimeout(function(){r(a)},100)}}function o(){var e=false;if(window.XMLHttpRequest){e=new XMLHttpRequest}return e}function u(e,t){if(!document.getElementById("helpUnderlay")){document.getElementsByTagName("body")[0].innerHTML+=e;t()}}function a(e){if(e.readyState===4){if(e.status===200||e.status===304){var t=e.responseText;u(t,function(){s()})}}}function f(){var e=o();if(e){e.onreadystatechange=function(){a(e)};e.open("POST","question.mark.html",true);e.setRequestHeader("Content-Type","application/x-www-form-urlencoded");e.send(null)}else{document.getElementsByTagName("body")[0].innerHTML+="Error: Your browser does not support Ajax"}}f()})() \ No newline at end of file diff --git a/web/songbook.css b/web/songbook.css new file mode 100644 index 0000000..5335352 --- /dev/null +++ b/web/songbook.css @@ -0,0 +1,58 @@ +body { + background-image: url('/songbook/background.jpg'); + padding: 0px; + border: 0px; + margin: 0px; +} +#title { + text-align: center; + font-family: Arial, Helvetica; + font-size: 28pt; +} +#artist { + text-align: center; + font-family: Arial, Helvetica; + font-size: 22pt; +} +#song { + padding-top: 100px; + padding-left: 20px; +} +#heading { + border: 0; + border-bottom: 1px solid black; + position: fixed; + margin: 0; + padding: 0; + background-color: #ddd; + width: 100%; +} +.lyrics, .lyrics_chorus { + font-size: 22pt; +} +.lyrics_tab, .lyrics_chorus_tab { + font-family: "Courier New", Courier; + font-size: 18pt; +} +.lyrics_chorus, .lyrics_chorus_tab, .chords_chorus, .chords_chorus_tab { + font-weight: bold; +} +.chords, .chords_chorus, .chords_tab, .chords_chorus_tab { + font-size: 18pt; + color: blue; + padding-right: 4pt; +} +.comment, .comment_italic { + color: #999; + font-size: 18pt; +} +.comment_box { + background-color: #ffbbaa; + text-align: center; +} +.comment_italic { + font-style: italic; +} +.comment_box { + border: solid; +} diff --git a/web/songbook.js b/web/songbook.js new file mode 100644 index 0000000..85a4b18 --- /dev/null +++ b/web/songbook.js @@ -0,0 +1,72 @@ +// Javascript functions for controling audio +starttime = null; +endtime = null; + +spacebar = 32; +return2start = 82; +backfewsecs = 66; +forwardfewsecs = 70; +seta = 65; +cleara = 67; +howmanysecs = 10; + +window.onload = function() { + song = document.getElementById('song'); + + starttime = song.currentTime; + endtime = song.duration; + body = document.getElementsByTagName('body')[0] + + body.onkeydown = + function(e) { + var ev = e || event; + if (ev.keyCode == spacebar) { + if (song.paused) { + playing = false; + } else { + playing = true; + } // if + + if (playing) { + song.pause(); + playing = false; + } else { + if (starttime != 0) { + song.currentTime = starttime + } // if + + song.play(); + playing = true; + } // if + + e.preventDefault(); + return; + } else if (ev.keyCode == return2start) { + if (starttime != null) { + song.currentTime = starttime; + } else { + song.currentTime = 0; + } // if + + return; + } else if (ev.keyCode == backfewsecs) { + song.currentTime -= howmanysecs; + song.play() + + return; + } else if (ev.keyCode == forwardfewsecs) { + song.currentTime += howmanysecs; + song.play(); + + return; + } else if (ev.keyCode == seta) { + starttime = song.currentTime; + + return; + } else if (ev.keyCode == cleara) { + starttime = 0; + + return; + } // if + } // function + } // getElementByTagName \ No newline at end of file diff --git a/web/webchord.cgi b/web/webchord.cgi index 15a3186..a64b4c1 100755 --- a/web/webchord.cgi +++ b/web/webchord.cgi @@ -12,7 +12,6 @@ # 2003-08-03 Version 1.1 Uses stylesheets # 2014-02-05 Added things particular to my implementation of Songbook at # http://defaria.com/songbook - use strict; use warnings; @@ -41,31 +40,31 @@ unless (-f $infile) { sub debug ($) { my ($msg) = @_; - + return unless $debug; - + print "Debug: $msg
"; - + return; } # debug -sub warning ($) { +sub warning ($) { my ($msg) = @_; debug "warning"; print "Warning $msg
"; - return; + return; } # warning sub error { my ($msg) = @_; - + print "Web Chord: Error" . "

Error

\n$msg\n

" . ""; - + exit; } # error @@ -73,17 +72,17 @@ sub musicFileExists ($) { my ($song) = @_; debug "ENTER musicFileExists ($song)"; - + my $title = fileparse ($song, qr/\.pro/); my $musicfile = "/opt/media/$title.mp3"; if (-r $musicfile) { debug "Exists!"; - + return $title; } else { debug "Could not find $musicfile"; - + return undef; } # if } # musicFileExists @@ -92,10 +91,10 @@ sub updateMusicpath ($$) { my ($chopro, $song) = @_; my $title = musicFileExists $song; - + # If there's no corresponding music file then do nothing return unless $title; - + # If the .pro file already has musicpath then do nothing if ($chopro =~ /\{musicpath:.*\}/) { debug "$song already has musicpath"; @@ -105,26 +104,26 @@ sub updateMusicpath ($$) { # Otherwise append the musicpath my $songfile; - + open $songfile, '>>', $song or undef $songfile; - + unless (defined $songfile) { my $msg = "Unable to open $song for append - $!
"; $msg .= "
Please notify Andrew DeFaria so this can be corrected.
"; $msg .= "
Thanks"; warning $msg; - + return; } # unless my $songbase = '/sdcard'; - + print $songfile "{musicpath:$songbase/SongBook/Media/$title.mp3}\n"; - + close $songfile; - return; + return; } # updateMusicPath # Outputs the HTML code of the chordpro file in the first parameter @@ -135,95 +134,53 @@ sub chopro2html ($$) { $chopro =~ s/\>/\>/g; # replace > with > $chopro =~ s/\&/\&/g; # replace & with & - my $title; - - if(($chopro =~ /^{title:(.*)}/mi) || ($chopro =~ /^{t:(.*)}/mi)) { + my $title = "ChordPro Song"; + my $artist = "Unknown"; + + if (($chopro =~ /^{title:(.*)}/mi) || ($chopro =~ /^{t:(.*)}/mi)) { $title = $1; - } else { - $title = "ChordPro song"; - } + } # if + + if (($chopro =~ /^{subtitle:(.*)}/mi) || ($chopro =~ /^{st:(.*)}/mi)) { + $artist = $1; + } # if + print < $title - + + + + + END $title = musicFileExists $song; - + if ($title) { updateMusicpath $chopro, $song; } # if - + print << "END"; - +
-END - - if ($title) { - print <<"END"; - -END - } # if -print <<"END"; + +
Home - -
$title
+
+ +
+
END my $mode = 0; # mode defines which class to use @@ -237,27 +194,23 @@ END $_ = $1; chomp; - if(/^#(.*)/) { # a line starting with # is a comment - print "\n"; # insert as HTML comment - } elsif(/{(.*)}/) { # this is a command + if (/^#(.*)/) { # a line starting with # is a comment + print "\n"; # insert as HTML comment + } elsif (/{(.*)}/) { # this is a command $_ = $1; - if(/^title:/i || /^t:/i) { # title - print "

$'

\n"; - } elsif(/^subtitle:/i || /^st:/i) { # subtitle - print "

$'

\n"; - } elsif(/^start_of_chorus/i || /^soc/i) { # start_of_chorus + if (/^start_of_chorus/i || /^soc/i) { # start_of_chorus $mode |= 1; - } elsif(/^end_of_chorus/i || /^eoc/i) { # end_of_chorus + } elsif (/^end_of_chorus/i || /^eoc/i) { # end_of_chorus $mode &= ~1; - } elsif(/^comment:/i || /^c:/i) { # comment + } elsif (/^comment:/i || /^c:/i) { # comment print "($')\n"; - } elsif(/^comment_italic:/i || /^ci:/i) { # comment_italic + } elsif (/^comment_italic:/i || /^ci:/i) { # comment_italic print "($')\n"; - } elsif(/^comment_box:/i || /^cb:/i) { # comment_box + } elsif (/^comment_box:/i || /^cb:/i) { # comment_box print "

$'

\n"; - } elsif(/^start_of_tab/i || /^sot/i) { # start_of_tab + } elsif (/^start_of_tab/i || /^sot/i) { # start_of_tab $mode |= 2; - } elsif(/^end_of_tab/i || /^eot/i) { # end_of_tab + } elsif (/^end_of_tab/i || /^eot/i) { # end_of_tab $mode &= ~2; } else { print "\n"; @@ -273,37 +226,39 @@ END } push(@lyrics,$_); # rest of line (after last chord) into @lyrics - if($lyrics[0] eq "") { # line began with a chord + if ($lyrics[0] eq "") { # line began with a chord shift(@chords); # remove first item shift(@lyrics); # (they are both empty) } - if(@lyrics==0) { # empty line? + if (@lyrics==0) { # empty line? print "
\n"; - } elsif(@lyrics==1 && $chords[0] eq "") { # line without chords - print "
$lyrics[0]
\n"; + } elsif (@lyrics==1 && $chords[0] eq "") { # line without chords + print "
$lyrics[0]
\n"; } else { - print ""; - print "\n"; + print "
"; + print "\n"; my($i); for($i = 0; $i < @chords; $i++) { - print ""; + print ""; } - print "\n\n"; + print "\n\n"; for($i = 0; $i < @lyrics; $i++) { - print ""; + print ""; } - print "
$chords[$i]$chords[$i]
$lyrics[$i]$lyrics[$i]
\n"; + print "\n"; } # if } # if } # while + + print "
"; } # chordpro2html ## Main print header; unless ($infile) { - error "No chordpro parameter"; + error "No chordpro parameter"; } # unless open my $file, '<', $infile @@ -318,6 +273,4 @@ chopro2html ($chopro, $infile); print end_html(); -exit; - - +exit; \ No newline at end of file