octopod-exe 0.9.4
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/README.md +8 -0
- data/Rakefile +11 -0
- data/assets/_config.yml.sample +48 -0
- data/assets/_includes/disqus_count.html +13 -0
- data/assets/_includes/disqus_thread.html +13 -0
- data/assets/_includes/flattr_loader.html +14 -0
- data/assets/_includes/isso_thread.html +6 -0
- data/assets/_includes/post.html +20 -0
- data/assets/_includes/post_header.html +17 -0
- data/assets/_includes/post_line.html +3 -0
- data/assets/_includes/sidebar.html +109 -0
- data/assets/_includes/tweet_us.html +3 -0
- data/assets/_layouts/default.html +86 -0
- data/assets/_layouts/feed.xml +107 -0
- data/assets/_layouts/jsonfeed.json +48 -0
- data/assets/_layouts/page.html +15 -0
- data/assets/_layouts/player_index.html +36 -0
- data/assets/_layouts/post.html +10 -0
- data/assets/_layouts/with_twitter_card.html +98 -0
- data/assets/_posts/2016-03-22-episode0.md +24 -0
- data/assets/_sass/_overrides.scss +68 -0
- data/assets/apple-touch-icon-precomposed.png +0 -0
- data/assets/episodes.m4a.rss +5 -0
- data/assets/episodes.mp3.rss +5 -0
- data/assets/episodes.ogg.rss +5 -0
- data/assets/episodes/episode0.m4a +0 -0
- data/assets/episodes/episode0.mp3 +0 -0
- data/assets/episodes/episode0.ogg +0 -0
- data/assets/favicon.ico +0 -0
- data/assets/feed.m4a.json +5 -0
- data/assets/feed.mp3.json +5 -0
- data/assets/feed.ogg.json +5 -0
- data/assets/general_feed.xml +30 -0
- data/assets/img/favicon.ico +0 -0
- data/assets/img/logo-360x360.png +0 -0
- data/assets/img/logo-itunes.jpg +0 -0
- data/assets/img/logo.jpg +0 -0
- data/assets/img/logo/android-icon-144x144.png +0 -0
- data/assets/img/logo/android-icon-192x192.png +0 -0
- data/assets/img/logo/android-icon-36x36.png +0 -0
- data/assets/img/logo/android-icon-48x48.png +0 -0
- data/assets/img/logo/android-icon-72x72.png +0 -0
- data/assets/img/logo/android-icon-96x96.png +0 -0
- data/assets/img/logo/apple-icon-114x114.png +0 -0
- data/assets/img/logo/apple-icon-120x120.png +0 -0
- data/assets/img/logo/apple-icon-144x144.png +0 -0
- data/assets/img/logo/apple-icon-152x152.png +0 -0
- data/assets/img/logo/apple-icon-180x180.png +0 -0
- data/assets/img/logo/apple-icon-57x57.png +0 -0
- data/assets/img/logo/apple-icon-60x60.png +0 -0
- data/assets/img/logo/apple-icon-72x72.png +0 -0
- data/assets/img/logo/apple-icon-76x76.png +0 -0
- data/assets/img/logo/apple-icon-precomposed.png +0 -0
- data/assets/img/logo/apple-icon.png +0 -0
- data/assets/img/logo/browserconfig.xml +2 -0
- data/assets/img/logo/favicon-16x16.png +0 -0
- data/assets/img/logo/favicon-32x32.png +0 -0
- data/assets/img/logo/favicon-96x96.png +0 -0
- data/assets/img/logo/favicon.ico +0 -0
- data/assets/img/logo/manifest.json +41 -0
- data/assets/img/logo/ms-icon-144x144.png +0 -0
- data/assets/img/logo/ms-icon-150x150.png +0 -0
- data/assets/img/logo/ms-icon-310x310.png +0 -0
- data/assets/img/logo/ms-icon-70x70.png +0 -0
- data/assets/imprint.md +19 -0
- data/assets/index.md +14 -0
- data/bin/octopod +273 -0
- data/lib/jekyll-octopod.rb +11 -0
- data/lib/jekyll/date_de.rb +54 -0
- data/lib/jekyll/flattr_filters.rb +107 -0
- data/lib/jekyll/octopod_filters.rb +336 -0
- data/lib/jekyll/paged_feed_page.rb +22 -0
- data/lib/jekyll/paged_feed_page_generator.rb +20 -0
- data/lib/jekyll/podcast_player_page.rb +24 -0
- data/lib/jekyll/podcast_player_page_generator.rb +14 -0
- data/lib/jekyll/podigee_player_tag.rb +44 -0
- data/lib/jekyll/static_file.rb +20 -0
- data/lib/jekyll/update_config.rb +14 -0
- data/lib/octopod/version.rb +11 -0
- metadata +580 -0
@@ -0,0 +1,336 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'digest/sha1'
|
3
|
+
|
4
|
+
module Jekyll
|
5
|
+
module OctopodFilters
|
6
|
+
JSON_ENTITIES = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C', "'" => '\u0027' }
|
7
|
+
|
8
|
+
# Escapes some text for CDATA
|
9
|
+
def cdata_escape(input)
|
10
|
+
input.gsub(/<!\[CDATA\[/, '<![CDATA[').gsub(/\]\]>/, ']]>')
|
11
|
+
end
|
12
|
+
|
13
|
+
# Escapes HTML entities in JSON strings.
|
14
|
+
# More or less a copy of the equivalent method in Active Support.
|
15
|
+
# https://github.com/rails/rails/tree/master/activesupport
|
16
|
+
def j(str)
|
17
|
+
str.to_s.gsub(/[&"><']/) { |e| JSON_ENTITIES[e] }
|
18
|
+
end
|
19
|
+
|
20
|
+
# Replaces relative urls with full urls
|
21
|
+
#
|
22
|
+
# {{ "about.html" | expand_urls }} => "/about.html"
|
23
|
+
# {{ "about.html" | expand_urls:site.url }} => "http://example.com/about.html"
|
24
|
+
def expand_urls(input, url='')
|
25
|
+
url ||= '/'
|
26
|
+
input.gsub /(\s+(href|src)\s*=\s*["|']{1})(\/[^\"'>]*)/ do
|
27
|
+
$1+url+$3
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Removes scripts tag and audio tags in multiline moderator
|
32
|
+
def remove_script_and_audio(input)
|
33
|
+
input.gsub(/<audio.*audio>/m, '').gsub(/<script.*script>/m, '')
|
34
|
+
end
|
35
|
+
|
36
|
+
# Formats a Time to be RSS compatible like "Wed, 15 Jun 2005 19:00:00 GMT"
|
37
|
+
#
|
38
|
+
# {{ site.time | time_to_rssschema }}
|
39
|
+
def time_to_rssschema(time)
|
40
|
+
time.strftime("%a, %d %b %Y %H:%M:%S %z")
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the first argument if it's not nil or empty otherwise it returns
|
44
|
+
# the second one.
|
45
|
+
#
|
46
|
+
# {{ post.author | otherwise:site.author }}
|
47
|
+
def otherwise(first, second)
|
48
|
+
first = first.to_s
|
49
|
+
first.empty? ? second : first
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns the audio file name of a given hash. Is no key as second parameter given, it
|
53
|
+
# trys first "mp3", than "m4a" and than it will return a more or less random
|
54
|
+
# value.
|
55
|
+
#
|
56
|
+
# {{ post.audio | audio:"m4a" }} => "my-episode.m4a"
|
57
|
+
def audio(hsh, key = nil)
|
58
|
+
if key.nil?
|
59
|
+
hsh['mp3'] ? hsh['mp3'] : hsh['m4a'] ? hsh['m4a'] : hsh['ogg'] ? hsh['ogg'] : hsh['opus'] ? hsh['opus'] : hsh.values.first
|
60
|
+
else
|
61
|
+
hsh[key]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# Returns the audio-type of a given hash. Is no key as second parameter given, it
|
67
|
+
# trys first "mp3", than "m4a" and than it will return a more or less random
|
68
|
+
# value.
|
69
|
+
#
|
70
|
+
# {{ post.audio | audiotype }} => "my-episode.m4a"
|
71
|
+
def audio_type(hsh)
|
72
|
+
hsh['mp3'] ? mime_type('mp3') : hsh['m4a'] ? mime_type('m4a') : hsh['ogg'] ? mime_type('ogg') : mime_type('opus')
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# Returns the MIME-Type of a given file format.
|
77
|
+
#
|
78
|
+
# {{ "m4a" | mime_type }} => "audio/mp4a-latm"
|
79
|
+
def mime_type(format)
|
80
|
+
types = {
|
81
|
+
'mp3' => 'mpeg',
|
82
|
+
'm4a' => 'mp4a-latm',
|
83
|
+
'ogg' => 'ogg; codecs=vorbis',
|
84
|
+
'opus' => 'ogg; codecs=opus'
|
85
|
+
}
|
86
|
+
|
87
|
+
"audio/#{types[format]}"
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns the size of a given file in bytes. If there is just a filename
|
91
|
+
# without a path, this method assumes that the file is an episode audio file
|
92
|
+
# which lives in /episodes.
|
93
|
+
#
|
94
|
+
# {{ "example.m4a" | file_size }} => 4242
|
95
|
+
def file_size(path, rel = nil)
|
96
|
+
return 0 if path.nil?
|
97
|
+
path = path =~ /\// ? path : File.join('episodes', path)
|
98
|
+
path = rel + path if rel
|
99
|
+
File.size(path)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns a slug based on the id of a given page.
|
103
|
+
#
|
104
|
+
# {{ page | slug }} => '2012_10_02_octopod'
|
105
|
+
def slug(page)
|
106
|
+
page['id'][1..-1].gsub('/', '_')
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns the image of the post or the default logo.
|
110
|
+
#
|
111
|
+
# {{ page | image_with_fallback }} => '/path/to/image.png'
|
112
|
+
def image_with_fallback(page)
|
113
|
+
if page["image"]
|
114
|
+
"/img/" + page["image"]
|
115
|
+
else
|
116
|
+
"/img/logo-itunes.jpg"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns the dowrload url with fallback to the site's episode folder url
|
121
|
+
def download_url_with_fallback(site)
|
122
|
+
if site["download_url"] == "" or site["download_url"] == nil
|
123
|
+
site["url"] + "/episodes"
|
124
|
+
else
|
125
|
+
site["download_url"]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
# Splits a chapter, like it is written to the post YAML front matter into
|
131
|
+
# the components 'start' which refers to a single point in time relative to
|
132
|
+
# the beginning of the media file nad 'title' which defines the text to be
|
133
|
+
# the title of the chapter.
|
134
|
+
#
|
135
|
+
# {{ '00:00:00.000 Welcome to Octopod!' | split_chapter }}
|
136
|
+
# => { 'start' => '00:00:00.000', 'title' => 'Welcome to Octopod!' }
|
137
|
+
#
|
138
|
+
# {{ '00:00:00.000 Welcome to Octopod!' | split_chapter:'title' }}
|
139
|
+
# => 'Welcome to Octopod!'
|
140
|
+
#
|
141
|
+
# {{ '00:00:00.000 Welcome to Octopod!' | split_chapter:'start' }}
|
142
|
+
# => '00:00:00.000'
|
143
|
+
def split_chapter(chapter_str, attribute = nil)
|
144
|
+
attributes = chapter_str.split(/ /, 2)
|
145
|
+
return nil unless attributes.first.match(/\A(\d|:|\.)+\z/)
|
146
|
+
|
147
|
+
if attribute.nil?
|
148
|
+
{ 'start' => attributes.first, 'title' => attributes.last }
|
149
|
+
else
|
150
|
+
attribute == 'start' ? attributes.first : attributes.last
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
# Gets a number of seconds and returns an human readable duration string of
|
156
|
+
# it.
|
157
|
+
#
|
158
|
+
# {{ 1252251 | string_of_duration }} => "00:03:13"
|
159
|
+
def string_of_duration(duration)
|
160
|
+
seconds = duration.to_i
|
161
|
+
minutes = seconds / 60
|
162
|
+
hours = minutes / 60
|
163
|
+
|
164
|
+
"#{"%02d" % hours}:#{"%02d" % (minutes % 60)}:#{"%02d" % (seconds % 60)}"
|
165
|
+
end
|
166
|
+
|
167
|
+
# Gets a number of bytes and returns an human readable string of it.
|
168
|
+
#
|
169
|
+
# {{ 1252251 | string_of_size }} => "1.19M"
|
170
|
+
def string_of_size(bytes)
|
171
|
+
bytes = bytes.to_i.to_f
|
172
|
+
out = '0'
|
173
|
+
return out if bytes == 0.0
|
174
|
+
|
175
|
+
jedec = %w[b K M G]
|
176
|
+
[3, 2, 1, 0].each { |i|
|
177
|
+
if bytes > 1024 ** i
|
178
|
+
out = "%.1f#{jedec[i]}" % (bytes / 1024 ** i)
|
179
|
+
break
|
180
|
+
end
|
181
|
+
}
|
182
|
+
|
183
|
+
return out
|
184
|
+
end
|
185
|
+
|
186
|
+
# Returns the host a given url
|
187
|
+
#
|
188
|
+
# {{ 'https://github.com/pattex/octopod' | host_from_url }} => "github.com"
|
189
|
+
def host_from_url(url)
|
190
|
+
URI.parse(url).host
|
191
|
+
end
|
192
|
+
|
193
|
+
# Generates the config for disqus integration
|
194
|
+
# If a page object is given, it generates the config variables only for this
|
195
|
+
# page. Otherwise it generate only the global config variables.
|
196
|
+
#
|
197
|
+
# {{ site | disqus_config }}
|
198
|
+
# {{ site | disqus_config:page }}
|
199
|
+
def disqus_config(site, page = nil)
|
200
|
+
if page
|
201
|
+
disqus_vars = {
|
202
|
+
'disqus_identifier' => page['url'],
|
203
|
+
'disqus_url' => "#{site['url']}#{page['url']}",
|
204
|
+
'disqus_category_id' => page['disqus_category_id'] || site['disqus_category_id'],
|
205
|
+
'disqus_title' => j(page['title'] || site['site'])
|
206
|
+
}
|
207
|
+
else
|
208
|
+
disqus_vars = {
|
209
|
+
'disqus_developer' => site['disqus_developer'],
|
210
|
+
'disqus_shortname' => site['disqus_shortname']
|
211
|
+
}
|
212
|
+
end
|
213
|
+
|
214
|
+
disqus_vars.delete_if { |_, v| v.nil? }
|
215
|
+
disqus_vars.map { |k, v| "var #{k} = '#{v}';" }.compact.join("\n")
|
216
|
+
end
|
217
|
+
|
218
|
+
# Returns the hex-encoded hash value of a given string. The optional
|
219
|
+
# second argument defines the length of the returned string.
|
220
|
+
#
|
221
|
+
# {{ "Octopod" | sha1 }} => "8b20a59c"
|
222
|
+
# {{ "Octopod" | sha1:23 }} => "8b20a59c8e2dcb5e1f845ba"
|
223
|
+
def sha1(str, lenght = 8)
|
224
|
+
sha1 = Digest::SHA1.hexdigest(str)
|
225
|
+
sha1[0, lenght.to_i]
|
226
|
+
end
|
227
|
+
|
228
|
+
# Returns a, ready to use, navigation list of all pages that have
|
229
|
+
# <tt>navigation</tt> set in their YAML front matter. The list is sorted by
|
230
|
+
# the value of <tt>navigation</tt>.
|
231
|
+
#
|
232
|
+
# {{ site | navigation_list:page }}
|
233
|
+
def navigation_list(site, page)
|
234
|
+
pages = site['pages'].select { |p|
|
235
|
+
p.data['navigation'] && p.data['title']
|
236
|
+
}.sort_by { |p| p.data['navigation'] }
|
237
|
+
|
238
|
+
list = []
|
239
|
+
list << pages.map { |p|
|
240
|
+
active = (p.url == page['url']) || (page.key?('next') && File.join(p.dir, p.basename) == '/index')
|
241
|
+
navigation_list_item(File.join(site['url'], p.url), p.data['title'], active)
|
242
|
+
}
|
243
|
+
list.join("\n")
|
244
|
+
end
|
245
|
+
|
246
|
+
def talk_list(site, page)
|
247
|
+
pages = site['pages'].select { |p|
|
248
|
+
p.data['talk'] && p.data['title']
|
249
|
+
}.sort_by { |p| p.data['talk'] }
|
250
|
+
|
251
|
+
list = ['<li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false"> Talks <span class="caret"></span>
|
252
|
+
</a><ul class="dropdown-menu">']
|
253
|
+
list << pages.map { |p|
|
254
|
+
active = (p.url == page['url']) || (page.key?('next') && File.join(p.dir, p.basename) == '/index')
|
255
|
+
navigation_list_item(File.join(site['url'], p.url), p.data['title'], active)
|
256
|
+
}
|
257
|
+
list << ['</ul></li>']
|
258
|
+
|
259
|
+
list.join("\n")
|
260
|
+
end
|
261
|
+
|
262
|
+
def navigation_list_item(url, title, active = false)
|
263
|
+
a_class = active ? ' class="active"' : ''
|
264
|
+
%Q{<li#{a_class}><a #{a_class} href="#{url}">#{title}</a></li>}
|
265
|
+
end
|
266
|
+
|
267
|
+
# Returns an array of all episode feeds named by the convetion
|
268
|
+
# 'episodes.<episode_file_format>.rss' within the root directory. Also it
|
269
|
+
# contains all additional feeds specified by 'additional_feeds' in the
|
270
|
+
# '_config.yml'. If an 'episode_file_format' or key of 'additional_feeds'
|
271
|
+
# equals the optional parameter 'except', it will be skipped.
|
272
|
+
#
|
273
|
+
# episode_feeds(site, except = nil) =>
|
274
|
+
# [
|
275
|
+
# ["m4a Episode RSS-Feed", "/episodes.m4a.rss"],
|
276
|
+
# ["mp3 Episode RSS-Feed", "/episodes.mp3.rss"],
|
277
|
+
# ["Torrent Feed m4a", "http://bitlove.org/octopod/octopod_m4a/feed"],
|
278
|
+
# ["Torrent Feed mp3", "http://bitlove.org/octopod/octopod_mp3/feed"]
|
279
|
+
# ]
|
280
|
+
def episode_feeds(site, except = nil)
|
281
|
+
feeds = []
|
282
|
+
|
283
|
+
if site['episode_feed_formats']
|
284
|
+
site['episode_feed_formats'].map { |f|
|
285
|
+
feeds << ["#{f} Episode RSS-Feed", "#{site['url']}/episodes.#{f}.rss"] unless f == except
|
286
|
+
}
|
287
|
+
end
|
288
|
+
if site['additional_feeds']
|
289
|
+
site['additional_feeds'].each { |k, v|
|
290
|
+
feeds << [k.gsub('_', ' '), v] unless k == except
|
291
|
+
}
|
292
|
+
end
|
293
|
+
|
294
|
+
feeds
|
295
|
+
end
|
296
|
+
|
297
|
+
# Returns HTML links to all episode feeds named by the convetion
|
298
|
+
# 'episodes.<episode_file_format>.rss' within the root directory. Also it
|
299
|
+
# returns all additional feeds specified by 'additional_feeds' in the
|
300
|
+
# '_config.yml'. If an 'episode_file_format' or key of 'additional_feeds'
|
301
|
+
# equals the optional parameter 'except', it will be skipped.
|
302
|
+
#
|
303
|
+
# {{ site | episode_feeds_html:'m4a' }} =>
|
304
|
+
# <link rel="alternate" type="application/rss+xml" title="mp3 Episode RSS-Feed" href="/episodes.mp3.rss" />
|
305
|
+
# <link rel="alternate" type="application/rss+xml" title="Torrent Feed m4a" href="http://bitlove.org/octopod/octopod_m4a/feed" />
|
306
|
+
# <link rel="alternate" type="application/rss+xml" title="Torrent Feed mp3" href="http://bitlove.org/octopod/octopod_mp3/feed" />
|
307
|
+
def episode_feeds_html(site, except = nil)
|
308
|
+
episode_feeds(site, except).map { |f|
|
309
|
+
%Q{<link rel="alternate" type="application/rss+xml" title="#{f.first || f.last}" href="#{f.last}" />}
|
310
|
+
}.join("\n")
|
311
|
+
end
|
312
|
+
|
313
|
+
# Returns RSS-XML links to all episode feeds named by the convetion
|
314
|
+
# 'episodes.<episode_file_format>.rss' within the root directory. Also it
|
315
|
+
# returns all additional feeds specified by 'additional_feeds' in the
|
316
|
+
# '_config.yml'. If an 'episode_file_format' or key of 'additional_feeds'
|
317
|
+
# equals the optional parameter 'except', it will be skipped.
|
318
|
+
#
|
319
|
+
# {{ site | episode_feeds_rss:'m4a' }} =>
|
320
|
+
# <atom:link rel="alternate" href="/episodes.mp3.rss" type="application/rss+xml" title="mp3 Episode RSS-Feed"/>
|
321
|
+
# <atom:link rel="alternate" href="http://bitlove.org/octopod/octopod_m4a/feed" type="application/rss+xml" title="Torrent Feed m4a"/>
|
322
|
+
# <atom:link rel="alternate" href="http://bitlove.org/octopod/octopod_mp3/feed" type="application/rss+xml" title="Torrent Feed mp3"/>
|
323
|
+
def episode_feeds_rss(site, except = nil)
|
324
|
+
episode_feeds(site, except).map { |f|
|
325
|
+
%Q{<atom:link rel="alternate" href="#{f.last}" type="application/rss+xml" title="#{f.first || f.last}"/>}
|
326
|
+
}.join("\n")
|
327
|
+
end
|
328
|
+
|
329
|
+
# Prints out current version
|
330
|
+
def version_string(site)
|
331
|
+
Jekyll::Octopod::VERSION::STRING
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
Liquid::Template.register_filter(Jekyll::OctopodFilters)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Jekyll
|
2
|
+
class PagedFeedPage < Page
|
3
|
+
def initialize(site, base, dir, name, page_number, pages_total, format)
|
4
|
+
@site = site
|
5
|
+
@dir = "/"
|
6
|
+
@name = name
|
7
|
+
|
8
|
+
self.process(@name)
|
9
|
+
self.read_yaml(File.join(base, '_layouts'), 'feed.xml')
|
10
|
+
self.data['next'] = pages_total > page_number ? (page_number + 1).to_s : nil
|
11
|
+
self.data['last'] = pages_total > 1 ? pages_total.to_s : nil
|
12
|
+
self.data['prev'] = case page_number
|
13
|
+
when 1 then nil
|
14
|
+
when 2 then ""
|
15
|
+
else (page_number - 1).to_s
|
16
|
+
end
|
17
|
+
self.data['myself'] = page_number == 1 ? nil : page_number.to_s
|
18
|
+
self.data['format'] = format
|
19
|
+
self.data['page_number'] = page_number
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Jekyll
|
2
|
+
class PagedFeedPageGenerator < Generator
|
3
|
+
safe true
|
4
|
+
|
5
|
+
def generate(site)
|
6
|
+
pages_total = (site.posts.docs.count.to_f / site.config["episodes_per_feed_page"]).ceil
|
7
|
+
|
8
|
+
site.config["episode_feed_formats"].each do |page_format|
|
9
|
+
name = "episodes." + page_format + ".rss"
|
10
|
+
page = PagedFeedPage.new(site, site.source, ".", name, 1, pages_total, page_format)
|
11
|
+
site.pages << page
|
12
|
+
(1..pages_total).each do |page_number|
|
13
|
+
name = "episodes" + page_number.to_s + "." + page_format + ".rss"
|
14
|
+
page = PagedFeedPage.new(site, site.source, ".", name, page_number, pages_total, page_format)
|
15
|
+
site.pages << page
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Jekyll
|
2
|
+
class PodcastPlayerPage < Page
|
3
|
+
def initialize(site, base, dir, post)
|
4
|
+
@site = site
|
5
|
+
@base = base
|
6
|
+
@dir = dir
|
7
|
+
@name = 'index.html'
|
8
|
+
|
9
|
+
self.process(@name)
|
10
|
+
self.read_yaml(File.join(base, '_layouts'), 'player_index.html')
|
11
|
+
|
12
|
+
self.data['title'] = post.data['title']
|
13
|
+
self.data['subtitle'] = post.data['subtitle']
|
14
|
+
self.data['datum'] = post.data['datum']
|
15
|
+
self.data['author'] = post.data['author']
|
16
|
+
self.data['duration'] = post.data['duration']
|
17
|
+
self.data['summary'] = post.data['summary']
|
18
|
+
self.data['explicit'] = post.data['explicit']
|
19
|
+
self.data['audio'] = post.data['audio']
|
20
|
+
self.data['chapters'] = post.data['chapters']
|
21
|
+
self.data['template'] = 'player_index'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Jekyll
|
2
|
+
class PodcastPlayerPageGenerator < Generator
|
3
|
+
safe true
|
4
|
+
|
5
|
+
def generate(site)
|
6
|
+
if site.layouts.key? 'player_index'
|
7
|
+
dir = site.config['players_dir'] || 'players'
|
8
|
+
site.posts.docs.each do |post|
|
9
|
+
site.pages << PodcastPlayerPage.new(site, site.source, File.join(dir, post.data['slug']), post)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Jekyll
|
2
|
+
class PodigeePlayerTag < Liquid::Tag
|
3
|
+
def playerconfig(context)
|
4
|
+
config = context.registers[:site].config
|
5
|
+
page = context.registers[:page]
|
6
|
+
|
7
|
+
audio = {}
|
8
|
+
download_url = config["download_url"] || config["url"] + "/episodes"
|
9
|
+
page["audio"].each { |key, value| audio[key] = download_url + "/" + value}
|
10
|
+
|
11
|
+
{ options: { theme: "default",
|
12
|
+
startPanel: "ChapterMarks" },
|
13
|
+
extensions: { ChapterMarks: {},
|
14
|
+
EpisodeInfo: {},
|
15
|
+
Playlist: {} },
|
16
|
+
title: options['title'],
|
17
|
+
episode: { media: audio,
|
18
|
+
coverUrl: config['url'] + (page["episode_cover"] || '/img/logo-360x360.png'),
|
19
|
+
title: page["title"],
|
20
|
+
subtitle: page["subtitle"],
|
21
|
+
url: config['url'] + page["url"],
|
22
|
+
description: page["description"],
|
23
|
+
chaptermarks: page["chapters"].map {|chapter| { start: chapter[0..12], title: chapter[13..255] }}
|
24
|
+
}
|
25
|
+
}.to_json
|
26
|
+
end
|
27
|
+
|
28
|
+
def render(context)
|
29
|
+
config = context.registers[:site].config
|
30
|
+
page = context.registers[:page]
|
31
|
+
return unless page["audio"]
|
32
|
+
return <<~HTML
|
33
|
+
<script>
|
34
|
+
window.playerConfiguration = #{playerconfig(context)}
|
35
|
+
</script>
|
36
|
+
<script class="podigee-podcast-player" data-configuration="playerConfiguration"
|
37
|
+
src="#{config["url"].split(":").first}://cdn.podigee.com/podcast-player/javascripts/podigee-podcast-player.js">
|
38
|
+
</script>
|
39
|
+
HTML
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
Liquid::Template.register_tag('podigee_player', Jekyll::PodigeePlayerTag)
|