1
0
cms11/app/Services/Browser.php

184 lines
4.5 KiB
PHP

<?php
namespace App\Services;
use Exception;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Exception\Internal\UnexpectedResponseException;
use Facebook\WebDriver\Exception\UnknownErrorException;
use Facebook\WebDriver\Exception\UnrecognizedExceptionException;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverBy;
use Illuminate\Support\Str;
use Intervention\Image\Laravel\Facades\Image;
use Laravel\Dusk\Browser as DuskBrowser;
use Laravel\Dusk\Chrome\SupportsChrome;
use Laravel\Dusk\Concerns\ProvidesBrowser;
class Browser
{
use ProvidesBrowser;
use SupportsChrome;
private $driver;
private $tries = 0;
private $screenshot = null;
private $title = null;
private $description = null;
public function __construct(public string $url, public ?string $optionsSet = 'normal')
{
}
public function name()
{
return Str::slug($this->url);
}
public function dataname()
{
return Str::slug('data_' . $this->url);
}
/**
* Return screenshot content as a jpg resource
*/
public function getScreenshot()
{
return $this->screenshot;
}
/**
* Return page title
*/
public function getTitle()
{
return $this->title;
}
/**
* Return page description, if any is found
*/
public function getDescription()
{
return $this->description;
}
/**
* Navigate to specified URL
*/
public function go()
{
$shouldRetry = false;
DuskBrowser::$storeScreenshotsAt = storage_path('app/screenshots');
DuskBrowser::$storeConsoleLogAt = storage_path('logs/dusk');
DuskBrowser::$storeSourceAt = storage_path('app/sources');
$this->closeAll();
try {
$this->browse(fn (DuskBrowser $browser) => $this->handleNavigation($browser));
} catch (UnknownErrorException $ex) {
// This could happen when SSL certificat is expired
} catch (UnexpectedResponseException $ex) {
dump($ex->getMessage());
} catch (UnrecognizedExceptionException $ex) {
// This could happen on - some - YouTube links. Using the "no-gpu"
// preset fixes the problem
$shouldRetry = true;
$this->optionsSet = 'no-gpu';
} finally {
$this->closeAll();
}
$this->tries++;
if ($shouldRetry) {
if ($this->tries === 3) {
throw new Exception(sprintf('Maximum tries reach for url %s', $this->url));
}
unset($this->driver);
return $this->go();
}
}
/**
* Create the RemoteWebDriver instance.
*/
protected function driver(): RemoteWebDriver
{
if (!isset($this->driver)) {
$options = $this->getDriverOptions();
$this->driver = RemoteWebDriver::create(
$_ENV['DUSK_DRIVER_URL'],
DesiredCapabilities::chrome()->setCapability(
ChromeOptions::CAPABILITY,
$options
)
);
}
return $this->driver;
}
/**
* Return driver options
*/
protected function getDriverOptions()
{
$options = (new ChromeOptions)
->addArguments(
collect(config(sprintf('browser.%s', $this->optionsSet)))
->all()
);
return $options;
}
private function handleNavigation(DuskBrowser $browser)
{
$browser->resize(1920, 1080)
->visit($this->url)
->pause(1000);
$this->screenshot = $this->takeScreenshot($browser);
$this->title = $browser->driver->getTitle();
$this->description = $this->findDescription($browser);
$browser->quit();
}
private function findDescription(DuskBrowser $browser)
{
$description = null;
try {
$descriptionMeta = $browser->driver->findElement(WebDriverBy::xpath("//meta[@name='description']"));
$description = $descriptionMeta->getAttribute('content');
} finally {
}
return $description;
}
private function takeScreenshot(DuskBrowser $browser)
{
$contents = $browser->driver->takeScreenshot();
$image = Image::read($contents);
$this->screenshot = $image->toJpeg();
return $this->screenshot;
}
}