From: Vincent Vanwaelscappel Date: Tue, 23 Aug 2022 18:13:10 +0000 (+0200) Subject: wip #5399 @1.5 X-Git-Url: http://git.cubedesigners.com/?a=commitdiff_plain;h=0fc89c539d54f4184590ef91bb29cf67d9e1d73a;p=fluidbook-toolbox.git wip #5399 @1.5 --- diff --git a/app/Http/Controllers/Admin/Operations/FluidbookPublication/Services/SocialImageOperation.php b/app/Http/Controllers/Admin/Operations/FluidbookPublication/Services/SocialImageOperation.php new file mode 100644 index 000000000..1efcb398d --- /dev/null +++ b/app/Http/Controllers/Admin/Operations/FluidbookPublication/Services/SocialImageOperation.php @@ -0,0 +1,131 @@ +withoutMiddleware([CheckIfAdmin::class]); + Route::match(['get'], 'services/facebook_thumbnail', $controller . '@ws2SocialImage')->withoutMiddleware([CheckIfAdmin::class]); + } + + public function ws2SocialImage() + { + if (request()->has('id') && request()->input('id') <= 18972) { + $publication = FluidbookPublication::find(request()->input('id')); + if (null === $publication) { + abort(404); + } + return $this->_socialImage($publication); + } else if (request()->has('cid')) { + return $this->socialImage(request()->input('cid')); + } + abort(404); + } + + public function socialImage($cid) + { + $publication = FluidbookPublication::where('cid', $cid)->first(); + if (null === $publication) { + abort(404); + } + return $this->_socialImage($publication); + } + + public static function socialImagePath($id, $ext = 'jpg') + { + return Files::mkdir(protected_path('fluidbookpublication/socialimage')) . '/' . $id . '.' . $ext; + } + + /** + * @param $fluidbook FluidbookPublication + * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response|object + * @throws \Exception + */ + protected function _socialImage($fluidbook) + { + PHP::neverStop(true); + + $social = self::createSocialImage($fluidbook); + return XSendFileController::sendfile($social); + } + + /** + * @param $fluidbook FluidbookPublication + * @return string + */ + public static function createSocialImage($fluidbook) + { + $id = $fluidbook->id; + $wid = $fluidbook->getAssetDir() . '/'; + + if ($fluidbook->facebook_image != '') { + $c = $wid . $fluidbook->facebook_image; + if (file_exists($c)) { + $res = $c; + } + } + + if (!isset($res)) { + $res = self::socialImagePath($id); + $limit = max(time() - (3600 * 24 * 30), $fluidbook->updated_at->getTimestamp()); + $minsize = 20 * 1024; + + if (isset($_GET['force']) || !file_exists($res) || filemtime($res) < $limit || filesize($res) < $minsize) { + $lock = self::socialImagePath($id, 'lock'); + if (!file_exists($lock) || filemtime($lock) < time() - 3600) { + touch($lock); + + $url = 'https://workshop.fluidbook.com/viewerh/' . $id . '_' . $fluidbook->hash . '_' . time() . '/?nointerface=1'; + if ((file_exists($res) && filemtime($res) < $limit) || isset($_GET['forcecompile'])) { + $url .= '&force=1'; + } + $url .= '#/page/0'; + + $w = 1200; + $h = 628; + + $cl = new CommandLine('node'); + $cl->setArg(null, resource_path('fluidbookpublication/social_screenshot/social_screenshot.js')); + $cl->setArg('width', $w); + $cl->setArg('height', $h); + $cl->setArg('delay', 10); + $cl->setArg('scale', 0.5); + $cl->setArg('dest', $res); + $cl->setArg('url', $url); + $cl->execute(); + unlink($lock); + } + } + } + return $res; + } + + /** + * @param $fluidbook + * @return array + * @throws \Exception + */ + public static function getSocialImageSize($fluidbook) + { + $socialImage = self::createSocialImage($fluidbook); + $sizeFile = self::socialImagePath($fluidbook->id, 'size'); + if (!file_exists($sizeFile) || filemtime($sizeFile) < filemtime($socialImage)) { + $res = Image::getimagesize($socialImage); + file_put_contents($sizeFile, json_encode($res)); + return $res; + } + return json_decode(file_get_contents($sizeFile), true); + } +} diff --git a/app/Jobs/FluidbookCompiler.php b/app/Jobs/FluidbookCompiler.php index 24eec2a8a..93836bb86 100644 --- a/app/Jobs/FluidbookCompiler.php +++ b/app/Jobs/FluidbookCompiler.php @@ -2,6 +2,8 @@ namespace App\Jobs; +use App\Http\Controllers\Admin\Operations\FluidbookPublication\Services\SocialImageOperation; +use App\Models\Signature; use App\Fluidbook\SearchIndex; use App\Fluidbook\SEO\Document; use App\Models\FluidbookPublication; @@ -514,8 +516,6 @@ class FluidbookCompiler extends Base implements CompilerInterface $this->config->manifest = $this->writeManifest(); } - $this->writeGPUDatabase(); - if ($this->config->form == 'bulle') { $this->addJsLib('bulle', 'js/libs/fluidbook/forms/fluidbook.form.bulle.js'); } else if ($this->config->form == 'bourbon') { @@ -1043,22 +1043,8 @@ class FluidbookCompiler extends Base implements CompilerInterface } } - public function writeGPUDatabase() - { - $r = $core->con->select('SELECT gpu,rgpu,score FROM gpu'); - $gpu = []; - while ($r->fetch()) { - $gpu[$r->gpu] = $r->score; - $gpu[$r->rgpu] = $r->score; - } - $this->config->gupsc = $gpu; - $this->config->gupse = wsServices::gpuSeparators(); - } - public function log($step) { - - $currenttime = microtime(true); if (null === $this->logfp) { $this->logfp = fopen('/var/log/extranet/htmlconversions/' . $this->book_id . '.log', 'w+'); @@ -1620,21 +1606,21 @@ height="0" width="0" style="display:none;visibility:hidden"> } } + /** + * @throws \Exception + */ public function getIndexVars() { if (null === $this->_indexVars) { $titre = $this->fluidbookSettings->title; - if (null === $this->_signature) { - $daoSignature = new wsDAOSignature($core->con); - $this->_signature = $daoSignature->selectById($this->fluidbookSettings->signature); + $this->_signature = Signature::find($this->fluidbookSettings->signature); + $credits = $this->_signature->credits; + } else { + $credits = ''; } - - $credits = $this->_signature->credits; - $hiddenContents = implode("\n", $this->hiddenContents); - $bgcolor = $this->themeSettings->loadingBackColor; // Feuilles de style @@ -1642,7 +1628,7 @@ height="0" width="0" style="display:none;visibility:hidden"> $style = array(); foreach ($sheets as $sheet) { - $style[] = ''; + $style[] = ''; } $style = implode("\n\t\t", $style); @@ -1654,7 +1640,7 @@ height="0" width="0" style="display:none;visibility:hidden"> $beginbody = implode("\n", array_unique($this->beginBody)); - $jstime = "?j=" . TIME; + $jstime = "?j=" . time(); $iscript = ''; if (count($this->htmlmultimedia)) { @@ -1680,18 +1666,11 @@ height="0" width="0" style="display:none;visibility:hidden"> $this->log('Got index vars 2'); - $socialTitle = html::escapeHTML($this->fluidbookSettings->facebook_title ? $this->fluidbookSettings->facebook_title : $titre); - $socialDescription = html::escapeHTML($this->fluidbookSettings->facebook_description ? $this->fluidbookSettings->facebook_description : $this->fluidbookSettings->seoDescription); + $socialTitle = htmlspecialchars($this->fluidbookSettings->facebook_title ?: $titre, ENT_COMPAT); + $socialDescription = htmlspecialchars($this->fluidbookSettings->facebook_description ?: $this->fluidbookSettings->seoDescription, ENT_COMPAT); - $socialImage = 'https://workshop.fluidbook.com/services/facebook_thumbnail?cid=' . $this->getFluidbook()->cid; - $sizeFile = WS_FILES . '/social_image/' . $this->getFluidbook()->book_id . '.size'; - if (!file_exists($sizeFile)) { - $dim = Image::getimagesize($socialImage); - file_put_contents($sizeFile, json_encode($dim)); - $this->log('Got index vars (measure social image)'); - } else { - $dim = json_decode(file_get_contents($sizeFile), true); - } + $socialImage = 'https://toolbox.fluidbook.com/services/socialimage/' . $this->getFluidbook()->cid; + $dim = SocialImageOperation::getSocialImageSize($this->getFluidbook()); $socialImageWidth = $dim[0]; $socialImageHeight = $dim[1]; @@ -1733,7 +1712,7 @@ height="0" width="0" style="display:none;visibility:hidden"> $convert = "convert $pngFile -resize 64x64^ -gravity center $tmp"; `$convert`; - $icotool = new cubeCommandLine('icotool'); + $icotool = new CommandLine('icotool'); $icotool->setArg('c'); $icotool->setArg('o', $icoFile); $icotool->setArg(null, $tmp); @@ -1935,7 +1914,7 @@ height="0" width="0" style="display:none;visibility:hidden"> } $a = $seoArticle; unset($a['image']); - $a['imageurl'] = 'https://workshop.fluidbook.com/services/facebook_thumbnail?cid=' . $this->getFluidbook()->cid . '&j=' . TIME; + $a['imageurl'] = 'https://workshop.fluidbook.com/services/facebook_thumbnail?cid=' . $this->getFluidbook()->cid . '&j=' . time(); if ($seoArticle['image']) { $a['imageurl'] .= '&image=' . $seoArticle['image']; } @@ -3197,13 +3176,10 @@ height="0" width="0" style="display:none;visibility:hidden"> $this->lessVariables['menu-chapters-font-size'] = $this->fluidbookSettings->chaptersFontSize; foreach ($this->getFluidbook()->chapters as $chapter) { - if (substr($chapter->page, 0, 1) != '#') { + if ($chapter['color'] == '') { continue; } - if ($chapter->color == '') { - continue; - } - $color = trim($chapter->color, '#'); + $color = trim($chapter['color'], '#'); $lessContents .= '.mview.c_' . $color . '{.menu-color(' . Color::colorToCSS($color) . ');}'; } @@ -3336,17 +3312,17 @@ height="0" width="0" style="display:none;visibility:hidden"> $body = '#background, #splash {'; switch ($this->themeSettings->repeat) { - case wsTheme::REPEAT: + case FluidbookTheme::REPEAT: $body .= 'background-repeat:repeat;'; break; - case wsTheme::NONE: + case FluidbookTheme::NONE: $body .= 'background-repeat:no-repeat;'; break; - case wsTheme::RATIO: + case FluidbookTheme::RATIO: $body .= 'background-repeat:no-repeat;'; $body .= 'background-size:cover;'; break; - case wsTheme::STRETCH: + case FluidbookTheme::STRETCH: $body .= 'background-repeat:no-repeat;'; $body .= 'background-size:100% 100%;'; break; @@ -3363,13 +3339,13 @@ height="0" width="0" style="display:none;visibility:hidden"> $body .= 'background-position:'; switch ($this->themeSettings->backgroundVAlign) { - case wsTheme::TOP: + case FluidbookTheme::TOP: $body .= 'top'; break; - case wsTheme::MIDDLE: + case FluidbookTheme::MIDDLE: $body .= 'center'; break; - case wsTheme::BOTTOM: + case FluidbookTheme::BOTTOM: $body .= 'bottom'; break; } @@ -3377,13 +3353,13 @@ height="0" width="0" style="display:none;visibility:hidden"> $body .= ' '; switch ($this->themeSettings->backgroundHAlign) { - case wsTheme::LEFT: + case FluidbookTheme::LEFT: $body .= 'left'; break; - case wsTheme::CENTER: + case FluidbookTheme::CENTER: $body .= 'center'; break; - case wsTheme::RIGHT: + case FluidbookTheme::RIGHT: $body .= 'right'; break; } @@ -3692,15 +3668,14 @@ height="0" width="0" style="display:none;visibility:hidden"> public function writeXMLArticles() { $f = $this->fluidbookSettings->articlesFile; - if (!$f || !file_exists($this->wdir . '/' . $f) || !is_file($this->wdir . '/' . $f)) { - return; - } $this->lessVariables['articles-title-color'] = '#000000'; $this->lessVariables['articles-font'] = 'Open Sans'; - $f = $this->wdir . '/' . $f; - + if (!$f || !file_exists($this->wdir . '/' . $f) || !is_file($this->wdir . '/' . $f)) { + return; + } + $f = $this->wdir . '/' . $f; $mapFonts = ['OpenSans' => 'Open Sans']; $this->addLess('articles'); if ($this->fluidbookSettings->articlesStyle !== 'default') { diff --git a/app/Models/FluidbookTheme.php b/app/Models/FluidbookTheme.php index 17fcdcb39..d9f6b8bc6 100644 --- a/app/Models/FluidbookTheme.php +++ b/app/Models/FluidbookTheme.php @@ -13,6 +13,19 @@ use Cubist\Backpack\Magic\Fields\SelectFromModel; class FluidbookTheme extends ToolboxSettingsModel { + const NONE = 3; + const STRETCH = 0; + const RATIO = 2; + const REPEAT = 1; + + const CENTER = 4; + const LEFT = 5; + const RIGHT = 6; + + const MIDDLE = 7; + const TOP = 8; + const BOTTOM = 9; + protected $table = 'fluidbook_theme'; protected $_options = ['name' => 'fluidbook-theme', 'singular' => 'theme', diff --git a/resources/fluidbookpublication/social_screenshot/social_screenshot.js b/resources/fluidbookpublication/social_screenshot/social_screenshot.js new file mode 100644 index 000000000..f27cc9d3a --- /dev/null +++ b/resources/fluidbookpublication/social_screenshot/social_screenshot.js @@ -0,0 +1,27 @@ +const puppeteer = require('puppeteer'); +const commandLineArgs = require('command-line-args'); +const optionDefinitions = [ + {name: 'url', type: String}, + {name: 'dest', type: String}, + {name: 'delay', type: Number, defaultOption: 10}, + {name: 'scale', type: Number, defaultOption: 1}, + {name: 'width', type: Number, defaultOption: 1920}, + {name: 'height', type: Number, defaultOption: 1080} +]; + +(async () => { + const options = commandLineArgs(optionDefinitions); + const browser = await puppeteer.launch({headless: true}); + const page = await browser.newPage(); + page.on('console', msg => console.log('PAGE LOG:', msg._text)); + await page.setViewport({ + width: options.width / options.scale, + height: options.height / options.scale, + deviceScaleFactor: options.scale, + }); + await page.setDefaultNavigationTimeout(0); + await page.goto(options.url); + await new Promise(r => setTimeout(r, 1000 * options.delay)); + await page.screenshot({path: options.dest, type: 'jpeg', quality: 95}); + await browser.close(); +})(); \ No newline at end of file