distorted-jekyll 0.5.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +661 -0
- data/README.md +6 -10
- data/lib/distorted-jekyll.rb +79 -0
- data/lib/distorted-jekyll/13th-style.rb +58 -0
- data/lib/distorted-jekyll/_config_default.yml +81 -0
- data/lib/distorted-jekyll/blocks.rb +16 -0
- data/lib/distorted-jekyll/floor.rb +266 -0
- data/lib/distorted-jekyll/invoker.rb +259 -0
- data/lib/distorted-jekyll/md_injection.rb +305 -0
- data/lib/distorted-jekyll/molecule/font.rb +62 -0
- data/lib/distorted-jekyll/molecule/image.rb +94 -0
- data/lib/distorted-jekyll/molecule/lastresort.rb +51 -0
- data/lib/distorted-jekyll/molecule/pdf.rb +79 -0
- data/lib/distorted-jekyll/molecule/svg.rb +47 -0
- data/lib/distorted-jekyll/molecule/text.rb +62 -0
- data/lib/distorted-jekyll/molecule/video.rb +85 -0
- data/lib/distorted-jekyll/monkey_business/jekyll/cleaner.rb +54 -0
- data/lib/distorted-jekyll/static_state.rb +201 -0
- data/lib/distorted-jekyll/template/13th-style.css +79 -0
- data/lib/distorted-jekyll/template/error_code.liquid +3 -0
- data/lib/distorted-jekyll/template/font.liquid +32 -0
- data/lib/distorted-jekyll/template/image.liquid +32 -0
- data/lib/distorted-jekyll/template/lastresort.liquid +20 -0
- data/lib/distorted-jekyll/template/pdf.liquid +14 -0
- data/lib/distorted-jekyll/template/svg.liquid +32 -0
- data/lib/distorted-jekyll/template/text.liquid +32 -0
- data/lib/distorted-jekyll/template/video.liquid +11 -0
- metadata +32 -34
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'distorted/molecule/font'
|
4
|
+
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module DistorteD
|
8
|
+
module Molecule
|
9
|
+
module Font
|
10
|
+
|
11
|
+
include Cooltrainer::DistorteD::Font
|
12
|
+
|
13
|
+
def render_to_output_buffer(context, output)
|
14
|
+
super
|
15
|
+
begin
|
16
|
+
filez = files.keep_if{ |f|
|
17
|
+
# Strip out all non-displayable media-types, e.g. the actual text/whatever.
|
18
|
+
f.key?(:type) && f&.dig(:type)&.media_type == 'image'.freeze
|
19
|
+
}.keep_if{ |f|
|
20
|
+
# Strip out full-size images (will have `nil`) — only display thumbnail vers
|
21
|
+
f.key?(:width) or f.key?(:height)
|
22
|
+
}.map{ |f|
|
23
|
+
# Stringify to make Liquid happy
|
24
|
+
f.transform_values(&:to_s).transform_keys(&:to_s)
|
25
|
+
}
|
26
|
+
output << parse_template.render({
|
27
|
+
'name' => @name,
|
28
|
+
'path' => @relative_dest,
|
29
|
+
'alt' => abstract(:alt),
|
30
|
+
'title' => abstract(:title),
|
31
|
+
'sources' => filez,
|
32
|
+
'fallback_img' => fallback_img,
|
33
|
+
})
|
34
|
+
rescue Liquid::SyntaxError => l
|
35
|
+
unless Jekyll.env == 'production'.freeze
|
36
|
+
output << parse_template(name: 'error_code'.freeze).render({
|
37
|
+
'message' => l.message,
|
38
|
+
})
|
39
|
+
end
|
40
|
+
end
|
41
|
+
output
|
42
|
+
end
|
43
|
+
|
44
|
+
# Return the filename of the most-compatible output image
|
45
|
+
# for use as the fallback <img> tag inside our <picture>.
|
46
|
+
def fallback_img
|
47
|
+
best_ver = nil
|
48
|
+
files.keep_if{|f| f.key?(:type) && f&.dig(:type)&.media_type == 'image'.freeze}.each{ |f|
|
49
|
+
# PNG > WebP
|
50
|
+
if f&.dig(:type)&.sub_type == 'png'.freeze || best_ver.nil?
|
51
|
+
best_ver = f
|
52
|
+
end
|
53
|
+
}
|
54
|
+
# Return the filename of the biggest matched variation,
|
55
|
+
# otherwise use the original filename.
|
56
|
+
best_ver&.dig(:name) || @name
|
57
|
+
end
|
58
|
+
|
59
|
+
end # Font
|
60
|
+
end # Molecule
|
61
|
+
end # DistorteD
|
62
|
+
end # Jekyll
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'distorted/molecule/image'
|
4
|
+
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module DistorteD
|
8
|
+
module Molecule
|
9
|
+
module Image
|
10
|
+
|
11
|
+
include Cooltrainer::DistorteD::Image
|
12
|
+
|
13
|
+
# Returns the filename we should use in the oldschool <img> tag
|
14
|
+
# as a fallback for <picture> sources. This file should be a cropped
|
15
|
+
# variation, the same MIME::Type as the input media, with the largest
|
16
|
+
# resolution possible.
|
17
|
+
# Failing that, use the filename of the original media.
|
18
|
+
# TODO: Handle situations when the input media_type is not in the
|
19
|
+
# Set of output media_types. We should pick the largest cropped variation
|
20
|
+
# of any type in that case.
|
21
|
+
def fallback_img
|
22
|
+
biggest_ver = nil
|
23
|
+
|
24
|
+
# Computes a Set of non-nil MIME::Type.sub_types for all MIME::Types
|
25
|
+
# detected for the original media file.
|
26
|
+
sub_types = type_mars.keep_if{ |m|
|
27
|
+
m.media_type == 'image'.freeze
|
28
|
+
}.map { |m|
|
29
|
+
m.sub_type
|
30
|
+
}.compact.to_set
|
31
|
+
files.keep_if{|f| f.key?(:width) or f.key?(:height)}.each{ |f|
|
32
|
+
if sub_types.include?(f[:type]&.sub_type)
|
33
|
+
if biggest_ver
|
34
|
+
if f[:width] > biggest_ver[:width]
|
35
|
+
biggest_ver = f
|
36
|
+
end
|
37
|
+
else
|
38
|
+
biggest_ver = f
|
39
|
+
end
|
40
|
+
end
|
41
|
+
}
|
42
|
+
# Return the filename of the biggest matched variation,
|
43
|
+
# otherwise use the original filename.
|
44
|
+
biggest_ver&.dig(:name) || @name
|
45
|
+
end
|
46
|
+
|
47
|
+
def outer_limits(*keys)
|
48
|
+
config = super
|
49
|
+
if config.empty?
|
50
|
+
Set[{
|
51
|
+
tag: :full,
|
52
|
+
crop: :none,
|
53
|
+
}]
|
54
|
+
else
|
55
|
+
config
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def render_to_output_buffer(context, output)
|
60
|
+
super
|
61
|
+
begin
|
62
|
+
# Liquid doesn't seem able to reference symbolic keys,
|
63
|
+
# so convert everything to string for template.
|
64
|
+
# Remove full-size images from <sources> list before generating.
|
65
|
+
# Those should only be linked to, not displayed.
|
66
|
+
filez = files.keep_if{|f| f.key?(:width) or f.key?(:height)}.map{ |f|
|
67
|
+
f.transform_values(&:to_s).transform_keys(&:to_s)
|
68
|
+
}
|
69
|
+
|
70
|
+
output << parse_template.render({
|
71
|
+
'name' => @name,
|
72
|
+
'path' => @relative_dest,
|
73
|
+
'alt' => abstract(:alt),
|
74
|
+
'title' => abstract(:title),
|
75
|
+
'href' => abstract(:href),
|
76
|
+
'caption' => abstract(:caption),
|
77
|
+
'loading' => abstract(:loading),
|
78
|
+
'sources' => filez,
|
79
|
+
'fallback_img' => fallback_img,
|
80
|
+
})
|
81
|
+
rescue Liquid::SyntaxError => l
|
82
|
+
unless Jekyll.env == 'production'.freeze
|
83
|
+
output << parse_template(name: 'error_code'.freeze).render({
|
84
|
+
'message' => l.message,
|
85
|
+
})
|
86
|
+
end
|
87
|
+
end
|
88
|
+
output
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'distorted/checking_you_out'
|
4
|
+
require 'distorted/injection_of_love'
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module DistorteD
|
8
|
+
module Molecule
|
9
|
+
module LastResort
|
10
|
+
|
11
|
+
|
12
|
+
LOWER_WORLD = CHECKING::YOU::IN('application/x.distorted.last-resort')
|
13
|
+
|
14
|
+
ATTRIBUTES = Set[:alt, :title, :href, :caption]
|
15
|
+
ATTRIBUTES_DEFAULT = {}
|
16
|
+
ATTRIBUTES_VALUES = {}
|
17
|
+
|
18
|
+
# This is one of the few render methods that will be defined in JekyllLand.
|
19
|
+
define_method(CHECKING::YOU::IN('application/x.distorted.last-resort').first.distorted_method) { |*a, **k, &b|
|
20
|
+
copy_file(*a, **k, &b)
|
21
|
+
}
|
22
|
+
|
23
|
+
include Cooltrainer::DistorteD::InjectionOfLove
|
24
|
+
|
25
|
+
|
26
|
+
def render_to_output_buffer(context, output)
|
27
|
+
super
|
28
|
+
begin
|
29
|
+
output << parse_template.render({
|
30
|
+
'name' => @name,
|
31
|
+
'basename' => File.basename(@name, '.*'),
|
32
|
+
'path' => @relative_dest,
|
33
|
+
'alt' => abstract(:alt),
|
34
|
+
'title' => abstract(:title),
|
35
|
+
'href' => abstract(:href),
|
36
|
+
'caption' => abstract(:caption),
|
37
|
+
})
|
38
|
+
rescue Liquid::SyntaxError => l
|
39
|
+
unless Jekyll.env == 'production'.freeze
|
40
|
+
output << parse_template(name: 'error_code'.freeze).render({
|
41
|
+
'message' => l.message,
|
42
|
+
})
|
43
|
+
end
|
44
|
+
end
|
45
|
+
output
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'distorted/molecule/pdf'
|
4
|
+
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module DistorteD
|
8
|
+
module Molecule
|
9
|
+
module PDF
|
10
|
+
|
11
|
+
include Cooltrainer::DistorteD::PDF
|
12
|
+
|
13
|
+
|
14
|
+
# Generate a Hash of our PDF Open Params based on any given to the Liquid tag
|
15
|
+
# and any loaded from the defaults.
|
16
|
+
# https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/pdf_open_parameters.pdf
|
17
|
+
def pdf_open_params
|
18
|
+
PDF_OPEN_PARAMS.map{ |p|
|
19
|
+
if ATTRIBUTES_VALUES.dig(p) == BOOLEAN_ATTR_VALUES
|
20
|
+
# Support multiple ways people might want to express a boolean
|
21
|
+
if Set[0, '0'.freeze, false, 'false'.freeze].include?(abstract(p))
|
22
|
+
[p, '0'.freeze]
|
23
|
+
elsif Set[1, '1'.freeze, true, 'true'.freeze].include?(abstract(p))
|
24
|
+
[p, '1'.freeze]
|
25
|
+
end
|
26
|
+
else
|
27
|
+
[p, abstract(p)]
|
28
|
+
end
|
29
|
+
}.to_h
|
30
|
+
end
|
31
|
+
|
32
|
+
# Generate the URL fragment version of the PDF Open Params.
|
33
|
+
# This would be difficult / impossible to construct within Liquid
|
34
|
+
# from the individual variables, so let's just do it out here.
|
35
|
+
def pdf_open_params_url
|
36
|
+
pdf_open_params.keep_if{ |p,v|
|
37
|
+
v != nil && v != ""
|
38
|
+
}.map{ |k,v|
|
39
|
+
# The PDF Open Params docs specify `search` should be quoted.
|
40
|
+
if k == :search
|
41
|
+
"#{k}=\"#{v}\""
|
42
|
+
else
|
43
|
+
"#{k}=#{v}"
|
44
|
+
end
|
45
|
+
}.join('&')
|
46
|
+
end
|
47
|
+
|
48
|
+
def render_to_output_buffer(context, output)
|
49
|
+
super
|
50
|
+
begin
|
51
|
+
# TODO: iOS treats our <object> like an <img>,
|
52
|
+
# showing only the first page with transparency and stretched to the
|
53
|
+
# size of the container element.
|
54
|
+
# We will need something like PDF.js in an <iframe> to handle this.
|
55
|
+
|
56
|
+
output << parse_template.render({
|
57
|
+
'name' => @name,
|
58
|
+
'path' => @relative_dest,
|
59
|
+
'alt' => abstract(:alt),
|
60
|
+
'title' => abstract(:title),
|
61
|
+
'height' => abstract(:height),
|
62
|
+
'width' => abstract(:width),
|
63
|
+
'caption' => abstract(:caption),
|
64
|
+
'pdf_open_params' => pdf_open_params_url,
|
65
|
+
})
|
66
|
+
rescue Liquid::SyntaxError => l
|
67
|
+
unless Jekyll.env == 'production'.freeze
|
68
|
+
output << parse_template(name: 'error_code'.freeze).render({
|
69
|
+
'message' => l.message,
|
70
|
+
})
|
71
|
+
end
|
72
|
+
end
|
73
|
+
output
|
74
|
+
end
|
75
|
+
|
76
|
+
end # PDF
|
77
|
+
end # Molecule
|
78
|
+
end # DistorteD
|
79
|
+
end # Jekyll
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'distorted/molecule/svg'
|
4
|
+
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module DistorteD
|
8
|
+
module Molecule
|
9
|
+
module SVG
|
10
|
+
|
11
|
+
include Cooltrainer::DistorteD::SVG
|
12
|
+
|
13
|
+
def render_to_output_buffer(context, output)
|
14
|
+
super
|
15
|
+
begin
|
16
|
+
# Liquid doesn't seem able to reference symbolic keys,
|
17
|
+
# so convert everything to string for template.
|
18
|
+
# Not stripping :full tags like Image because all of our
|
19
|
+
# SVG variations will be full-res for now.
|
20
|
+
filez = files.map{ |f|
|
21
|
+
f.transform_values(&:to_s).transform_keys(&:to_s)
|
22
|
+
}
|
23
|
+
output << parse_template.render({
|
24
|
+
'name' => @name,
|
25
|
+
'path' => @relative_dest,
|
26
|
+
'alt' => abstract(:alt),
|
27
|
+
'title' => abstract(:title),
|
28
|
+
'href' => abstract(:href),
|
29
|
+
'caption' => abstract(:caption),
|
30
|
+
'loading' => abstract(:loading),
|
31
|
+
'sources' => filez,
|
32
|
+
'fallback_img' => @name,
|
33
|
+
})
|
34
|
+
rescue Liquid::SyntaxError => l
|
35
|
+
unless Jekyll.env == 'production'.freeze
|
36
|
+
output << parse_template(name: 'error_code'.freeze).render({
|
37
|
+
'message' => l.message,
|
38
|
+
})
|
39
|
+
end
|
40
|
+
end
|
41
|
+
output
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'distorted/molecule/text'
|
4
|
+
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module DistorteD
|
8
|
+
module Molecule
|
9
|
+
module Text
|
10
|
+
|
11
|
+
include Cooltrainer::DistorteD::Text
|
12
|
+
|
13
|
+
def render_to_output_buffer(context, output)
|
14
|
+
super
|
15
|
+
begin
|
16
|
+
filez = files.keep_if{ |f|
|
17
|
+
# Strip out all non-displayable media-types, e.g. the actual text/whatever.
|
18
|
+
f.key?(:type) && f&.dig(:type)&.media_type == 'image'.freeze
|
19
|
+
}.keep_if{ |f|
|
20
|
+
# Strip out full-size images (will have `nil`) — only display thumbnail vers
|
21
|
+
f.key?(:width) or f.key?(:height)
|
22
|
+
}.map{ |f|
|
23
|
+
# Stringify to make Liquid happy
|
24
|
+
f.transform_values(&:to_s).transform_keys(&:to_s)
|
25
|
+
}
|
26
|
+
output << parse_template.render({
|
27
|
+
'name' => @name,
|
28
|
+
'path' => @relative_dest,
|
29
|
+
'alt' => abstract(:alt),
|
30
|
+
'title' => abstract(:title),
|
31
|
+
'sources' => filez,
|
32
|
+
'fallback_img' => fallback_img,
|
33
|
+
})
|
34
|
+
rescue Liquid::SyntaxError => l
|
35
|
+
unless Jekyll.env == 'production'.freeze
|
36
|
+
output << parse_template(name: 'error_code'.freeze).render({
|
37
|
+
'message' => l.message,
|
38
|
+
})
|
39
|
+
end
|
40
|
+
end
|
41
|
+
output
|
42
|
+
end
|
43
|
+
|
44
|
+
# Return the filename of the most-compatible output image
|
45
|
+
# for use as the fallback <img> tag inside our <picture>.
|
46
|
+
def fallback_img
|
47
|
+
best_ver = nil
|
48
|
+
files.keep_if{|f| f.key?(:type) && f&.dig(:type)&.media_type == 'image'.freeze}.each{ |f|
|
49
|
+
# PNG > WebP
|
50
|
+
if f&.dig(:type)&.sub_type == 'png'.freeze || best_ver.nil?
|
51
|
+
best_ver = f
|
52
|
+
end
|
53
|
+
}
|
54
|
+
# Return the filename of the biggest matched variation,
|
55
|
+
# otherwise use the original filename.
|
56
|
+
best_ver&.dig(:name) || @name
|
57
|
+
end
|
58
|
+
|
59
|
+
end # Text
|
60
|
+
end # Molecule
|
61
|
+
end # DistorteD
|
62
|
+
end # Jekyll
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'distorted/molecule/video'
|
2
|
+
|
3
|
+
|
4
|
+
module Jekyll
|
5
|
+
module DistorteD
|
6
|
+
module Molecule
|
7
|
+
module Video
|
8
|
+
|
9
|
+
include Cooltrainer::DistorteD::Video
|
10
|
+
|
11
|
+
def render_to_output_buffer(context, output)
|
12
|
+
super
|
13
|
+
begin
|
14
|
+
output << parse_template.render({
|
15
|
+
'name' => @name,
|
16
|
+
'basename' => File.basename(@name, '.*'),
|
17
|
+
'path' => @url,
|
18
|
+
'caption' => abstract(:caption),
|
19
|
+
})
|
20
|
+
rescue Liquid::SyntaxError => l
|
21
|
+
unless Jekyll.env == 'production'.freeze
|
22
|
+
output << parse_template(name: 'error_code'.freeze).render({
|
23
|
+
'message' => l.message,
|
24
|
+
})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
output
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return a Set of extant video variations due to inability/unwillingness
|
31
|
+
# to exactly predict GStreamer's HLS/DASH segment output naming
|
32
|
+
# even if we are controlling all variables like segment length etc.
|
33
|
+
# This implementation may give stale segments but will at least speed
|
34
|
+
# up site generation by not having to regenerate the video every time.
|
35
|
+
def destinations(dest)
|
36
|
+
wanted = Set[]
|
37
|
+
if Dir.exist?(File.join(dest, @relative_dest))
|
38
|
+
hls_dir = File.join(dest, @relative_dest, "#{basename}.hls")
|
39
|
+
if Dir.exist?(hls_dir)
|
40
|
+
wanted.merge(Dir.entries(hls_dir).to_set.map{|f| File.join(hls_dir, f)})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
wanted
|
44
|
+
end
|
45
|
+
|
46
|
+
def modified?
|
47
|
+
# We can't use the standard Static::State#modified? here until
|
48
|
+
# I figure out how to cleanly get a duplicate of what would be
|
49
|
+
# the generated filenames from GStreamer's sink.
|
50
|
+
#
|
51
|
+
# For now for the sake of speeding up my site generation
|
52
|
+
# I'll assume not-modified that if the output variant (e.g. DASH/HLS)
|
53
|
+
# container dir exists and contains at least two files:
|
54
|
+
# the playlist and at least one segment.
|
55
|
+
#
|
56
|
+
# Hacky HLS-only right now until dashsink2 lands in upstream Gst.
|
57
|
+
#
|
58
|
+
# Assume modified for the sake of freshness :)
|
59
|
+
modified = true
|
60
|
+
|
61
|
+
site_dest = Jekyll::DistorteD::Floor::config(:destination).to_s
|
62
|
+
if Dir.exist?(site_dest)
|
63
|
+
|
64
|
+
dd_dest = File.join(site_dest, @relative_dest)
|
65
|
+
if Dir.exist?(dd_dest)
|
66
|
+
|
67
|
+
hls_dir = File.join(dd_dest, "#{basename}.hls")
|
68
|
+
if Dir.exist?(hls_dir)
|
69
|
+
need_filez = Set["#{basename}.m3u8"]
|
70
|
+
var_filez = Dir.entries(hls_dir).to_set
|
71
|
+
if need_filez.subset?(var_filez) and var_filez.count > 2
|
72
|
+
modified = false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
Jekyll.logger.debug("#{@name} modified?", modified)
|
79
|
+
modified
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|