Bug 8377 [ENH] Show HTML5 video/ audio for media files in OPAC and staff client
This enhancement uses information from MARC field 856 to generate the appropriate HTML5 code to embed am media player for the file(s) in a tab in the OPAC and staff client detail view. This patch supports the HTML5 <audio> and <video> element. Additionally it gives basic support for the <track> element. This element is not supported very well by recent browsers. Please consider the patch working when you get working video or audio. Rebased to Master 22.11.2012 Signed-off-by: Chris Cormack <chrisc@catalyst.net.nz> Signed-off-by: Jonathan Druart <jonathan.druart@biblibre.com> Signed-off-by: Jared Camins-Esakov <jcamins@cpbibliography.com>
This commit is contained in:
parent
37bd0c8d7e
commit
33aa6ec2fd
8 changed files with 298 additions and 1 deletions
226
C4/HTML5Media.pm
Normal file
226
C4/HTML5Media.pm
Normal file
|
@ -0,0 +1,226 @@
|
|||
package C4::HTML5Media;
|
||||
|
||||
# Copyright 2012 Mirko Tietgen
|
||||
#
|
||||
# This file is part of Koha.
|
||||
#
|
||||
# Koha is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with Koha; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use C4::Context;
|
||||
use MARC::Field;
|
||||
|
||||
|
||||
=head1 HTML5Media
|
||||
|
||||
C4::HTML5Media
|
||||
|
||||
=head1 Description
|
||||
|
||||
This module gets the relevant data from field 856 (MARC21/UNIMARC) to create a HTML5 audio or video element containing the file(s) catalogued in 856.
|
||||
|
||||
=cut
|
||||
|
||||
=head2 gethtml5media
|
||||
|
||||
Get all relevant data from field 856. Takes $template and $record in the subroutine call, sets appropriate params.
|
||||
|
||||
=cut
|
||||
|
||||
sub gethtml5media {
|
||||
my $self = shift;
|
||||
my $template = shift;
|
||||
my $record = shift;
|
||||
my @HTML5Media_sets = ();
|
||||
my @HTML5Media_fields = $record->field(856);
|
||||
my $HTML5MediaParent;
|
||||
my $HTML5MediaWidth;
|
||||
my @HTML5MediaExtensions = split( /\|/, C4::Context->preference("HTML5MediaExtensions") );
|
||||
my $marcflavour = C4::Context->preference("marcflavour");
|
||||
foreach my $HTML5Media_field (@HTML5Media_fields) {
|
||||
my %HTML5Media;
|
||||
# protocol
|
||||
if ( $HTML5Media_field->indicator(1) eq '1' ) {
|
||||
$HTML5Media{protocol} = 'ftp';
|
||||
}
|
||||
elsif ( $HTML5Media_field->indicator(1) eq '4' ) {
|
||||
$HTML5Media{protocol} = 'http';
|
||||
}
|
||||
elsif ( $HTML5Media_field->indicator(1) eq '7' ) {
|
||||
if ($marcflavour eq 'MARC21' || $marcflavour eq 'NORMARC') {
|
||||
$HTML5Media{protocol} = $HTML5Media_field->subfield('2');
|
||||
}
|
||||
elsif ($marcflavour eq 'UNIMARC') {
|
||||
$HTML5Media{protocol} = $HTML5Media_field->subfield('y');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$HTML5Media{protocol} = 'http';
|
||||
}
|
||||
# user
|
||||
if ( $HTML5Media_field->subfield('l') ) {
|
||||
$HTML5Media{username} = $HTML5Media_field->subfield('l'); # yes, that is arbitrary if h and l are not the same. originally i flipped a coin in that case.
|
||||
}
|
||||
elsif ( $HTML5Media_field->subfield('h') ) {
|
||||
$HTML5Media{username} = $HTML5Media_field->subfield('h');
|
||||
}
|
||||
# user/pass
|
||||
if ( $HTML5Media{username} && $HTML5Media_field->subfield('k') ) {
|
||||
$HTML5Media{loginblock} = $HTML5Media{username} . ':' . $HTML5Media_field->subfield('k') . '@';
|
||||
}
|
||||
elsif ( $HTML5Media{username} ) {
|
||||
$HTML5Media{loginblock} = $HTML5Media{username} . '@';
|
||||
}
|
||||
else {
|
||||
$HTML5Media{loginblock} = '';
|
||||
}
|
||||
# port
|
||||
if ( $HTML5Media_field->subfield('p') ) {
|
||||
$HTML5Media{portblock} = ':' . $HTML5Media_field->subfield('k');
|
||||
}
|
||||
else {
|
||||
$HTML5Media{portblock} = '';
|
||||
}
|
||||
# src
|
||||
if ( $HTML5Media_field->subfield('u') ) {
|
||||
$HTML5Media{srcblock} = $HTML5Media_field->subfield('u');
|
||||
}
|
||||
elsif ( $HTML5Media_field->subfield('a') && $HTML5Media_field->subfield('d') && $HTML5Media_field->subfield('f') ) {
|
||||
$HTML5Media{host} = $HTML5Media_field->subfield('a');
|
||||
$HTML5Media{host} =~ s/(^\/|\/$)//g;
|
||||
$HTML5Media{path} = $HTML5Media_field->subfield('d');
|
||||
$HTML5Media{path} =~ s/(^\/|\/$)//g;
|
||||
$HTML5Media{file} = $HTML5Media_field->subfield('f');
|
||||
$HTML5Media{srcblock} = $HTML5Media{protocol} . '://' . $HTML5Media{loginblock} . $HTML5Media{host} . $HTML5Media{portblock} . '/' . $HTML5Media{path} . '/' . $HTML5Media{file};
|
||||
}
|
||||
else {
|
||||
next; # no file to play
|
||||
}
|
||||
# extension
|
||||
$HTML5Media{extension} = ($HTML5Media{srcblock} =~ m/([^.]+)$/)[0];
|
||||
if ( !grep /$HTML5Media{extension}/, @HTML5MediaExtensions ) {
|
||||
next; # not a specified media file
|
||||
}
|
||||
# mime
|
||||
if ( $HTML5Media_field->subfield('c') ) {
|
||||
$HTML5Media{codecs} = $HTML5Media_field->subfield('c');
|
||||
}
|
||||
### from subfield q…
|
||||
if ( $HTML5Media_field->subfield('q') ) {
|
||||
$HTML5Media{mime} = $HTML5Media_field->subfield('q');
|
||||
}
|
||||
### …or from file extension and codecs…
|
||||
elsif ( $HTML5Media{codecs} ) {
|
||||
if ( $HTML5Media{codecs} =~ /theora.*vorbis/ ) {
|
||||
$HTML5Media{mime} = 'video/ogg';
|
||||
}
|
||||
elsif ( $HTML5Media{codecs} =~ /vp8.*vorbis/ ) {
|
||||
$HTML5Media{mime} = 'video/webm';
|
||||
}
|
||||
elsif ( ($HTML5Media{codecs} =~ /^vorbis$/) && ($HTML5Media{extension} eq 'ogg') ) {
|
||||
$HTML5Media{mime} = 'audio/ogg';
|
||||
}
|
||||
elsif ( ($HTML5Media{codecs} =~ /^vorbis$/) && ($HTML5Media{extension} eq 'webm') ) {
|
||||
$HTML5Media{mime} = 'audio/webm';
|
||||
}
|
||||
}
|
||||
### …or just from file extension
|
||||
else {
|
||||
if ( $HTML5Media{extension} eq 'ogv' ) {
|
||||
$HTML5Media{mime} = 'video/ogg';
|
||||
$HTML5Media{codecs} = 'theora,vorbis';
|
||||
}
|
||||
if ( $HTML5Media{extension} eq 'oga' ) {
|
||||
$HTML5Media{mime} = 'audio/ogg';
|
||||
$HTML5Media{codecs} = 'vorbis';
|
||||
}
|
||||
elsif ( $HTML5Media{extension} eq 'spx' ) {
|
||||
$HTML5Media{mime} = 'audio/ogg';
|
||||
$HTML5Media{codecs} = 'speex';
|
||||
}
|
||||
elsif ( $HTML5Media{extension} eq 'opus' ) {
|
||||
$HTML5Media{mime} = 'audio/ogg';
|
||||
$HTML5Media{codecs} = 'opus';
|
||||
}
|
||||
elsif ( $HTML5Media{extension} eq 'vtt' ) {
|
||||
$HTML5Media{mime} = 'text/vtt';
|
||||
}
|
||||
}
|
||||
# codecs
|
||||
if ( $HTML5Media{codecs} ) {
|
||||
$HTML5Media{codecblock} = '; codecs="' . $HTML5Media{codecs} . '"';
|
||||
}
|
||||
else {
|
||||
$HTML5Media{codecblock} = '';
|
||||
}
|
||||
# type
|
||||
if ( $HTML5Media{mime} ) {
|
||||
$HTML5Media{typeblock} = ' type=\'' . $HTML5Media{mime} . $HTML5Media{codecblock} . '\'';
|
||||
}
|
||||
else {
|
||||
$HTML5Media{typeblock} = '';
|
||||
}
|
||||
# element
|
||||
if ( $HTML5Media{mime} =~ /audio/ ) {
|
||||
$HTML5Media{type} = 'audio';
|
||||
}
|
||||
elsif ( $HTML5Media{mime} =~ /video/ ) {
|
||||
$HTML5Media{type} = 'video';
|
||||
}
|
||||
elsif ( $HTML5Media{mime} =~ /text/ ) {
|
||||
$HTML5Media{type} = 'track';
|
||||
}
|
||||
# push
|
||||
if ( $HTML5Media{srcblock} && $HTML5Media{type} ) {
|
||||
push (@HTML5Media_sets, \%HTML5Media);
|
||||
}
|
||||
}
|
||||
# parent element
|
||||
for my $i ( 0 .. $#HTML5Media_sets ) {
|
||||
if ( ($HTML5Media_sets[$i]{mime}) && ($HTML5Media_sets[$i]{mime} =~ /audio/) ) {
|
||||
if ( $HTML5MediaParent ne 'video' ) {
|
||||
$HTML5MediaParent = 'audio';
|
||||
$HTML5MediaWidth = '';
|
||||
}
|
||||
}
|
||||
elsif ( ($HTML5Media_sets[$i]{mime}) && ($HTML5Media_sets[$i]{mime} =~ /video/) ) {
|
||||
$HTML5MediaParent = 'video';
|
||||
$HTML5MediaWidth = ' width="480"';
|
||||
}
|
||||
}
|
||||
# child element
|
||||
for my $j ( 0 .. $#HTML5Media_sets ) {
|
||||
if ( ($HTML5Media_sets[$j]{type}) && ( ($HTML5Media_sets[$j]{type} eq 'video') || ($HTML5Media_sets[$j]{type} eq 'audio') ) ) {
|
||||
if ( $HTML5Media_sets[$j]{type} eq $HTML5MediaParent ) {
|
||||
$HTML5Media_sets[$j]{child} = 'source';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$HTML5Media_sets[$j]{child} = $HTML5Media_sets[$j]{type};
|
||||
}
|
||||
}
|
||||
# template parameters
|
||||
if ( (scalar(@HTML5Media_sets) > 0) && ($HTML5MediaParent) ) {
|
||||
$template->param(
|
||||
HTML5MediaEnabled => 1,
|
||||
HTML5MediaSets => \@HTML5Media_sets,
|
||||
HTML5MediaParent => $HTML5MediaParent,
|
||||
HTML5MediaWidth => $HTML5MediaWidth);
|
||||
}
|
||||
return $template;
|
||||
}
|
||||
|
||||
1;
|
|
@ -40,6 +40,7 @@ use C4::VirtualShelves;
|
|||
use C4::XSLT;
|
||||
use C4::Images;
|
||||
use Koha::DateUtils;
|
||||
use C4::HTML5Media;
|
||||
|
||||
# use Smart::Comments;
|
||||
|
||||
|
@ -379,6 +380,12 @@ if ( C4::Context->preference("LocalCoverImages") == 1 ) {
|
|||
$template->{VARS}->{localimages} = \@images;
|
||||
}
|
||||
|
||||
# HTML5 Media
|
||||
if ( (C4::Context->preference("HTML5MediaEnabled") eq 'staff') || (C4::Context->preference("HTML5MediaEnabled") eq 'both') ) {
|
||||
$template = C4::HTML5Media->gethtml5media($template,$record);
|
||||
}
|
||||
|
||||
|
||||
# Get OPAC URL
|
||||
if (C4::Context->preference('OPACBaseURL')){
|
||||
$template->param( OpacUrl => C4::Context->preference('OPACBaseURL') );
|
||||
|
|
|
@ -400,3 +400,5 @@ INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('
|
|||
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacSeparateHoldings', '0', 'Separate current branch holdings from other holdings (OPAC)', NULL, 'YesNo');
|
||||
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacSeparateHoldingsBranch', 'homebranch', 'Branch used to separate holdings (OPAC)', 'homebranch|holdingbranch', 'Choice');
|
||||
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('RenewalSendNotice','0', NULL, '', 'YesNo');
|
||||
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('HTML5MediaEnabled','not','Show a tab with a HTML5 media player for files catalogued in field 856','not|opac|staff|both','Choice');
|
||||
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('HTML5MediaExtensions','webm|ogg|ogv|oga|vtt','Media file extensions','','free');
|
||||
|
|
|
@ -6309,6 +6309,14 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
|
|||
SetVersion($DBversion);
|
||||
}
|
||||
|
||||
$DBversion = 'XXX';
|
||||
if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
|
||||
$dbh->do("INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('HTML5MediaEnabled','not','Show a HTML5 media player in a tab on opac-detail.pl for media files catalogued in field 856.','not|opac|staff|both','Choice');");
|
||||
$dbh->do("INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('HTML5MediaExtensions','webm|ogg|ogv|oga|vtt','Media file extensions','','free');");
|
||||
print "Upgrade to $DBversion done (Add HTML5MediaEnabled and HTML5MediaExtensions sysprefs)\n";
|
||||
SetVersion ($DBversion);
|
||||
}
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
=head2 TableExists($table)
|
||||
|
|
|
@ -286,3 +286,17 @@ Enhanced Content:
|
|||
yes: Allow
|
||||
no: "Don't allow"
|
||||
- multiple images to be attached to each bibliographic record.
|
||||
HTML5 Media:
|
||||
-
|
||||
- Show a tab with a HTML5 media player for files catalogued in field 856
|
||||
- pref: HTML5MediaEnabled
|
||||
choices:
|
||||
not: "not at all."
|
||||
opac: "in the OPAC."
|
||||
staff: "in the staff client."
|
||||
both: "in OPAC and staff client."
|
||||
-
|
||||
- Media file extensions
|
||||
- pref: HTML5MediaExtensions
|
||||
class: multi
|
||||
- (separated with |).
|
||||
|
|
|
@ -272,7 +272,8 @@ function verify_images() {
|
|||
[% IF ( subscriptionsnumber ) %]<li><a href="#subscriptions">Subscriptions</a></li>[% END %]
|
||||
[% IF ( FRBRizeEditions ) %][% IF ( XISBNS ) %]<li><a href="#editions">Editions</a></li>[% END %][% END %]
|
||||
[% IF ( LocalCoverImages ) %][% IF ( localimages || CAN_user_tools_upload_local_cover_images ) %]<li><a href="#images">Images</a></li>[% END %][% END %]
|
||||
</ul>
|
||||
[% IF ( HTML5MediaEnabled ) %][% IF ( HTML5MediaSets ) %]<li><a href="#html5media">Play media</a></li>[% END %][% END %]
|
||||
</ul>
|
||||
|
||||
[% BLOCK items_table %]
|
||||
<table>
|
||||
|
@ -587,6 +588,20 @@ function verify_images() {
|
|||
</div>
|
||||
[% END %]
|
||||
|
||||
[% IF ( HTML5MediaEnabled ) %]
|
||||
<div id="html5media">
|
||||
<p>
|
||||
<[% HTML5MediaParent %][% HTML5MediaWidth %] controls preload=none>
|
||||
[% FOREACH HTML5MediaSet IN HTML5MediaSets %]
|
||||
<[% HTML5MediaSet.child %] src="[% HTML5MediaSet.srcblock %]"[% HTML5MediaSet.typeblock %] />
|
||||
[% END %]
|
||||
[[% HTML5MediaParent %] tag not supported by your browser.]
|
||||
</[% HTML5MediaParent %]>
|
||||
</p>
|
||||
</div>
|
||||
[% END %]
|
||||
|
||||
|
||||
</div><!-- /bibliodetails -->
|
||||
|
||||
<div class="yui-g" id="export" style="margin-top: 1em;">
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="/opac-tmpl/prog/en/css/jquery.rating.css" />[% END %]
|
||||
|
||||
[% IF ( OpacHighlightedWords ) %]<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.highlight-3.js"></script>[% END %]
|
||||
|
||||
<script type="text/JavaScript" language="JavaScript">
|
||||
//<![CDATA[
|
||||
|
||||
|
@ -718,6 +719,11 @@ YAHOO.util.Event.onContentReady("furtherm", function () {
|
|||
[% IF ( OPACLocalCoverImages && localimages.size ) %]
|
||||
<li id="tab_images"><a href="#images">Images</a></li>
|
||||
[% END %]
|
||||
|
||||
[% IF ( HTML5MediaEnabled ) %][% IF ( HTML5MediaSets ) %]
|
||||
<li id="tab_html5media"><a href="#html5media">Play media</a></li>
|
||||
[% END %][% END %]
|
||||
|
||||
</ul>
|
||||
|
||||
[% IF ( serialcollection ) %]
|
||||
|
@ -1053,6 +1059,19 @@ YAHOO.util.Event.onContentReady("furtherm", function () {
|
|||
</table>
|
||||
</div>[% END %][% END %]
|
||||
|
||||
[% IF ( HTML5MediaEnabled ) %]
|
||||
<div id="html5media">
|
||||
<p>
|
||||
<[% HTML5MediaParent %][% HTML5MediaWidth %] controls preload=none>
|
||||
[% FOREACH HTML5MediaSet IN HTML5MediaSets %]
|
||||
<[% HTML5MediaSet.child %] src="[% HTML5MediaSet.srcblock %]"[% HTML5MediaSet.typeblock %] />
|
||||
[% END %]
|
||||
[[% HTML5MediaParent %] tag not supported by your browser.]
|
||||
</[% HTML5MediaParent %]>
|
||||
</p>
|
||||
</div>
|
||||
[% END %]
|
||||
|
||||
[% IF ( OPACLocalCoverImages && localimages.size ) %]
|
||||
<div id="images">
|
||||
<p>Click on an image to view it in the image viewer</p>
|
||||
|
|
|
@ -49,6 +49,7 @@ use MARC::Field;
|
|||
use List::MoreUtils qw/any none/;
|
||||
use C4::Images;
|
||||
use Koha::DateUtils;
|
||||
use C4::HTML5Media;
|
||||
|
||||
BEGIN {
|
||||
if (C4::Context->preference('BakerTaylorEnabled')) {
|
||||
|
@ -776,6 +777,11 @@ if (C4::Context->preference("OPACLocalCoverImages")){
|
|||
$template->param(OPACLocalCoverImages => 1);
|
||||
}
|
||||
|
||||
# HTML5 Media
|
||||
if ( (C4::Context->preference("HTML5MediaEnabled") eq 'opac') || (C4::Context->preference("HTML5MediaEnabled") eq 'both') ) {
|
||||
$template = C4::HTML5Media->gethtml5media($template,$record);
|
||||
}
|
||||
|
||||
my $syndetics_elements;
|
||||
|
||||
if ( C4::Context->preference("SyndeticsEnabled") ) {
|
||||
|
|
Loading…
Reference in a new issue