Commit 46a59377 authored by Laurent's avatar Laurent

dev #86172 On author page view, Bokeh now fetch Wikidata, BNF, ISNI and YouTube…

dev #86172 On author page view, Bokeh now fetch Wikidata, BNF, ISNI and YouTube channel identifiers.

On author page view, Bokeh adds INA interviews and first three videos of author's YouTube channel when available.

Improve AJAXification of thumbnails rendering for records
parent 066ea25f
Pipeline #6220 canceled with stage
in 32 seconds
- ticket #86172 : Enrichissements : import des identifiants Wikidata, BNF Ark, ISNI et YouTube dans la codification des auteurs. Enrichissement YouTube et INA des pages auteur.
\ No newline at end of file
......@@ -49,6 +49,9 @@ class Admin_RecordsController extends ZendAfi_Controller_Action {
public function thumbnailAction() {
if (!$record = Class_Notice::find((int)$this->_getParam('id')))
return $this->_redirectClose($this->_getReferer());
$this->view->titre = $this->_('Modifier la vignette');
$form = new ZendAfi_Form_VignetteNotice(['action' => $this->view->url(['module' => 'admin',
......@@ -67,7 +70,7 @@ class Admin_RecordsController extends ZendAfi_Controller_Action {
}
$this->view->form = $form;
$this->view->url_vignette = Class_Notice::find((int)$this->_getParam('id'))->fetchUrlVignette();
$this->view->url_vignette = $record->fetchUrlLocalVignette();
}
......
......@@ -24,11 +24,51 @@ class AuthorController extends ZendAfi_Controller_Action {
if (!$author = $this->_findAuthor())
throw new Zend_Controller_Action_Exception($this->view->_('Désolé, cette page n\'existe pas'), 404);
$this->_addInspectorGadget($author);
$this->view->author_description = new Class_CodifAuteur_Description($author);
$this->view->titre = $this->view->_('Auteur');
}
public function renderYoutubeChannelAction() {
session_write_close();
$this->getHelper('ViewRenderer')->setNoRender();
if (!$author = $this->_findAuthor())
return;
$items = [];
foreach((new Class_WebService_Youtube())
->videosOfChannel($author->getYoutubeChannelId()) as $video) {
$items[] = $this->view->tag('div',
$this->view->tag('iframe', '', ['src' => $video->getEmbedUrl()])
.
$this->view->tag('h3', $video->getTitle()));
if (3 == count($items))
break;
}
$html = $this->view->tag('div', implode($items));
$this->_response->setHeader('Content-Type', 'text/html;charset=utf-8');
$this->_response->setBody($html);
}
protected function _addInspectorGadget($author) {
if (!$ig = Zend_Controller_Front::getInstance()
->getPlugin('ZendAfi_Controller_Plugin_InspectorGadget'))
return;
if(!$ig->isEnabled())
return;
$ig->addButton(new Class_Entity(['Label' => $this->_('Auteur Bokeh'),
'Content' => $this->view->renderAuthorMetadata($author)]));
}
protected function _findAuthor() {
if ($id = (int)$this->_getParam('id'))
return Class_CodifAuteur::find($id);
......
......@@ -343,6 +343,7 @@ class NoticeAjaxController extends ZendAfi_Controller_Action {
public function videosAction() {
$width = $this->_getParam('width', 500) - 8; //8px du skin de l'INA sur lequel on n'a pas la main
$height = (int)($width * 4/5);
$author = $this->_getParam('author', $this->notice->getAuteurPrincipal());
if ($num_video = $this->_getParam("num_video", 0)) {
$num_video = $num_video-1;
......@@ -352,8 +353,8 @@ class NoticeAjaxController extends ZendAfi_Controller_Action {
}
unset($_SESSION["video_interview"]);
$notice=$this->notice->getNotice("JA");
if(!trim($notice["A"])) {
if(!$author) {
$html=$this->notice_html->getNonTrouve($this->view->_("Cette notice n'a pas d'auteur."),true);
$this->_sendResponseWithScripts($html);
return;
......@@ -361,10 +362,8 @@ class NoticeAjaxController extends ZendAfi_Controller_Action {
if($this->service_afi > "") {
$args = ['titre' => $notice['J'],
'auteur' => $notice['A'],
'width' => $width,
'height' => $height];
$args = ['auteur' => $author,
'width' => $width];
$data = Class_WebService_AllServices::runServiceAfiInterviews($args);
$source = $data["source"];
$videos = $data["videos"];
......
......@@ -491,6 +491,7 @@ class RechercheController extends ZendAfi_Controller_Action {
$viewRenderer->setNoRender();
session_write_close();
$this->_response->setHeader('Content-Type', 'image/png');
$record = Class_Notice::find((int)$this->_getParam('id'));
(new Class_WebService_Vignette())
->renderThumbnail($record->getId(),
......
......@@ -290,6 +290,6 @@ class RssController extends Zend_Controller_Action
$notice->getAuteurPrincipal(),
$notice->getEditeur(),
$notice->getAnnee(),
$this->view->absoluteUrl($notice->fetchUrlVignette()));
$this->view->absoluteUrl($notice->fetchUrlLocalVignette()));
}
}
......@@ -9,7 +9,7 @@ Class_ScriptLoader::getInstance()
$html = '';
foreach($this->notices as $notice)
$html .= $this->tagAnchor($this->urlNotice($notice, $this->preferences, null, true),
$this->tagImg($this->absoluteUrl($notice->fetchUrlVignette()),
$this->tagImg($this->absoluteUrl($notice->fetchUrlLocalVignette()),
['title' => $notice->getTitrePrincipal()]),
['target' => '_parent']);
......
......@@ -8,7 +8,7 @@ Class_ScriptLoader::getInstance()
$records_html = '';
foreach($this->notices as $notice) {
$onclick = "window.parent.location='". $this->urlNotice($notice, $this->preferences, null, true) . "';";
$records_html .= $this->tagImg($this->absoluteUrl($notice->fetchUrlVignette(true)),
$records_html .= $this->tagImg($this->absoluteUrl($notice->fetchUrlLocalVignette()),
['title' => $notice->getTitrePrincipal(),
'onclick' => $onclick,
'width' => $this->preferences["op_largeur_img"] . 'px',
......
......@@ -49,7 +49,7 @@ function mycarousel_initCallback(carousel) {
$lis = '';
foreach($this->notices as $notice) {
$img = $this->tagImg($this->absoluteUrl($notice->fetchUrlVignette()),
$img = $this->tagImg($this->absoluteUrl($notice->fetchUrlLocalVignette()),
['title' => $notice->getTitrePrincipal(),
'width' => $this->preferences["op_largeur_img"],
'height' => $this->preferences["op_hauteur_img"]]);
......
<?php
$lis = '';
foreach($this->records as $record) {
$img = $this->tagImg($this->absoluteUrl($record->fetchUrlVignette()),
$img = $this->tagImg($this->absoluteUrl($record->fetchUrlLocalVignette()),
['title' => $record->getTitrePrincipal(),
'width' => $this->preferences["op_largeur_img"],
'height' => $this->preferences["op_hauteur_img"]]);
......
......@@ -15,7 +15,7 @@ Class_ScriptLoader::getInstance()
$anchors = '';
foreach($this->notices as $notice) {
$img = $this->tagImg($this->absoluteUrl($notice->fetchUrlVignette()),
$img = $this->tagImg($this->absoluteUrl($notice->fetchUrlLocalVignette()),
['border' => '0',
'width' => $this->preferences['op_largeur_img'],
'height' => $this->preferences['op_hauteur_img'],
......
......@@ -14,7 +14,7 @@ if(!$hauteur) $hauteur=110;
$images = '';
foreach($this->notices as $notice){
$images .= $this->tagAnchor($this->urlNotice($notice, $this->preferences, null, true),
$this->tagImg($this->absoluteUrl($notice->fetchUrlVignette()),
$this->tagImg($this->absoluteUrl($notice->fetchUrlLocalVignette()),
['alt' => $this->_('vignette notice') . ' ' . $notice->getTitrePrincipal(),
'title' => $notice->getTitrePrincipal(),
'width' => $largeur,
......
<table border="0" cellpadding="3" cellspacing="1">
<tr>
<td rowspan="2" valign="top">
<img src="<?php print($this->notice->fetchUrlVignette()); ?>" width="90px" onclick="<?php print($this->notice->fetchUrlImage());?> " style="cursor:pointer"/>
<img src="<?php print($this->notice->fetchUrlLocalVignette()); ?>" width="90px" onclick="<?php print($this->notice->fetchUrlImage());?> " style="cursor:pointer"/>
</td>
<td valign="top" width="550px">
<table width="100%">
......
......@@ -4,7 +4,7 @@ echo $this->toolbar($this->_("Recherche"),
<ul data-role="listview" data-inset="true" class="doctype_<?php echo $this->notice->getTypeDoc();?>">
<li data-theme="c">
<img src="<?php echo $this->notice->fetchUrlVignette();?>">
<img src="<?php echo $this->notice->fetchUrlLocalVignette();?>">
<h3><?php echo $this->iconeSupport($this->notice->getTypeDoc()) . $this->notice->getTitrePrincipal() ;?></h3>
<p class="serie">
<?php
......
<?php
$adapter = Zend_Db_Table_Abstract::getDefaultAdapter();
try {
$adapter->query('alter table codif_auteur add column wikidata_id varchar(255)');
$adapter->query('alter table codif_auteur add column youtube_channel_id varchar(255)');
$adapter->query('alter table codif_auteur add column isni varchar(255)');
$adapter->query('alter table codif_auteur add column ark varchar(255)');
$adapter->query('alter table codif_auteur add index wikidata_id (wikidata_id)');
} catch(Exception $e) {}
......@@ -435,7 +435,7 @@ class Class_AvisNotice extends Storm_Model_Abstract {
public function getUrlVignette() {
if (!$notice = $this->getFirstNotice())
return '';
return $notice->fetchUrlVignette();
return $notice->fetchUrlLocalVignette();
}
......
......@@ -118,7 +118,11 @@ class Class_CodifAuteur extends Storm_Model_Abstract {
$_default_attribute_values = ['libelle' => '',
'mots_renvois' => '',
'id_bnf' => '',
'date_creation' => ''];
'date_creation' => '',
'wikidata_id' => '',
'youtube_channel_id' => '',
'isni' => '',
'ark' => ''];
public function getCategorie() {
return;
......
......@@ -34,6 +34,11 @@ class Class_CodifAuteur_Description {
}
public function getId() {
return $this->_author->getId();
}
public function getLabel() {
return $this->_author->getLibelle();
}
......@@ -61,6 +66,11 @@ class Class_CodifAuteur_Description {
}
public function getYoutubeChannelId() {
return $this->_author->getYoutubeChannelId();
}
public function getRecords() {
if (isset($this->_all_records))
return $this->_all_records;
......@@ -93,6 +103,14 @@ class Class_CodifAuteur_Description {
$this->getRecords(),
$this->getAssociatedAuthors());
$author_attribs = array_intersect_key($data, ['wikidata_id' => '',
'youtube_channel_id' => '',
'ark' => '',
'isni' => '']);
$this->_author
->updateAttributes($author_attribs)
->save();
if ($biography = $data['biographie']) {
$biography = $this->_enrichBiographyWithRecords($biography,
$this->getRecords(),
......@@ -157,7 +175,9 @@ class Class_CodifAuteur_Description {
$associated_authors = [];
foreach($facets as $code => $count) {
$id = substr($code, 1);
$associated_authors[$id] = ['author' => Class_CodifAuteur::find($id),
if (!$collaborator = Class_CodifAuteur::find($id))
continue;
$associated_authors[$id] = ['author' => $collaborator,
'occurences' => $count];
}
......
......@@ -1579,7 +1579,7 @@ class Class_Notice extends Storm_Model_Abstract {
$visitor->visitTypeDoc($this->getTypeDoc());
$visitor->visitNatureDoc($this->getNatureDocs());
if ($this->hasVignette()) {
$visitor->visitVignette(Class_Url::absolute($this->fetchUrlVignette()));
$visitor->visitVignette(Class_Url::absolute($this->fetchUrlLocalVignette()));
$visitor->visitImage(Class_Url::absolute($this->fetchUrlImage()));
}
$visitor->visitIsbn($this->getIsbn());
......
......@@ -32,11 +32,7 @@ class Class_Notice_Thumbnail {
if ($this->_shouldRetry($record, $record->getUrlVignette()))
return $this->_service->getAjaxUrl($record);
$url = $record->getUrlVignette();
return $this->_service->isNoData($url)
? $this->_rawThumbnailUrl($record)
: $url;
return $record->getUrlVignette();
}
......
......@@ -89,11 +89,7 @@ class Class_WebService_Vignette extends Class_WebService_Abstract {
static function renderThumbnail($id_notice,$titre,$type_doc) {
$image = static::createImage($titre,
$width=100,
$height=90,
$type_doc);
$image = static::createImage($titre, 300, 400, $type_doc);
imagepng($image);
}
......@@ -114,7 +110,7 @@ class Class_WebService_Vignette extends Class_WebService_Abstract {
public static function createImage($titre, $width=100, $height=110, $type_doc) {
$image = imagecreatetruecolor($width,$height);
$image = imagecreatetruecolor($width, $height);
// Couleur de fond
$fond = imagecolorallocate($image, 255, 255, 255);
......@@ -122,7 +118,7 @@ class Class_WebService_Vignette extends Class_WebService_Abstract {
// Titre
if($titre > "")
$image = static::writeText($titre,$image);
$image = static::writeText($titre, $image);
return $image;
}
......@@ -133,18 +129,17 @@ class Class_WebService_Vignette extends Class_WebService_Abstract {
$texte=explode(";", $texte);
// Parametres
$font = 3;
$couleur = imagecolorallocate($image_obj, 102, 102, 102);
$pos_x=0;
$pos_y=2;
$hauteur=15;
$largeur=100;
$pos_x=20;
$pos_y=50;
$hauteur=50;
$largeur=200;
// Afficher
foreach($texte as $ligne) {
$pos_x=($largeur/2)-(strlen($ligne) * 3.5);
imagestring($image_obj,$font, $pos_x, $pos_y, $ligne, $couleur);
$pos_y+=$hauteur;
imagettftext($image_obj, 30, 0, $pos_x, $pos_y, $couleur, PATH_FONTS . 'Vera.ttf', trim($ligne));
$pos_y += $hauteur;
}
return $image_obj;
......
<?php
/**
* Copyright (c) 2012-2018, Agence Française Informatique (AFI). All rights reserved.
*
* BOKEH is free software; you can redistribute it and/or modify
* it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
* the Free Software Foundation.
*
* There are special exceptions to the terms and conditions of the AGPL as it
* is applied to this software (see README file).
*
* BOKEH 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 AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
* along with BOKEH; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Class_WebService_Youtube extends Class_WebService_Abstract {
public function videosOfChannel($channel) {
if (!$channel)
return new Storm_Collection([]);
$rss = $this->httpGet('https://www.youtube.com/feeds/videos.xml?'
. http_build_query(['channel_id' => $channel]));
try {
$xml = new SimpleXMLElement($rss);
} catch(Exception $e) {
return new Storm_Collection([]);
}
$items = [];
foreach($xml->entry as $entry)
$items[] = (new Class_WebService_Youtube_Video())
->setId(str_replace('yt:video:', '', $entry->id))
->setTitle($entry->title);
return new Storm_Collection($items);
}
}
class Class_WebService_Youtube_Video extends Class_Entity {
public function getEmbedUrl() {
return 'https://www.youtube.com/embed/' . $this->getId();
}
}
......@@ -191,7 +191,10 @@ create: function(event, ui) { if (ui.panel.hasClass(\'ig-accordion\')) ui.panel.
public function log() {
$httpClient = Class_HttpClientFactory::getInstance()->getLastHttpClient();
if (!$httpClient = Class_HttpClientFactory::getInstance()->getLastHttpClient()) {
return $this;
}
$response_code = $response_body = null;
if ($response = $httpClient->getLastResponse()) {
$response_code = $response->getStatus();
......@@ -206,6 +209,7 @@ create: function(event, ui) { if (ui.panel.hasClass(\'ig-accordion\')) ui.panel.
$response_code);
$this->addCall($call);
return $this;
}
......
......@@ -65,9 +65,7 @@ class ZendAfi_View_Helper_Abonne_Operation extends ZendAfi_View_Helper_BaseHelpe
$record = $this->_getRecord($operation);
return ($record->getId())
? $this->view->Notice_Vignette($record,
$attribs,
ZendAfi_View_Helper_Notice_Vignette::MODE_VIEW)
? $this->view->Notice_Vignette($record, $attribs)
: '';
}
......
......@@ -114,7 +114,7 @@ class ZendAfi_View_Helper_Avis extends ZendAfi_View_Helper_BaseHelper {
if (strlen($auteur_principal = $notice->getAuteurPrincipal()) > 0)
$title .= ' (' . $auteur_principal . ')';
$url_vignette = $notice->fetchUrlVignette();
$url_vignette = $notice->fetchUrlLocalVignette();
}
$content = $this->contenu_avis($avis);
......
......@@ -63,7 +63,7 @@ abstract class ZendAfi_View_Helper_Notice_VignetteStrategy {
$this->_initUrl();
return $this->_service->isNoData($this->_getUrl())
return $this->_service->isNoData($this->_fetchUrl())
? $this->_renderNoThumbnail()
: $this->_renderThumbnail();
}
......@@ -128,9 +128,7 @@ class ZendAfi_View_Helper_Notice_VignetteStrategyResult
protected function _initUrl() {
$this->_record->isSigb()
? $this->_record->fetchUrlLocalVignette()
: $this->_record->fetchUrlVignette();
$this->_record->fetchUrlVignette();
}
}
......@@ -142,7 +140,7 @@ class ZendAfi_View_Helper_Notice_VignetteStrategyView
protected function _renderThumbnail() {
if ($this->_service->isNoData($this->_record->getUrlImage()))
return parent::_renderThumbnail();
return parent::_renderNoThumbnail();
$id = 'vignette_' . $this->_record->getId();
......
......@@ -32,15 +32,58 @@ class ZendAfi_View_Helper_RenderAuthorDescription extends ZendAfi_View_Helper_Ba
$this->_renderBiography($author_description)
. $this->_renderAssociatedFacets($author_description)
. $this->_renderCollaborations($author_description)
. $this->_renderYoutube($author_description)
. $this->_renderRecords($author_description),
['class' => 'author',
'id' => $div_id]);
}
protected function _renderYoutube($author_description) {
if (!$author_description->getYoutubeChannelId())
return '';
$id = 'youtube-channel-' . uniqid();
Class_ScriptLoader::getInstance()
->addJQueryReady(sprintf('$("#%s").load("%s")',
$id,
$this->view->url(['controller' => 'author',
'action' => 'render-youtube-channel',
'id' => $author_description->getId()])));
return $this->_tag('div',
$this->_tag('h2', $this->_('Chaîne Youtube'))
. $this->_tag('div', '', ['id' => $id]),
['class' => 'youtube-channel']);
}
protected function _renderInterviews($author_description) {
if (!$author_description->getRecords())
return '';
$id = 'interviews-' . uniqid();
Class_ScriptLoader::getInstance()
->addJQueryReady(sprintf('$("#%s").load("%s iframe")',
$id,
$this->view->url(['controller' => 'noticeajax',
'action' => 'videos',
'width' => 550,
'author' => $author_description->getLabel(),
'id' => $author_description->getRecords()[0]->getId()])));
return $this->_tag('div',
'',
['id' => $id,
'class' => 'interview']);
}
protected function _renderBiography($author_description) {
return $this->_tag('div',
$author_description->renderBiographieOn($this->view)
$this->_renderInterviews($author_description)
. $author_description->renderBiographieOn($this->view)
.
$this->_renderSeeMore($this->_('Afficher la biographie complète')),
['class' => 'biography']);
......
<?php
/**
* Copyright (c) 2012-2018, Agence Française Informatique (AFI). All rights reserved.
*
* BOKEH is free software; you can redistribute it and/or modify
* it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
* the Free Software Foundation.
*
* There are special exceptions to the terms and conditions of the AGPL as it
* is applied to this software (see README file).
*
* BOKEH 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 AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
* along with BOKEH; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class ZendAfi_View_Helper_renderAuthorMetadata extends ZendAfi_View_Helper_BaseHelper {
public function renderAuthorMetadata($author) {
$attributes = $author->toArray();
if ($id = $attributes['ark'])
$attributes['ark'] = $this->_tag('a',
$id,
['href' => 'https://data.bnf.fr/fr/atelier/' . $id]);
if ($id = $attributes['wikidata_id'])
$attributes['wikidata_id'] = $this->_tag('a',
$id,
['href' => 'https://www.wikidata.org/wiki/' . $id]);
if ($id = $attributes['youtube_channel_id'])
$attributes['youtube_channel_id'] = $this->_tag('a',
$id,
['href' => 'https://www.youtube.com/channel/' . $id]);
return
$this->_tag('h2', $this->_('Auteur : %s',
$author->getLibelle()))
. $this->_tag('dl',
$this->_renderAttributes($attributes));
}
protected function _renderAttributes($attributes) {
$html = '';
foreach($attributes as $key => $value)
$html .= $this->_tag('dt', $key) . $this->_tag('dd', $value);
return $html;
}
}
?>
\ No newline at end of file
......@@ -45,7 +45,7 @@ class FrbrNoticesTelephoneRenderer extends Zend_View_Helper_HtmlElement {
public function renderNotice($notice) {
$url = $this->view->urlNotice($notice);
$img = $this->view->tagImg($notice->fetchUrlVignette());
$img = $this->view->tagImg($notice->fetchUrlLocalVignette());
$h3 = $this->view->tag('h3', $notice->getTitrePrincipal());
$auteur = $this->view->tag('p', $notice->getAuteurPrincipal());
......
......@@ -70,7 +70,7 @@ class ZendAfi_View_Helper_Telephone_Kiosque extends ZendAfi_View_Helper_Accueil_
'id' => $notice->getId(),
'type_doc' => $notice->getTypeDoc()],
null, true),
$notice->fetchUrlVignette(true),
$notice->fetchUrlLocalVignette(),
$this->preferences["op_largeur_img"],
htmlentities($notice->getTitrePrincipal()));
}
......
......@@ -90,7 +90,7 @@ class ZendAfi_View_Helper_Telephone_ListeNotices extends ZendAfi_View_Helper_Bas
// Image
$html .= sprintf('<tr><td width="70px" valign="top"><img src="%s" width="60px" style="cursor:pointer;"></td>',
$notice->fetchUrlVignette());
$notice->fetchUrlLocalVignette());
// Titre / auteur principal
$html .= '<td valign="top">' . $this->view->iconeSupport($type_doc) . '&nbsp;' . $notice->getTitrePrincipal() . BR . $notice->getAuteurPrincipal();
......
......@@ -3606,6 +3606,11 @@ a[href*="bookmarked-searches/notify"] img {
}
.author_view .interview {
margin-left: 10px;
float: right;
}
.author_view .author > div {
clear: both;
}
......@@ -3620,6 +3625,7 @@ a[href*="bookmarked-searches/notify"] img {
.author_view .author > .authors h2,
.author_view .author > .facets h2,
.author_view .author > .youtube-channel h2,
.author_view .author .records h2 {
border-bottom: 1px solid;
padding-top: 10px;
......@@ -3627,6 +3633,16 @@ a[href*="bookmarked-searches/notify"] img {
}
.author_view .author > .youtube-channel > div > div {
display: inline-flex;
column-gap: 20px;
}
.author_view .author > .youtube-channel h3 {
font-size: 0.9em;
}
.author_view .author > .facets {
margin-bottom: 20px;
}