]> _ Git - fluidbook-toolbox.git/commitdiff
wip #5399 @1.5
authorVincent Vanwaelscappel <vincent@cubedesigners.com>
Tue, 23 Aug 2022 18:13:10 +0000 (20:13 +0200)
committerVincent Vanwaelscappel <vincent@cubedesigners.com>
Tue, 23 Aug 2022 18:13:10 +0000 (20:13 +0200)
app/Http/Controllers/Admin/Operations/FluidbookPublication/Services/SocialImageOperation.php [new file with mode: 0644]
app/Jobs/FluidbookCompiler.php
app/Models/FluidbookTheme.php
resources/fluidbookpublication/social_screenshot/social_screenshot.js [new file with mode: 0644]

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 (file)
index 0000000..1efcb39
--- /dev/null
@@ -0,0 +1,131 @@
+<?php
+
+namespace App\Http\Controllers\Admin\Operations\FluidbookPublication\Services;
+
+use App\Http\Middleware\CheckIfAdmin;
+use App\Models\FluidbookPublication;
+use Cubist\Backpack\Http\Controllers\Base\XSendFileController;
+use Cubist\Util\CommandLine;
+use Cubist\Util\Files\Files;
+use Cubist\Util\Graphics\Image;
+use Cubist\Util\PHP;
+use Illuminate\Support\Facades\Route;
+use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions\F;
+
+trait SocialImageOperation
+{
+    protected function setupSocialimageRoutes($segment, $routeName, $controller)
+    {
+        Route::match(['get'], 'services/socialimage/{cid?}', $controller . '@socialImage')->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);
+    }
+}
index 24eec2a8aa5afb572db43fde16b088ceb46a0c75..93836bb86f5dd96a4fd3b45594f7497785d8f7c4 100644 (file)
@@ -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"></iframe></noscript>
         }
     }
 
+    /**
+     * @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"></iframe></noscript>
 
             $style = array();
             foreach ($sheets as $sheet) {
-                $style[] = '<link type="text/css" rel="stylesheet" media="screen" href="' . $sheet . '?j=' . TIME . '">';
+                $style[] = '<link type="text/css" rel="stylesheet" media="screen" href="' . $sheet . '?j=' . time() . '">';
             }
             $style = implode("\n\t\t", $style);
 
@@ -1654,7 +1640,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
 
             $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"></iframe></noscript>
 
             $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"></iframe></noscript>
                     $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"></iframe></noscript>
             }
             $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"></iframe></noscript>
         $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"></iframe></noscript>
         $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"></iframe></noscript>
             $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"></iframe></noscript>
             $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"></iframe></noscript>
     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') {
index 17fcdcb39686a07275a83c98cbb0e35e9bf15f7b..d9f6b8bc6443714ce09d15b72edd3a0ecffc120f 100644 (file)
@@ -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 (file)
index 0000000..f27cc9d
--- /dev/null
@@ -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