jekyll-lilypond 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +99 -0
- data/LICENSE +21 -0
- data/README.md +98 -0
- data/files/rite.png +0 -0
- data/jekyll-lilypond.gemspec +23 -0
- data/lib/jekyll-lilypond/file_processor.rb +67 -0
- data/lib/jekyll-lilypond/lilypond_tag.rb +34 -0
- data/lib/jekyll-lilypond/tag.rb +17 -0
- data/lib/jekyll-lilypond/tag_processor.rb +56 -0
- data/lib/jekyll-lilypond/templates/basic.ly +45 -0
- data/lib/jekyll-lilypond/templates/empty.ly +1 -0
- data/lib/jekyll-lilypond/templates/figure.html +25 -0
- data/lib/jekyll-lilypond/templates/img.html +4 -0
- data/lib/jekyll-lilypond/templates/raw.html +1 -0
- data/lib/jekyll-lilypond/templates/raw.ly +1 -0
- data/lib/jekyll-lilypond/templates/showsource.html +36 -0
- data/lib/jekyll-lilypond/templates.rb +60 -0
- data/lib/jekyll-lilypond/version.rb +5 -0
- data/lib/jekyll-lilypond.rb +11 -0
- data/spec/file_processor_spec.rb +167 -0
- data/spec/fixtures/.gitignore +5 -0
- data/spec/fixtures/404.html +25 -0
- data/spec/fixtures/Gemfile +31 -0
- data/spec/fixtures/_config.yml +56 -0
- data/spec/fixtures/_layouts/basic_html.html +1 -0
- data/spec/fixtures/_layouts/vacuous_html.html +1 -0
- data/spec/fixtures/_layouts/vacuous_ly.ly +1 -0
- data/spec/fixtures/_layouts/variables_html.html +1 -0
- data/spec/fixtures/_layouts/variables_ly.ly +1 -0
- data/spec/fixtures/_posts/2021-01-16-welcome-to-jekyll.markdown +29 -0
- data/spec/fixtures/about.markdown +18 -0
- data/spec/fixtures/index.markdown +6 -0
- data/spec/fixtures/page.md +8 -0
- data/spec/integration_spec.rb +115 -0
- data/spec/spec_helper.rb +88 -0
- data/spec/tag_processor_spec.rb +135 -0
- data/spec/tag_spec.rb +51 -0
- data/spec/templates_spec.rb +175 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 03f518ed64fd17a4aa282f1e11c82f1ea127de1231919ad2f22f419f3a95d942
|
4
|
+
data.tar.gz: 8225e9fd20e2be85d2be52781a01d65de431313399d7313d754e416f78148c6c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 48f09dbd1c6101a2ff2d13500690f72efee15bfc7b33cc647ecf050de11f082de1bc195a16fa56d52958b7605c362cf7a21258498f0cce8c51015436261056c5
|
7
|
+
data.tar.gz: 0b51587b3ff6e62de63486833c9269bd961d025d047770431adcb8b7fb0c98207eb6798efee19ee6e175e7a705d4811216395004290f7fe223755552dac9788c
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.7.0)
|
5
|
+
public_suffix (>= 2.0.2, < 5.0)
|
6
|
+
colorator (1.1.0)
|
7
|
+
concurrent-ruby (1.1.7)
|
8
|
+
diff-lcs (1.4.4)
|
9
|
+
docile (1.3.5)
|
10
|
+
em-websocket (0.5.2)
|
11
|
+
eventmachine (>= 0.12.9)
|
12
|
+
http_parser.rb (~> 0.6.0)
|
13
|
+
eventmachine (1.2.7)
|
14
|
+
ffi (1.14.2)
|
15
|
+
forwardable-extended (2.6.0)
|
16
|
+
http_parser.rb (0.6.0)
|
17
|
+
i18n (1.8.7)
|
18
|
+
concurrent-ruby (~> 1.0)
|
19
|
+
jekyll (4.2.0)
|
20
|
+
addressable (~> 2.4)
|
21
|
+
colorator (~> 1.0)
|
22
|
+
em-websocket (~> 0.5)
|
23
|
+
i18n (~> 1.0)
|
24
|
+
jekyll-sass-converter (~> 2.0)
|
25
|
+
jekyll-watch (~> 2.0)
|
26
|
+
kramdown (~> 2.3)
|
27
|
+
kramdown-parser-gfm (~> 1.0)
|
28
|
+
liquid (~> 4.0)
|
29
|
+
mercenary (~> 0.4.0)
|
30
|
+
pathutil (~> 0.9)
|
31
|
+
rouge (~> 3.0)
|
32
|
+
safe_yaml (~> 1.0)
|
33
|
+
terminal-table (~> 2.0)
|
34
|
+
jekyll-feed (0.15.1)
|
35
|
+
jekyll (>= 3.7, < 5.0)
|
36
|
+
jekyll-sass-converter (2.1.0)
|
37
|
+
sassc (> 2.0.1, < 3.0)
|
38
|
+
jekyll-seo-tag (2.7.1)
|
39
|
+
jekyll (>= 3.8, < 5.0)
|
40
|
+
jekyll-watch (2.2.1)
|
41
|
+
listen (~> 3.0)
|
42
|
+
kramdown (2.3.0)
|
43
|
+
rexml
|
44
|
+
kramdown-parser-gfm (1.1.0)
|
45
|
+
kramdown (~> 2.0)
|
46
|
+
liquid (4.0.3)
|
47
|
+
listen (3.4.1)
|
48
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
49
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
50
|
+
mercenary (0.4.0)
|
51
|
+
minima (2.5.1)
|
52
|
+
jekyll (>= 3.5, < 5.0)
|
53
|
+
jekyll-feed (~> 0.9)
|
54
|
+
jekyll-seo-tag (~> 2.1)
|
55
|
+
pathutil (0.16.2)
|
56
|
+
forwardable-extended (~> 2.6)
|
57
|
+
public_suffix (4.0.6)
|
58
|
+
rb-fsevent (0.10.4)
|
59
|
+
rb-inotify (0.10.1)
|
60
|
+
ffi (~> 1.0)
|
61
|
+
rexml (3.2.4)
|
62
|
+
rouge (3.26.0)
|
63
|
+
rspec (3.10.0)
|
64
|
+
rspec-core (~> 3.10.0)
|
65
|
+
rspec-expectations (~> 3.10.0)
|
66
|
+
rspec-mocks (~> 3.10.0)
|
67
|
+
rspec-core (3.10.1)
|
68
|
+
rspec-support (~> 3.10.0)
|
69
|
+
rspec-expectations (3.10.1)
|
70
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
71
|
+
rspec-support (~> 3.10.0)
|
72
|
+
rspec-mocks (3.10.1)
|
73
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
74
|
+
rspec-support (~> 3.10.0)
|
75
|
+
rspec-support (3.10.1)
|
76
|
+
safe_yaml (1.0.5)
|
77
|
+
sassc (2.4.0)
|
78
|
+
ffi (~> 1.9)
|
79
|
+
simplecov (0.21.2)
|
80
|
+
docile (~> 1.1)
|
81
|
+
simplecov-html (~> 0.11)
|
82
|
+
simplecov_json_formatter (~> 0.1)
|
83
|
+
simplecov-html (0.12.3)
|
84
|
+
simplecov_json_formatter (0.1.2)
|
85
|
+
terminal-table (2.0.0)
|
86
|
+
unicode-display_width (~> 1.1, >= 1.1.1)
|
87
|
+
unicode-display_width (1.7.0)
|
88
|
+
|
89
|
+
PLATFORMS
|
90
|
+
universal-darwin-19
|
91
|
+
|
92
|
+
DEPENDENCIES
|
93
|
+
jekyll
|
94
|
+
minima
|
95
|
+
rspec
|
96
|
+
simplecov
|
97
|
+
|
98
|
+
BUNDLED WITH
|
99
|
+
2.2.5
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2021 Leah Velleman
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# jekyll-lilypond
|
2
|
+
|
3
|
+
<p align="center">
|
4
|
+
<img src="files/rite.png" width="75%"/>
|
5
|
+
</p>
|
6
|
+
|
7
|
+
Automatically generate sheet music images by adding Lilypond blocks to your markdown files. Customize their
|
8
|
+
appearance using Liquid attributes. The plugin caches the images it generates, making auto-regeneration fast.
|
9
|
+
|
10
|
+
For complete documentation, see [the plugin website](https://www.velleman.org/jekyll-lilypond).
|
11
|
+
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
The plugin requires Lilypond and Inkscape. To use it in a Jekyll site,
|
16
|
+
add
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'jekyll-lilypond'
|
20
|
+
```
|
21
|
+
|
22
|
+
to your Gemfile and
|
23
|
+
|
24
|
+
```yaml
|
25
|
+
plugins:
|
26
|
+
- jekyll-lilypond
|
27
|
+
```
|
28
|
+
|
29
|
+
to your `_config.yml`.
|
30
|
+
|
31
|
+
## Quick start
|
32
|
+
|
33
|
+
Inside the block, write a Lilypond music expression.
|
34
|
+
```
|
35
|
+
{% lilypond alt: "Five notes of the A-minor scale" %}
|
36
|
+
a b c d e
|
37
|
+
{% endlilypond %}
|
38
|
+
```
|
39
|
+
The expression can include multiple staves, expressive marks, time and key signature changes, and any of the other notation Lilypond supports within a music
|
40
|
+
expression. For details, see [this brief summary](https://lilypond.org/doc/v2.20/Documentation/learning/score-is-a-_0028single_0029-compound-musical-expression) in the Lilypond teaching manual or [Wikipedia's list of common music expression details](https://en.wikipedia.org/wiki/Help:Score#Syntax).
|
41
|
+
|
42
|
+
To make customizations that can't be make within a music expression — for instance, to change the width or height of the score or specify a custom font —
|
43
|
+
use attributes on the `{% lilypond %}` tag. For more information on attributes, see [the plugin documentation](http://127.0.0.1:4000/jekyll-lilypond#attributes).
|
44
|
+
|
45
|
+
## Approach
|
46
|
+
|
47
|
+
### Caching
|
48
|
+
|
49
|
+
Lilypond runs more slowly than Jekyll, and regenerating every score would create a noticeable lag. This would be especially painful in auto-regenerate mode,
|
50
|
+
which is normally very responsive. To solve this, I cache images. Each Lilypond source file, and each resulting image, has a filename derived from the MD5 hash
|
51
|
+
of the source code. The plugin only compiles a Lilypond source file when the corresponding image does not yet exist.
|
52
|
+
|
53
|
+
To force the plugin to regenerate all of the score images for a site, which is sometimes useful for debugging, empty the `lilypond_files` directory.
|
54
|
+
|
55
|
+
To keep upload size to a minimum, you can also empty the `lilypond_files` directory and regenerate the site before deploying. This removes "stale" images
|
56
|
+
that are no longer in use.
|
57
|
+
|
58
|
+
### Templates
|
59
|
+
|
60
|
+
The plugin generates two kinds of code: Lilypond source files, which it uses to generate images, and HTML includes, which appear in the finished page
|
61
|
+
and contain the `img` element and surrounding markup.
|
62
|
+
|
63
|
+
To generate both kinds of source code, it uses Liquid templates. Liquid is the native templating language of Jekyll. Just as Jekyll users can write their own
|
64
|
+
templates to create new page layouts, users of this plugin can write their own templates to add simple features and customizations.
|
65
|
+
|
66
|
+
As well as allowing customization, using a template to generate Lilypond source avoids the need to repeat boilerplate. For instance, the default Lilypond
|
67
|
+
template begins like this:
|
68
|
+
```
|
69
|
+
\version "2.20.0"
|
70
|
+
\paper {
|
71
|
+
indent = 0\mm
|
72
|
+
short-indent = 0\mm
|
73
|
+
bottom-margin = 4\mm
|
74
|
+
oddHeaderMarkup = ##f
|
75
|
+
evenHeaderMarkup = ##f
|
76
|
+
oddFooterMarkup = ##f
|
77
|
+
evenFooterMarkup = ##f
|
78
|
+
...
|
79
|
+
}
|
80
|
+
```
|
81
|
+
These settings produce clean output without extraneous marks, headers, footers, or whitespace, but it would be a hassle to retype them in every Lilypond block.
|
82
|
+
Later parts of the template include correct code for setting the page width, font, and so on, which saves the user from needing to remember the somewhat
|
83
|
+
arbitrary syntax for doing those things.
|
84
|
+
|
85
|
+
### Future plans
|
86
|
+
|
87
|
+
The next thing on my agenda is to generate assets other than images. For instance, Lilypond can generate MIDI files and software synthesizers can generate
|
88
|
+
mp3 audio from MIDI. It would be nice to support those — and, beyond that, to support other workflows that users might think of. (Maybe someone will want to
|
89
|
+
generate video? Or do musical analysis on MIDI files?)
|
90
|
+
|
91
|
+
The most flexible way to do all this would be to let users specify workflow steps in a sitewide Rakefile, alongside whatever other deployment and
|
92
|
+
asset-processing tasks they may have specified there. Templates could then specify what sorts of generated files they require, and the plugin could call on
|
93
|
+
Rake to generate those that don't exist.
|
94
|
+
|
95
|
+
## Testing
|
96
|
+
|
97
|
+
`bundle exec rspec` runs tests. A minimal sample Jekyll site for tests to call on is in `spec/fixtures`,
|
98
|
+
with the interesting details being the sample templates in `spec/fixtures/layouts`.
|
data/files/rite.png
ADDED
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
require "jekyll-lilypond/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.version = "0.1.1"
|
8
|
+
spec.authors = "Leah Velleman"
|
9
|
+
spec.name = "jekyll-lilypond"
|
10
|
+
spec.summary = "Lilypond music snippets in Jekyll"
|
11
|
+
spec.homepage = "https://www.velleman.org/jekyll-lilypond.html"
|
12
|
+
spec.license = "MIT"
|
13
|
+
spec.files = `git ls-files -z`.split("\x0")
|
14
|
+
spec.metadata = {
|
15
|
+
"documentation_uri" => "https://www.velleman.org/jekyll-lilypond.html",
|
16
|
+
"source_code_uri" => "https://github.com/leahvelleman/jekyll-lilypond"
|
17
|
+
}
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
spec.add_dependency "jekyll", ">= 3.0", "< 5.0"
|
20
|
+
spec.add_development_dependency "rspec", "~> 3.5"
|
21
|
+
end
|
22
|
+
|
23
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "digest"
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Lilypond
|
5
|
+
class FileProcessor
|
6
|
+
def initialize(working_dir, hash, source)
|
7
|
+
@hash = hash
|
8
|
+
@source = source
|
9
|
+
@working_dir = working_dir
|
10
|
+
end
|
11
|
+
|
12
|
+
def filepath
|
13
|
+
"#{@working_dir}/#{@hash}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def write
|
17
|
+
unless File.directory?(@working_dir)
|
18
|
+
FileUtils.mkdir_p(@working_dir)
|
19
|
+
end
|
20
|
+
unless File.exist?("#{filepath}.ly")
|
21
|
+
File.open("#{filepath}.ly", "w") do |f|
|
22
|
+
f.write(@source)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def compile
|
28
|
+
unless File.exist?("#{filepath}.svg")
|
29
|
+
puts "Jekyll-lilypond: making #{@hash}.svg"
|
30
|
+
Kernel.system("lilypond", "-lERROR",
|
31
|
+
"-dbackend=svg",
|
32
|
+
"--output=#{filepath}",
|
33
|
+
"#{filepath}.ly")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def trim_svg
|
38
|
+
unless File.exist?("#{filepath}-trimmed.svg")
|
39
|
+
if File.exist?("#{filepath}.svg")
|
40
|
+
puts "Jekyll-lilypond: making #{@hash}-trimmed.svg"
|
41
|
+
Kernel.system("inkscape",
|
42
|
+
"#{filepath}.svg",
|
43
|
+
"--export-area-drawing",
|
44
|
+
"--export-type=svg",
|
45
|
+
"--export-filename=#{filepath}-trimmed.svg")
|
46
|
+
else
|
47
|
+
raise RuntimeError.new(
|
48
|
+
"Cannot trim SVG: expected SVG file #{filepath}.svg does not exist")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def make_mp3
|
54
|
+
unless File.exist?("#{filepath}.mp3")
|
55
|
+
if File.exist?("#{filepath}.midi")
|
56
|
+
puts "Jekyll-lilypond: making #{@hash}.mp3"
|
57
|
+
Kernel.system("timidity #{filepath}.midi -Ow -o - | ffmpeg -i - -acodec libmp3lame -ab 64k #{filepath}.mp3", [:out, :err] => "/dev/null")
|
58
|
+
else
|
59
|
+
raise RuntimeError.new(
|
60
|
+
"Cannot generate mp3: expected MIDI file #{filepath}.midi does not exist.")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module Lilypond
|
3
|
+
class LilypondTag < Liquid::Block
|
4
|
+
def initialize(_, argtext, _)
|
5
|
+
super
|
6
|
+
@attributes = parse_attributes(argtext)
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse_attributes(text)
|
10
|
+
attributes = {}
|
11
|
+
text.scan(Liquid::TagAttributes) do |key, value|
|
12
|
+
value=value.delete_prefix('"').delete_prefix("'")
|
13
|
+
value=value.delete_suffix('"').delete_suffix("'")
|
14
|
+
attributes[key] = value
|
15
|
+
end
|
16
|
+
attributes["attr_text"] = text
|
17
|
+
attributes
|
18
|
+
end
|
19
|
+
|
20
|
+
def render(context)
|
21
|
+
content = super.strip
|
22
|
+
site = context.registers[:site]
|
23
|
+
|
24
|
+
tag = Tag.new(@attributes, content)
|
25
|
+
tp = TagProcessor.new(site, tag)
|
26
|
+
tp.run!
|
27
|
+
tp.include
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Liquid::Template.register_tag("lilypond", Jekyll::Lilypond::LilypondTag)
|
34
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module Lilypond
|
3
|
+
class Tag
|
4
|
+
attr_accessor :attrs, :template_names, :template_code
|
5
|
+
|
6
|
+
def initialize(attrs, content)
|
7
|
+
@attrs = attrs
|
8
|
+
@attrs["content"] = content
|
9
|
+
@template_names = { source: @attrs.delete("source_template"),
|
10
|
+
include: @attrs.delete("include_template") }
|
11
|
+
@template_code = { source: @attrs.delete("source_template_code"),
|
12
|
+
include: @attrs.delete("include_template_code") }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module Lilypond
|
3
|
+
class TagProcessor
|
4
|
+
attr_accessor :site
|
5
|
+
|
6
|
+
def initialize(site, tag)
|
7
|
+
@site = site
|
8
|
+
@tag = tag
|
9
|
+
end
|
10
|
+
|
11
|
+
def source
|
12
|
+
source_template_obj.render(@tag)
|
13
|
+
end
|
14
|
+
|
15
|
+
def source_template_obj
|
16
|
+
Template.new(@site, @tag, :source)
|
17
|
+
end
|
18
|
+
|
19
|
+
def hash
|
20
|
+
Digest::MD5.hexdigest(source)
|
21
|
+
end
|
22
|
+
|
23
|
+
def include
|
24
|
+
@tag.attrs.update("filename" => hash)
|
25
|
+
include_template_obj.render(@tag)
|
26
|
+
end
|
27
|
+
|
28
|
+
def include_template_obj
|
29
|
+
Template.new(@site, @tag, :include)
|
30
|
+
end
|
31
|
+
|
32
|
+
def file_processor
|
33
|
+
FileProcessor.new("#{site.source}/lilypond_files", hash, source)
|
34
|
+
end
|
35
|
+
|
36
|
+
def run!
|
37
|
+
fp = file_processor
|
38
|
+
fp.write
|
39
|
+
fp.compile
|
40
|
+
fp.trim_svg
|
41
|
+
fp.make_mp3 if @tag.attrs["mp3"] == "true"
|
42
|
+
|
43
|
+
@site.static_files << StaticFile.new(site,
|
44
|
+
site.source,
|
45
|
+
"lilypond_files",
|
46
|
+
"#{hash}-trimmed.svg")
|
47
|
+
|
48
|
+
@site.static_files << StaticFile.new(site,
|
49
|
+
site.source,
|
50
|
+
"lilypond_files",
|
51
|
+
"#{hash}.mp3") if @tag.attrs["mp3"] == "true"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
\version "2.20.0"
|
2
|
+
\include "articulate.ly"
|
3
|
+
\paper {
|
4
|
+
indent = 0\mm
|
5
|
+
short-indent = 0\mm
|
6
|
+
{% if width %}
|
7
|
+
paper-width = {{ width }}\in
|
8
|
+
{% if height %}
|
9
|
+
paper-height = {{ height }}\in
|
10
|
+
{% else %}
|
11
|
+
page-breaking = #ly:one-page-breaking
|
12
|
+
{% endif %}
|
13
|
+
{% else %}
|
14
|
+
page-breaking = #ly:one-line-breaking
|
15
|
+
{% endif %}
|
16
|
+
left-margin = 4\mm
|
17
|
+
right-margin = 4\mm
|
18
|
+
top-margin = 4\mm
|
19
|
+
bottom-margin = 4\mm
|
20
|
+
oddHeaderMarkup = ##f
|
21
|
+
evenHeaderMarkup = ##f
|
22
|
+
oddFooterMarkup = ##f
|
23
|
+
evenFooterMarkup = ##f
|
24
|
+
}
|
25
|
+
\score {
|
26
|
+
\unfoldRepeats \articulate
|
27
|
+
<<
|
28
|
+
{{ content }}
|
29
|
+
>>
|
30
|
+
\layout {
|
31
|
+
#(layout-set-staff-size 16)
|
32
|
+
\context {
|
33
|
+
\Lyrics
|
34
|
+
{% if lyricfont %}
|
35
|
+
\override LyricText #'font-name = #"{{ lyricfont }}"
|
36
|
+
{% endif %}
|
37
|
+
{% if lyricsize %}
|
38
|
+
\override LyricText #'font-size = #{{ lyricsize }}
|
39
|
+
{% endif %}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
\midi {
|
43
|
+
\tempo 4 = {{ tempo | default: "120" }}
|
44
|
+
}
|
45
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
{{ content }}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<figure>
|
2
|
+
<img
|
3
|
+
src="lilypond_files/{{ filename }}-trimmed.svg"
|
4
|
+
{%- if style %}
|
5
|
+
style="{{ style }}"
|
6
|
+
{% endif -%}
|
7
|
+
{%- if class %}
|
8
|
+
class="{{ class }}"
|
9
|
+
{% endif -%}
|
10
|
+
{%- if alt %}
|
11
|
+
alt="{{ alt }}"
|
12
|
+
title="{{ alt }}"
|
13
|
+
{% endif -%}
|
14
|
+
/>
|
15
|
+
{%- if mp3 %}
|
16
|
+
<audio controls>
|
17
|
+
<source src="lilypond_files/{{ filename }}.mp3" type="audio/mp3" />
|
18
|
+
Your browser does not support the <code>audio</code> element.
|
19
|
+
</audio>
|
20
|
+
{% endif -%}
|
21
|
+
{%- if caption %}
|
22
|
+
<figcaption>{{ caption }}</figcaption>
|
23
|
+
{% endif -%}
|
24
|
+
</figure>
|
25
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
{{ content }}
|
@@ -0,0 +1 @@
|
|
1
|
+
{{ content }}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<figure
|
2
|
+
{%- if style %}
|
3
|
+
style="{{ style }}"
|
4
|
+
{% endif -%}
|
5
|
+
{%- if class %}
|
6
|
+
class="{{ class }}"
|
7
|
+
{% endif -%}
|
8
|
+
>
|
9
|
+
<img src="lilypond_files/{{ filename }}-trimmed.svg"
|
10
|
+
{%- if alt %}
|
11
|
+
alt="{{ alt }}"
|
12
|
+
title="{{ alt }}"
|
13
|
+
{% endif -%}
|
14
|
+
/>
|
15
|
+
{%- if mp3 %}
|
16
|
+
<audio controls>
|
17
|
+
<source src="lilypond_files/{{ filename }}.mp3" type="audio/mp3" />
|
18
|
+
Your browser does not support the <code>audio</code> element.
|
19
|
+
</audio>
|
20
|
+
{% endif -%}
|
21
|
+
{%- if caption %}
|
22
|
+
<figcaption>{{ caption }}</figcaption>
|
23
|
+
{% endif -%}
|
24
|
+
<details>
|
25
|
+
<summary>Show source</summary>
|
26
|
+
<pre>
|
27
|
+
{%- raw -%}{% {% endraw %}
|
28
|
+
lilypond {{ attr_text -}}
|
29
|
+
{%- raw %}%}{% endraw %}
|
30
|
+
{{ content | escape -}}
|
31
|
+
{%- raw -%}
|
32
|
+
{% endlilypond %}
|
33
|
+
{% endraw %}
|
34
|
+
</pre>
|
35
|
+
</details>
|
36
|
+
</figure>
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module Lilypond
|
3
|
+
class Template
|
4
|
+
def initialize(site, tag, type)
|
5
|
+
@site = site
|
6
|
+
@type = type
|
7
|
+
@tag_template_names = tag.template_names
|
8
|
+
@tag_template_code = tag.template_code
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(tag)
|
12
|
+
Liquid::Template.parse(template_code).render(tag.attrs)
|
13
|
+
end
|
14
|
+
|
15
|
+
def template_name
|
16
|
+
@tag_template_names[@type] || sitewide_template_names[@type] || plugin_template_names[@type]
|
17
|
+
end
|
18
|
+
|
19
|
+
def template_code
|
20
|
+
@tag_template_code[@type] or
|
21
|
+
fetch_site_template(template_name) or
|
22
|
+
fetch_plugin_template(template_name) or
|
23
|
+
raise LoadError.new("No template named #{template_name}.#{extension}")
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
private
|
28
|
+
def sitewide_template_names
|
29
|
+
if @site.respond_to? :lilypond and @site.lilypond.respond_to? :template_names
|
30
|
+
@site.lilypond.template_names
|
31
|
+
else
|
32
|
+
{ source: nil, include: nil }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def plugin_template_names
|
37
|
+
{ source: "basic", include: "img" }
|
38
|
+
end
|
39
|
+
|
40
|
+
def fetch_site_template(name)
|
41
|
+
if @site.layouts[name]
|
42
|
+
@site.layouts[name].content.strip
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_plugin_template(name)
|
47
|
+
dir = File.join(File.dirname(__dir__), "/jekyll-lilypond/templates/")
|
48
|
+
filename = File.join(dir, "#{name}.#{extension}")
|
49
|
+
if File.exists?(filename)
|
50
|
+
File.read(filename).strip
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def extension
|
55
|
+
if @type == :source then "ly" else "html" end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "jekyll"
|
2
|
+
require "jekyll-lilypond/tag.rb"
|
3
|
+
require "jekyll-lilypond/file_processor.rb"
|
4
|
+
require "jekyll-lilypond/templates.rb"
|
5
|
+
require "jekyll-lilypond/tag_processor.rb"
|
6
|
+
require "jekyll-lilypond/lilypond_tag.rb"
|
7
|
+
|
8
|
+
module Jekyll
|
9
|
+
module Lilypond
|
10
|
+
end
|
11
|
+
end
|