m-chrzan.xyz
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Chrzanowski <m@m-chrzan.xyz>2021-09-12 14:17:19 +0200
committerMarcin Chrzanowski <m@m-chrzan.xyz>2021-09-12 14:17:19 +0200
commitf3039744d72454e7e3b8cb1032266bcc172ce488 (patch)
tree5a92a698056e2cbec6f0b121a9ce31596e4a4581
Initial commit
-rw-r--r--lib/html.rb13
-rw-r--r--lib/latex.rb17
-rw-r--r--lib/ly.rb14
-rw-r--r--lib/pather.rb39
-rw-r--r--lib/recording.rb36
-rw-r--r--lib/song.rb47
-rw-r--r--lib/songs.rb19
-rw-r--r--lib/statics.rb10
-rw-r--r--lib/templated.rb20
-rw-r--r--lib/util.rb85
-rw-r--r--ly/preamble.ly12
-rw-r--r--scripts/build.rb31
-rw-r--r--src/index.html.erb9
-rw-r--r--src/style.css31
14 files changed, 383 insertions, 0 deletions
diff --git a/lib/html.rb b/lib/html.rb
new file mode 100644
index 0000000..61e25a3
--- /dev/null
+++ b/lib/html.rb
@@ -0,0 +1,13 @@
+require './lib/templated'
+
+def render_html song
+ template = html_template 'song'
+ template.result binding
+end
+
+def make_htmls songs
+ songs.each do |song_id, song|
+ content = render_html song
+ write_templated content, song_html(song_id), song.title
+ end
+end
diff --git a/lib/latex.rb b/lib/latex.rb
new file mode 100644
index 0000000..e17a6ef
--- /dev/null
+++ b/lib/latex.rb
@@ -0,0 +1,17 @@
+def render_latex song
+ template = tex_template 'song'
+ templated = template.result binding
+ File.write(tmp(song_tex song.id), templated)
+end
+
+def render_pdf song
+ render_latex song
+ system "lualatex --shell-escape -output-directory=#{TmpDir}/#{SongsDir} #{tmp (song_tex song.id)}"
+ system "mv #{tmp (song_pdf song.id)} #{build (song_pdf song.id)}"
+end
+
+def make_pdfs songs
+ songs.each_value do |song|
+ render_pdf song
+ end
+end
diff --git a/lib/ly.rb b/lib/ly.rb
new file mode 100644
index 0000000..fc85204
--- /dev/null
+++ b/lib/ly.rb
@@ -0,0 +1,14 @@
+def compile_ly ly_filename
+ system "lilypond --svg --output=#{tmp SongsDir} #{ly_filename}"
+ system "lilypond --output=#{tmp SongsDir} #{ly_filename}"
+end
+
+def make_sheets songs
+ songs.keys.each do |song_id|
+ ly_filename = src(song_ly song_id)
+ if File.file? ly_filename
+ compile_ly ly_filename
+ system "mv #{tmp (song_tmp_svg song_id)} #{build(song_svg song_id)}"
+ end
+ end
+end
diff --git a/lib/pather.rb b/lib/pather.rb
new file mode 100644
index 0000000..1f59df0
--- /dev/null
+++ b/lib/pather.rb
@@ -0,0 +1,39 @@
+class Pather
+ attr_accessor :current_path
+ def initialize
+ @assets = {}
+ @current_path = []
+ end
+
+ def add asset_id, path
+ @assets[asset_id] = @current_path + path.split('/')
+ end
+
+ def path_to asset_id
+ other_path = @assets[asset_id]
+ find_path_between @current_path, other_path
+ end
+
+ def find_path_between from, to
+ from, to = drop_common_prefix from, to
+ path = ('../' * from.length) + to.join('/')
+ end
+
+ def drop_common_prefix path1, path2
+ common_prefix_length = path1.zip(path2).take_while do |(segment1, segment2)|
+ segment1 == segment2
+ end.length
+
+ return path1[common_prefix_length..], path2[common_prefix_length..]
+ end
+
+ def cd path
+ path.split('/').each do |segment|
+ if segment == '..'
+ @current_path.pop
+ else
+ @current_path.push segment
+ end
+ end
+ end
+end
diff --git a/lib/recording.rb b/lib/recording.rb
new file mode 100644
index 0000000..d1d7683
--- /dev/null
+++ b/lib/recording.rb
@@ -0,0 +1,36 @@
+class NotImplemented < Exception
+end
+
+class Recording
+ def render
+ raise NotImplemented
+ end
+end
+
+class YouTubeRecording
+ attr_accessor :vid
+ def initialize link
+ @vid = parse_vid link
+ end
+
+ def parse_vid link
+ /\?v=(.{11})/.match(link)[1]
+ end
+
+ def render
+ template = ERB.new(File.read('templates/youtube.html.erb'), trim_mode: '-')
+ template.result binding
+ end
+end
+
+class BandcampRecording
+ attr_accessor :link
+ def initialize link
+ @link = link
+ end
+
+ def render
+ template = ERB.new(File.read('templates/bandcamp.html.erb'), trim_mode: '-')
+ template.result binding
+ end
+end
diff --git a/lib/song.rb b/lib/song.rb
new file mode 100644
index 0000000..4076956
--- /dev/null
+++ b/lib/song.rb
@@ -0,0 +1,47 @@
+require 'yaml'
+
+require './lib/recording'
+
+class Song
+ attr_accessor :title, :id, :lyrics, :recordings
+ def initialize title, id
+ @title = title
+ @id = id
+ @recordings = []
+ end
+
+ def self.from_yaml song_id
+ metadata = YAML.load(File.read(src(song_meta song_id)))
+ song = Song.new metadata['title'], song_id
+
+ song.lyrics = nil
+ lyrics_file = src (song_lyrics song_id)
+ if File.file? lyrics_file
+ song.lyrics = File.read lyrics_file
+ end
+
+ if metadata['recordings']
+ metadata['recordings'].each do |recording|
+ if recording['type'] == 'youtube'
+ song.recordings.push YouTubeRecording.new(recording['link'])
+ elsif recording['type'] == 'bandcamp'
+ song.recordings.push BandcampRecording.new(recording['link'])
+ end
+ end
+ end
+ song
+ end
+
+ def split_lyrics
+ @lyrics.split("\n\n").map { |paragraph| paragraph.split "\n" }
+ end
+
+ def render_sheet_music
+ if File.file? (src (song_ly id))
+ template = ERB.new(File.read('templates/sheet_music.html.erb'), trim_mode: '-')
+ template.result binding
+ else
+ ""
+ end
+ end
+end
diff --git a/lib/songs.rb b/lib/songs.rb
new file mode 100644
index 0000000..aa519e1
--- /dev/null
+++ b/lib/songs.rb
@@ -0,0 +1,19 @@
+require 'set'
+
+require './lib/util'
+
+@songs = nil
+
+def get_song_ids dir
+ ids = Set.new
+ Dir.new(src SongsDir).children.each do |filename|
+ ids.add(File.basename filename, '.*')
+ end
+ ids
+end
+
+def songs
+ @songs ||= get_song_ids(SongsDir).map do |song_id|
+ [song_id, Song.from_yaml(song_id)]
+ end.to_h
+end
diff --git a/lib/statics.rb b/lib/statics.rb
new file mode 100644
index 0000000..24ca9d6
--- /dev/null
+++ b/lib/statics.rb
@@ -0,0 +1,10 @@
+require 'fileutils'
+
+def write_statics statics
+ statics = statics.each do |filename|
+ source = src filename
+ target = build filename
+ FileUtils.mkdir_p(File.dirname target)
+ FileUtils.cp_r source, target
+ end
+end
diff --git a/lib/templated.rb b/lib/templated.rb
new file mode 100644
index 0000000..548352c
--- /dev/null
+++ b/lib/templated.rb
@@ -0,0 +1,20 @@
+def write_templated_file content_filename, title
+ content = File.read(src content_filename)
+ write_templated content, content_filename, title
+end
+
+def write_erb erb_filename
+ content = ERB.new(File.read(src erb_filename)).result
+ cut_filename = erb_filename.sub /\.erb$/, ''
+ File.write build(cut_filename), content
+end
+
+def write_templated_erb erb_filename, title = nil
+ content = ERB.new(File.read(src erb_filename), trim_mode: '-').result
+ cut_filename = erb_filename.sub /\.erb$/, ''
+ write_templated content, cut_filename, title
+end
+
+def write_templated content, filename, title = nil
+ File.write build(filename), page_template.result(binding)
+end
diff --git a/lib/util.rb b/lib/util.rb
new file mode 100644
index 0000000..48698ff
--- /dev/null
+++ b/lib/util.rb
@@ -0,0 +1,85 @@
+SongsDir = 'songs'
+SrcDir = 'src'
+BuildDir = 'public'
+TmpDir = 'tmp'
+TemplatesDir = 'templates'
+
+def song filename
+ File.join SongsDir, filename
+end
+
+def build filename
+ File.join BuildDir, filename
+end
+
+def tmp filename
+ File.join TmpDir, filename
+end
+
+def src filename
+ File.join SrcDir, filename
+end
+
+def song_lyrics song_id
+ song "#{song_id}.txt"
+end
+
+def song_ly song_id
+ song "#{song_id}.ly"
+end
+
+def song_meta song_id
+ song "#{song_id}.yaml"
+end
+
+def song_tex song_id
+ song "#{song_id}.tex"
+end
+
+def song_sheet_pdf song_id
+ song "#{song_id}.cropped.pdf"
+end
+
+def song_tmp_svg song_id
+ song "#{song_id}.cropped.svg"
+end
+
+def song_pdf song_id
+ song "#{song_id}.pdf"
+end
+
+def song_sheet_svg song_id
+ song "#{song_id}.svg"
+end
+
+def song_svg song_id
+ song "#{song_id}.svg"
+end
+
+def song_html song_id
+ song "#{song_id}.html"
+end
+
+def template filename
+ ERB.new(File.read(filename), trim_mode: '-')
+end
+
+def template_file filename
+ File.join TemplatesDir, filename
+end
+
+def tex_template name
+ template(template_file "#{name}.tex.erb")
+end
+
+def html_template name
+ template(template_file "#{name}.html.erb")
+end
+
+def page_template
+ html_template 'template'
+end
+
+def path_to asset_id
+ P.path_to asset_id
+end
diff --git a/ly/preamble.ly b/ly/preamble.ly
new file mode 100644
index 0000000..437ee5e
--- /dev/null
+++ b/ly/preamble.ly
@@ -0,0 +1,12 @@
+\version "2.22.1"
+
+#(ly:set-option 'print-pages #f)
+#(ly:set-option 'crop #t)
+
+\header {
+ tagline = ##f
+}
+
+\paper {
+ indent = 0
+}
diff --git a/scripts/build.rb b/scripts/build.rb
new file mode 100644
index 0000000..1ad5472
--- /dev/null
+++ b/scripts/build.rb
@@ -0,0 +1,31 @@
+require 'erb'
+
+require './lib/song'
+require './lib/songs'
+require './lib/tags'
+require './lib/latex'
+require './lib/pather'
+require './lib/ly'
+require './lib/html'
+require './lib/statics'
+
+statics = [ 'style.css' ]
+
+P = Pather.new
+
+P.add 'index', 'index.html'
+P.add 'style', 'style.css'
+
+songs.each_key do |song_id|
+ P.add(song_html(song_id), song_html(song_id))
+ P.add(song_svg(song_id), song_svg(song_id))
+ P.add(song_pdf(song_id), song_pdf(song_id))
+end
+
+write_templated_erb 'index.html.erb'
+write_statics statics
+
+P.cd SongsDir
+make_sheets songs
+make_pdfs songs
+make_htmls songs
diff --git a/src/index.html.erb b/src/index.html.erb
new file mode 100644
index 0000000..2008d11
--- /dev/null
+++ b/src/index.html.erb
@@ -0,0 +1,9 @@
+Ĺšpiewnik polskiej muzyki tradycyjnej.
+
+<ul>
+<%- songs.each_value do |song| -%>
+ <li>
+ <a href='<%= path_to (song_html song.id) %>'><%= song.title %></a>
+ </li>
+<%- end -%>
+</ul>
diff --git a/src/style.css b/src/style.css
new file mode 100644
index 0000000..f6ec3cc
--- /dev/null
+++ b/src/style.css
@@ -0,0 +1,31 @@
+body {
+ margin: 40px auto;
+ max-width: 800px;
+ line-height: 1.6;
+ font-size: 18px;
+ padding: 0 10px;
+}
+
+a {
+ color: darkblue;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #55f;
+}
+
+ul {
+ list-style-type: '';
+ column-count: 3;
+}
+
+li {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding-left: 0.7em;
+}
+
+h1, h2, h3 {
+ line-height: 1.2
+}