@@ -, +, @@ - failed QA: removed default view for media tab, changed tab name to "Play audio" resp. "Play video". - put most of the code in separate module and access it from OPAC and staff client now, so the feature works in both - had to change sysprefs: HTML5MediaEnabled can be 'none', 'opac', 'staff' or 'both' - Import attached test data. [I chose media typ 'bk' because it's probably present on most systems. It's not appropriate for the data but that doesn't matter.] - Rebuild zebra -b -z - Go to Administration->System preferences->enhanced content->HTML5 Media and set HTML5MediaEnabled to an appropriate setting, save preferences. - Search the OPAC or staff client for 'bug 8377' - Get 4 results - Open detail pages for results. Observe working video (1-3) or audio (4) player on detail page. --- Koha/HTML5Media.pm | 227 ++++++++++++++++++++ catalogue/detail.pl | 7 + installer/data/mysql/sysprefs.sql | 2 + installer/data/mysql/updatedatabase.pl | 8 + .../admin/preferences/enhanced_content.pref | 14 ++ .../prog/en/modules/catalogue/detail.tt | 17 ++- koha-tmpl/opac-tmpl/prog/en/modules/opac-detail.tt | 21 ++ opac/opac-detail.pl | 8 + 8 files changed, 303 insertions(+), 1 deletions(-) create mode 100644 Koha/HTML5Media.pm --- a/Koha/HTML5Media.pm +++ a/Koha/HTML5Media.pm @@ -0,0 +1,227 @@ +package Koha::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 + +Koha::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; + --- a/catalogue/detail.pl +++ a/catalogue/detail.pl @@ -40,6 +40,7 @@ use C4::VirtualShelves; use C4::XSLT; use C4::Images; use Koha::DateUtils; +use Koha::HTML5Media; # use Smart::Comments; @@ -397,6 +398,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 = Koha::HTML5Media->gethtml5media($template,$record); +} + + # Get OPAC URL if (C4::Context->preference('OPACBaseURL')){ $template->param( OpacUrl => C4::Context->preference('OPACBaseURL') ); --- a/installer/data/mysql/sysprefs.sql +++ a/installer/data/mysql/sysprefs.sql @@ -375,3 +375,5 @@ INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ( INSERT INTO systempreferences (variable,value,explanation,type) VALUES('EnableBorrowerFiles','0','If enabled, allows librarians to upload and attach arbitrary files to a borrower record.','YesNo'); INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('UpdateTotalIssuesOnCirc','0','Whether to update the totalissues field in the biblio on each circ.',NULL,'YesNo'); INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('IntranetSlipPrinterJS','','Use this JavaScript for printing slips. Define at least function printThenClose(). For use e.g. with Firefox PlugIn jsPrintSetup, see http://jsprintsetup.mozdev.org/','','Free'); +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'); --- a/installer/data/mysql/updatedatabase.pl +++ a/installer/data/mysql/updatedatabase.pl @@ -5566,6 +5566,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) --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref @@ -336,3 +336,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 |). --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt @@ -262,7 +262,8 @@ function verify_images() { [% IF ( FRBRizeEditions ) %][% IF ( XISBNS ) %]
  • Editions
  • [% END %][% END %] [% IF ( AmazonSimilarItems ) %]
  • Related titles
  • [% END %] [% IF ( LocalCoverImages ) %][% IF ( localimages || CAN_user_tools_upload_local_cover_images ) %]
  • Images
  • [% END %][% END %] - +[% IF ( HTML5MediaEnabled ) %][% IF ( HTML5MediaSets ) %]
  • Play media
  • [% END %][% END %] +
    [% IF ( count ) %] @@ -566,6 +567,20 @@ function verify_images() {
    [% END %] +[% IF ( HTML5MediaEnabled ) %] +
    +

    + <[% HTML5MediaParent %][% HTML5MediaWidth %] controls preload=none> + [% FOREACH HTML5MediaSet IN HTML5MediaSets %] + <[% HTML5MediaSet.child %] src="[% HTML5MediaSet.srcblock %]"[% HTML5MediaSet.typeblock %] /> + [% END %] + [[% HTML5MediaParent %] tag not supported by your browser.] + +

    +
    +[% END %] + +
    --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-detail.tt +++ a/koha-tmpl/opac-tmpl/prog/en/modules/opac-detail.tt @@ -12,6 +12,7 @@ [% IF ( OpacStarRatings != 'disable' ) %] [% END %] +