Skip to content

Commit 55820a6

Browse files
author
Sanders Kleinfeld
committed
Merge pull request #143 from oreillymedia/audio-video
Handling for audio/video assets in EPUB OPF manifest.
2 parents 0a46b3e + 814eaaa commit 55820a6

File tree

3 files changed

+126
-0
lines changed

3 files changed

+126
-0
lines changed

htmlbook-xsl/mimetypes-by-file-extension.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,8 @@
1717
<mimetype file-extension="jpeg">image/jpeg</mimetype>
1818
<mimetype file-extension="tif">image/tiff</mimetype>
1919
<mimetype file-extension="tiff">image/tiff</mimetype>
20+
<mimetype file-extension="mp3">audio/mpeg</mimetype>
21+
<mimetype file-extension="aac">audio/mp4</mimetype>
22+
<mimetype file-extension="mp4">video/mp4</mimetype>
23+
<mimetype file-extension="ogg">video/ogg</mimetype>
2024
</mimetypes-by-file-extension>

htmlbook-xsl/opf.xsl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@
231231
</xsl:if>
232232
<!-- Add images to manifest -->
233233
<xsl:call-template name="manifest-images"/>
234+
<!-- Add any audio-video assets to manifest -->
235+
<xsl:call-template name="manifest-audio-video-assets"/>
234236
<!-- Add HTML documents to manifest -->
235237
<xsl:call-template name="manifest-html"/>
236238
</manifest>
@@ -475,6 +477,50 @@
475477
</xsl:if>
476478
</xsl:template>
477479

480+
<xsl:template name="manifest-audio-video-assets">
481+
<xsl:param name="asset-nodes" select="key('nodes-by-name', 'audio')|key('nodes-by-name', 'video')"/>
482+
<!-- Get the nodes from the asset-nodes list that have the @src attributes; either the audio/video tags themselves, or child source tags -->
483+
<xsl:variable name="asset-source-nodes" select="$asset-nodes[@src]|$asset-nodes/h:source[@src]"/>
484+
<xsl:for-each select="$asset-source-nodes">
485+
<!-- Generate an <item> for this asset only if it is the first instance of the asset with this @src attribute -->
486+
<xsl:if test="not(@src = (preceding::*[self::h:audio|self::h:video|self::h:source]/@src|
487+
ancestor::*[self::h:audio|self::h:video|self::h:source]/@src))">
488+
<xsl:variable name="filename" select="@src"/>
489+
<xsl:variable name="file-extension">
490+
<xsl:call-template name="get-extension-from-filename">
491+
<xsl:with-param name="filename" select="$filename"/>
492+
</xsl:call-template>
493+
</xsl:variable>
494+
<xsl:variable name="file-extension-corresponding-mimetype">
495+
<xsl:call-template name="get-mimetype-from-file-extension">
496+
<xsl:with-param name="file-extension" select="$file-extension"/>
497+
</xsl:call-template>
498+
</xsl:variable>
499+
<item>
500+
<xsl:attribute name="id">
501+
<xsl:apply-templates select="." mode="opf.id"/>
502+
</xsl:attribute>
503+
<xsl:attribute name="href">
504+
<xsl:value-of select="$filename"/>
505+
</xsl:attribute>
506+
<xsl:attribute name="media-type">
507+
<xsl:choose>
508+
<!-- When @type attribute is specified explicitly on element (only valid HTML5 to supply it on source,
509+
but if we're processing <audio> or <video>, and it happens to have a @type, we'll go ahead and use it -->
510+
<xsl:when test="@type">
511+
<xsl:value-of select="@type"/>
512+
</xsl:when>
513+
<!-- Otherwise, go ahead and infer mimetype from file extension -->
514+
<xsl:otherwise>
515+
<xsl:value-of select="$file-extension-corresponding-mimetype"/>
516+
</xsl:otherwise>
517+
</xsl:choose>
518+
</xsl:attribute>
519+
</item>
520+
</xsl:if>
521+
</xsl:for-each>
522+
</xsl:template>
523+
478524
<xsl:template name="manifest-images">
479525
<xsl:param name="img-nodes" select="key('nodes-by-name', 'img')"/>
480526
<xsl:for-each select="$img-nodes">

htmlbook-xsl/xspec/opf.xspec

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,88 @@ UbuntuMono-Regular.otf
149149
</x:scenario>
150150
</x:scenario>
151151

152+
<x:scenario label="When manifest-audio-video-assets is called">
153+
<x:call template="manifest-audio-video-assets">
154+
<x:param name="asset-nodes">
155+
<video src="dancing-puppy.mp4"/>
156+
<video src="dancing-kitty.ogg"/>
157+
<audio src="barking-puppy.aac"/>
158+
<audio src="purring-kitty.mp3"/>
159+
<!-- Intentional duplicate for testing to ensure no manifest redundancy -->
160+
<video src="dancing-puppy.mp4"/>
161+
</x:param>
162+
</x:call>
163+
<x:expect label="there should be an item for each audio/video src in the source files"
164+
test="every $asset in ('dancing-puppy.mp4', 'dancing-kitty.ogg', 'barking-puppy.aac', 'purring-kitty.mp3')
165+
satisfies (exists(//opf:item[@href=$asset]))"/>
166+
<x:expect label="audio/video items should have the correct mimetype inferred" test="(every $asset in (//opf:item[substring-after(@href, '.') = 'mp4'])
167+
satisfies ($asset[@media-type = 'video/mp4'])) and
168+
(every $asset in (//opf:item[substring-after(@href, '.') = 'ogg'])
169+
satisfies ($asset[@media-type = 'video/ogg'])) and
170+
(every $asset in (//opf:item[substring-after(@href, '.') = 'aac'])
171+
satisfies ($asset[@media-type = 'audio/mp4'])) and
172+
(every $asset in (//opf:item[substring-after(@href, '.') = 'mp3'])
173+
satisfies ($asset[@media-type = 'audio/mpeg']))"/>
174+
<x:expect label="and there should be only one item that references each asset file" test="not(exists(//@href[(. = preceding::opf:item/@href) or (. = following::opf:item/@href)]))"/>
175+
176+
<x:scenario label="on audio/video elements with source children">
177+
<x:call>
178+
<x:param name="asset-nodes">
179+
<video>
180+
<source src="dancing-puppy.mp4"/>
181+
<source src="dancing-puppy.ogg"/>
182+
</video>
183+
<audio>
184+
<source src="purring-kitty.aac"/>
185+
<source src="purring-kitty.mp3"/>
186+
</audio>
187+
<!-- Intentional duplicate for testing to ensure no manifest redundancy -->
188+
<video>
189+
<source src="dancing-puppy.mp4"/>
190+
</video>
191+
</x:param>
192+
</x:call>
193+
<x:expect label="there should be an item for each audio/video src in the source files"
194+
test="every $asset in ('dancing-puppy.mp4', 'dancing-puppy.ogg', 'purring-kitty.aac', 'purring-kitty.mp3')
195+
satisfies (exists(//opf:item[@href=$asset]))"/>
196+
<x:expect label="audio/video items should have the correct mimetype inferred" test="(every $asset in (//opf:item[substring-after(@href, '.') = 'mp4'])
197+
satisfies ($asset[@media-type = 'video/mp4'])) and
198+
(every $asset in (//opf:item[substring-after(@href, '.') = 'ogg'])
199+
satisfies ($asset[@media-type = 'video/ogg'])) and
200+
(every $asset in (//opf:item[substring-after(@href, '.') = 'aac'])
201+
satisfies ($asset[@media-type = 'audio/mp4'])) and
202+
(every $asset in (//opf:item[substring-after(@href, '.') = 'mp3'])
203+
satisfies ($asset[@media-type = 'audio/mpeg']))"/>
204+
<x:expect label="and there should be only one item that references each asset file" test="not(exists(//@href[(. = preceding::opf:item/@href) or (. = following::opf:item/@href)]))"/>
205+
</x:scenario>
206+
207+
<x:scenario label="on audio/video elements with @type attributes that don't match expected types that would be inferred from file extension">
208+
<x:call>
209+
<x:param name="asset-nodes">
210+
<video>
211+
<source src="dancing-puppy.mp4" type="video/ogg"/>
212+
</video>
213+
<audio>
214+
<source src="purring-kitty.mp3" type="audio/mp4"/>
215+
</audio>
216+
</x:param>
217+
</x:call>
218+
219+
<x:expect label="@type attributes should take precedence in determining item @media-type">
220+
<item xmlns="http://www.idpf.org/2007/opf" id="..." href="dancing-puppy.mp4" media-type="video/ogg"/>
221+
<item xmlns="http://www.idpf.org/2007/opf" id="..." href="purring-kitty.mp3" media-type="audio/mp4"/>
222+
</x:expect>
223+
</x:scenario>
224+
225+
</x:scenario>
226+
152227
<x:scenario label="When manifest-images is called">
153228
<x:call template="manifest-images">
154229
<x:param name="img-nodes">
155230
<img src="puppy.jpg"/>
156231
<img src="kitty.png"/>
157232
<img src="birdie.gif"/>
233+
<!-- Intentional duplicate for testing to ensure no manifest redundancy -->
158234
<img src="puppy.jpg"/>
159235
</x:param>
160236
</x:call>

0 commit comments

Comments
 (0)