distorted-jekyll 0.5.3 → 0.6.0
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 +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
|