diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index faec9f09..15297cc3 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,8 +1,21 @@ FROM rssbridge/rss-bridge:latest -RUN apt-get update && \ - apt-get install --yes --no-install-recommends \ - git && \ - pecl install xdebug && \ - pear install PHP_CodeSniffer && \ - docker-php-ext-enable xdebug \ No newline at end of file +COPY --chmod=755 post-create-command.sh /usr/local/bin/post-create-command + +ADD https://raw.githubusercontent.com/docker-library/php/master/docker-php-ext-enable /usr/local/bin/docker-php-ext-enable +RUN chmod u+x /usr/local/bin/docker-php-ext-enable + +ADD https://getcomposer.org/installer /usr/local/bin/composer-installer.php +RUN chmod u+x /usr/local/bin/composer-installer.php +RUN php /usr/local/bin/composer-installer.php --check && \ + php /usr/local/bin/composer-installer.php --filename=composer --install-dir=/usr/local/bin + +RUN apt-get update && \ + apt-get install -y \ + git \ + php-dev \ + make \ + unzip + +RUN pecl install xdebug && \ + PHP_INI_DIR=/etc/php/8.2/fpm docker-php-ext-enable xdebug diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 6e625b8a..564da38a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,9 +6,9 @@ "vscode": { // Set *default* container specific settings.json values on container create. "settings": { - "php.validate.executablePath": "/usr/local/bin/php", - "phpSniffer.executablesFolder": "/usr/local/bin/", - "phpcs.executablePath": "/usr/local/bin/phpcs", + "php.validate.executablePath": "/usr/bin/php", + "phpSniffer.executablesFolder": "/root/.config/composer/vendor/bin", + "phpcs.executablePath": "/root/.config/composer/vendor/bin/phpcs", "phpcs.lintOnType": false }, @@ -22,6 +22,9 @@ ] } }, + "remoteEnv": { + "PATH": "${containerEnv:PATH}:/root/.config/composer/vendor/bin", + }, "forwardPorts": [3100, 9000, 9003], - "postCreateCommand": "cp .devcontainer/nginx.conf /etc/nginx/conf.d/default.conf && cp .devcontainer/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini && mkdir .vscode && cp .devcontainer/launch.json .vscode && echo '*' > whitelist.txt && chmod a+x \"$(pwd)\" && rm -rf /var/www/html && ln -s \"$(pwd)\" /var/www/html && nginx && php-fpm -D" + "postCreateCommand": "/usr/local/bin/post-create-command" } \ No newline at end of file diff --git a/.devcontainer/launch.json b/.devcontainer/launch.json index e1b473b8..7fe617e9 100644 --- a/.devcontainer/launch.json +++ b/.devcontainer/launch.json @@ -9,7 +9,8 @@ "type": "php", "request": "launch", "port": 9003, - "auto": true + "auto": true, + "log": true }, { "name": "Launch currently open script", diff --git a/.devcontainer/post-create-command.sh b/.devcontainer/post-create-command.sh new file mode 100755 index 00000000..aa3819eb --- /dev/null +++ b/.devcontainer/post-create-command.sh @@ -0,0 +1,27 @@ +#/bin/sh + +cp .devcontainer/nginx.conf /etc/nginx/conf.d/default.conf +cp .devcontainer/xdebug.ini /etc/php/8.2/fpm/conf.d/xdebug.ini + +# This should download some dev-dependencies, like phpunit and the PHP code sniffers +composer global require "phpunit/phpunit:^9" +composer global require "squizlabs/php_codesniffer:^3.6" +composer global require "phpcompatibility/php-compatibility:^9.3" + +# We need to this manually for running the PHPCompatibility ruleset +phpcs --config-set installed_paths /root/.config/composer/vendor/phpcompatibility/php-compatibility + +mkdir -p .vscode +cp .devcontainer/launch.json .vscode + +echo '*' > whitelist.txt + +chmod a+x $(pwd) +rm -rf /var/www/html +ln -s $(pwd) /var/www/html + +# Solves possible issue of cache directory not being accessible +chown www-data:www-data -R $(pwd)/cache + +nginx +php-fpm8.2 -D \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 206b53de..79201edd 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,7 +8,7 @@ on: jobs: phpcs: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: matrix: php-versions: ['7.4'] @@ -21,7 +21,7 @@ jobs: - run: phpcs . --standard=phpcs.xml --warning-severity=0 --extensions=php -p phpcompatibility: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: matrix: php-versions: ['7.4'] @@ -36,7 +36,7 @@ jobs: - run: ~/.composer/vendor/bin/phpcs . --standard=phpcompatibility.xml --warning-severity=0 --extensions=php -p executable_php_files_check: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - run: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 93f07b0f..96128fc2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ on: jobs: phpunit8: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: matrix: php-versions: ['7.4', '8.0', '8.1'] diff --git a/bridges/CuriousCatBridge.php b/bridges/CuriousCatBridge.php deleted file mode 100644 index 3d6e87d0..00000000 --- a/bridges/CuriousCatBridge.php +++ /dev/null @@ -1,113 +0,0 @@ - [ - 'name' => 'Username', - 'type' => 'text', - 'required' => true, - 'exampleValue' => 'koethekoethe', - ] - ]]; - - const CACHE_TIMEOUT = 3600; - - public function collectData() - { - $url = self::URI . '/api/v2/profile?username=' . urlencode($this->getInput('username')); - - $apiJson = getContents($url); - - $apiData = Json::decode($apiJson); - if (isset($apiData['error'])) { - throw new \Exception($apiData['error_code']); - } - - foreach ($apiData['posts'] as $post) { - $item = []; - - $item['author'] = 'Anonymous'; - - if ($post['senderData']['id'] !== false) { - $item['author'] = $post['senderData']['username']; - } - - $item['uri'] = $this->getURI() . '/post/' . $post['id']; - $item['title'] = $this->ellipsisTitle($post['comment']); - - $item['content'] = $this->processContent($post); - $item['timestamp'] = $post['timestamp']; - - $this->items[] = $item; - } - } - - public function getURI() - { - if (!is_null($this->getInput('username'))) { - return self::URI . '/' . $this->getInput('username'); - } - - return parent::getURI(); - } - - public function getName() - { - if (!is_null($this->getInput('username'))) { - return $this->getInput('username') . ' - Curious Cat'; - } - - return parent::getName(); - } - - private function processContent($post) - { - $author = 'Anonymous'; - - if ($post['senderData']['id'] !== false) { - $authorUrl = self::URI . '/' . $post['senderData']['username']; - - $author = <<{$post['senderData']['username']} -EOD; - } - - $question = $this->formatUrls($post['comment']); - $answer = $this->formatUrls($post['reply']); - - $content = <<{$author} asked:

-
{$question}

-

{$post['addresseeData']['username']} answered:

-
{$answer}
-EOD; - - return $content; - } - - private function ellipsisTitle($text) - { - $length = 150; - - if (strlen($text) > $length) { - $text = explode('
', wordwrap($text, $length, '
')); - return $text[0] . '...'; - } - - return $text; - } - - private function formatUrls($content) - { - return preg_replace( - '/(http[s]{0,1}\:\/\/[a-zA-Z0-9.\/\?\&=\-_]{4,})/ims', - '$1 ', - $content - ); - } -} diff --git a/bridges/EpicGamesFreeBridge.php b/bridges/EpicGamesFreeBridge.php index 087b95be..3b16cd5b 100644 --- a/bridges/EpicGamesFreeBridge.php +++ b/bridges/EpicGamesFreeBridge.php @@ -27,7 +27,7 @@ class EpicGamesFreeBridge extends BridgeAbstract 'Türkçe' => 'tr', '简体中文' => 'zh-CN', '繁體中文' => 'zh-Hant', - ], + ], 'title' => 'Language for game information', 'defaultValue' => 'en-US', ], @@ -51,16 +51,21 @@ class EpicGamesFreeBridge extends BridgeAbstract $data = $json['data']['Catalog']['searchStore']['elements']; foreach ($data as $element) { - if (!isset($element['promotions']['promotionalOffers'][0])) { + $promo = $element['promotions']['promotionalOffers'][0]['promotionalOffers'][0] ?? false; + if ( + !$promo || + $promo['discountSetting']['discountType'] !== 'PERCENTAGE' || + $promo['discountSetting']['discountPercentage'] !== 0 + ) { continue; } $item = [ 'author' => $element['seller']['name'], 'content' => $element['description'], 'enclosures' => array_map(fn($item) => $item['url'], $element['keyImages']), - 'timestamp' => strtotime($element['promotions']['promotionalOffers'][0]['promotionalOffers'][0]['startDate']), + 'timestamp' => strtotime($promo['startDate']), 'title' => $element['title'], - 'url' => parent::getURI() . $this->getInput('locale') . '/p/' . $element['urlSlug'], + 'uri' => parent::getURI() . $this->getInput('locale') . '/p/' . $element['productSlug'], ]; $this->items[] = $item; } diff --git a/bridges/FabBridge.php b/bridges/FabBridge.php index bed849be..00130ad2 100644 --- a/bridges/FabBridge.php +++ b/bridges/FabBridge.php @@ -10,6 +10,7 @@ class FabBridge extends BridgeAbstract public function collectData() { + $responseheaders = get_headers(static::URI); $csrf = ""; @@ -27,8 +28,8 @@ class FabBridge extends BridgeAbstract 'Accept: application/json, text/plain, */*', 'Accept-Language: en', 'Accept-Encoding: gzip, deflate, br, zstd', - 'Referer: ' . static::URI, 'Cookie: ' . $csrf, + 'Referer: ' . static::URI ]; $json = getContents($url, $header); diff --git a/bridges/GoComicsBridge.php b/bridges/GoComicsBridge.php index 968c2c4d..8e78ce5e 100644 --- a/bridges/GoComicsBridge.php +++ b/bridges/GoComicsBridge.php @@ -31,25 +31,33 @@ class GoComicsBridge extends BridgeAbstract public function collectData() { $link = $this->getURI(); + $landingpage = getSimpleHTMLDOM($link); + $element = $landingpage->find('div[data-post-url]', 0); + if ($element) { + $link = $element->getAttribute('data-post-url'); + } else { // fallback for comics without data-post-url (assumes daily comic) + $nextcomiclink = $landingpage->find('a[class*="ComicNavigation_controls__button_previous__"]', 0)->href; + preg_match('/(\d{4}\/\d{2}\/\d{2})/', $nextcomiclink, $nclmatches); + if (!empty($nclmatches[1])) { + $nextdate = new DateTime($nclmatches[1]); + $nextdate = $nextdate->modify('+1 day')->format('Y/m/d'); + $link = $link . '/' . $nextdate; + } else { + throw new \Exception('Could not find the first comic URL. Please create a new GitHub issue.'); + } + } for ($i = 0; $i < $this->getInput('limit'); $i++) { $html = getSimpleHTMLDOM($link); - // get json data from the first page - $json = $html->find('div[class^="ShowComicViewer_showComicViewer__comic__"] script[type="application/ld+json"]', 0)->innertext; - $data = json_decode($json, false); + + $imagelink = $html->find('meta[property="og:image"]', 0)->content; + $parts = explode('/', $link); + $date = DateTime::createFromFormat('Y/m/d', implode('/', array_slice($parts, -3))); + $title = $html->find('meta[property="og:title"]', 0)->content; + preg_match('/by (.*?) for/', $title, $authormatches); + $author = $authormatches[1] ?? 'GoComics'; $item = []; - - $author = $data->author->name; - $imagelink = $data->contentUrl; - $date = $data->datePublished; - $title = $data->name . ' - GoComics'; - - // get a permlink for this day's comic if there isn't one specified - if ($link === $this->getURI()) { - $link = $this->getURI() . '/' . DateTime::createFromFormat('F j, Y', $date)->format('Y/m/d'); - } - $item['id'] = $imagelink; $item['uri'] = $link; $item['author'] = $author; @@ -57,7 +65,7 @@ class GoComicsBridge extends BridgeAbstract if ($this->getInput('date-in-title') === true) { $item['title'] = $title; } - $item['timestamp'] = DateTime::createFromFormat('F j, Y', $date)->setTime(0, 0, 0)->getTimestamp(); + $item['timestamp'] = $date->setTime(0, 0, 0)->getTimestamp(); $item['content'] = ''; $link = rtrim(self::URI, '/') . $html->find('a[class*="ComicNavigation_controls__button_previous__"]', 0)->href; diff --git a/bridges/GolemBridge.php b/bridges/GolemBridge.php index 219233f4..fbd154e3 100644 --- a/bridges/GolemBridge.php +++ b/bridges/GolemBridge.php @@ -152,7 +152,7 @@ class GolemBridge extends FeedExpander $img->src = $img->getAttribute('data-src-full'); } - foreach ($content->find('p, h1, h2, h3, img[src*="."], iframe, video') as $element) { + foreach ($content->find('p, h1, h2, h3, pre, img[src*="."], iframe, video') as $element) { $item .= $element; } diff --git a/bridges/IdealoBridge.php b/bridges/IdealoBridge.php index 55cee467..05a2ebb8 100644 --- a/bridges/IdealoBridge.php +++ b/bridges/IdealoBridge.php @@ -35,6 +35,16 @@ class IdealoBridge extends BridgeAbstract ] ]; + private $headers = [ + 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139.0) Gecko/20100101 Firefox/139.0', + 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', + 'Accept-Language: fr-FR,fr;q=0.8,en-US;q=0.5,en;q=0.3' + ]; + private $options = [ + CURLOPT_TRANSFER_ENCODING => 1, + CURLOPT_ACCEPT_ENCODING => 'gzip, deflate, br' + ]; + public function getIcon() { return 'https://cdn.idealo.com/storage/ids-assets/ico/favicon.ico'; @@ -53,10 +63,7 @@ class IdealoBridge extends BridgeAbstract // The cache does not contain the title of the bridge, we must get it and save it in the cache if ($product === null) { - $header = [ - 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2.1 Safari/605.1.15' - ]; - $html = getSimpleHTMLDOM($link, $header); + $html = getSimpleHTMLDOM($link, $this->headers, $this->options); $product = $html->find('.oopStage-title', 0)->find('span', 0)->plaintext; $this->saveCacheValue($keyTITLE, $product); } @@ -123,13 +130,8 @@ class IdealoBridge extends BridgeAbstract } public function collectData() { - // Needs header with user-agent to function properly. - $header = [ - 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2.1 Safari/605.1.15' - ]; - $link = $this->getInput('Link'); - $html = getSimpleHTMLDOM($link, $header); + $html = getSimpleHTMLDOM($link, $this->headers, $this->options); // Get Productname $titleobj = $html->find('.oopStage-title', 0); diff --git a/bridges/OpenlyBridge.php b/bridges/OpenlyBridge.php deleted file mode 100644 index 9f54e22a..00000000 --- a/bridges/OpenlyBridge.php +++ /dev/null @@ -1,255 +0,0 @@ - [], - 'All Opinion' => [], - 'By Region' => [ - 'region' => [ - 'name' => 'Region', - 'type' => 'list', - 'values' => [ - 'Africa' => 'africa', - 'Asia Pacific' => 'asia-pacific', - 'Europe' => 'europe', - 'Latin America' => 'latin-america', - 'Middle Easta' => 'middle-east', - 'North America' => 'north-america' - ] - ], - 'content' => [ - 'name' => 'Content', - 'type' => 'list', - 'values' => [ - 'News' => 'news', - 'Opinion' => 'people' - ], - 'defaultValue' => 'news' - ] - ], - 'By Tag' => [ - 'tag' => [ - 'name' => 'Tag', - 'type' => 'text', - 'required' => true, - 'exampleValue' => 'lgbt-law', - ], - 'content' => [ - 'name' => 'Content', - 'type' => 'list', - 'values' => [ - 'News' => 'news', - 'Opinion' => 'people' - ], - 'defaultValue' => 'news' - ] - ], - 'By Author' => [ - 'profileId' => [ - 'name' => 'Profile ID', - 'type' => 'text', - 'required' => true, - 'exampleValue' => '003D000002WZGYRIA5', - ] - ] - ]; - - const TEST_DETECT_PARAMETERS = [ - 'https://www.openlynews.com/profile/?id=0033z00002XUTepAAH' => [ - 'context' => 'By Author', 'profileId' => '0033z00002XUTepAAH' - ], - 'https://www.openlynews.com/news/?page=1&theme=lgbt-law' => [ - 'context' => 'By Tag', 'content' => 'news', 'tag' => 'lgbt-law' - ], - 'https://www.openlynews.com/news/?page=1®ion=north-america' => [ - 'context' => 'By Region', 'content' => 'news', 'region' => 'north-america' - ], - 'https://www.openlynews.com/news/?theme=lgbt-law' => [ - 'context' => 'By Tag', 'content' => 'news', 'tag' => 'lgbt-law' - ], - 'https://www.openlynews.com/news/?region=north-america' => [ - 'context' => 'By Region', 'content' => 'news', 'region' => 'north-america' - ] - ]; - - const CACHE_TIMEOUT = 900; // 15 mins - const ARTICLE_CACHE_TIMEOUT = 3600; // 1 hour - - private $feedTitle = ''; - private $itemLimit = 10; - - private $profileUrlRegex = '/openlynews\.com\/profile\/\?id=([a-zA-Z0-9]+)/'; - private $tagUrlRegex = '/openlynews\.com\/([a-z]+)\/\?(?:page=(?:[0-9]+)&)?theme=([\w-]+)/'; - private $regionUrlRegex = '/openlynews\.com\/([a-z]+)\/\?(?:page=(?:[0-9]+)&)?region=([\w-]+)/'; - - public function detectParameters($url) - { - $params = []; - - if (preg_match($this->profileUrlRegex, $url, $matches) > 0) { - $params['context'] = 'By Author'; - $params['profileId'] = $matches[1]; - return $params; - } - - if (preg_match($this->tagUrlRegex, $url, $matches) > 0) { - $params['context'] = 'By Tag'; - $params['content'] = $matches[1]; - $params['tag'] = $matches[2]; - return $params; - } - - if (preg_match($this->regionUrlRegex, $url, $matches) > 0) { - $params['context'] = 'By Region'; - $params['content'] = $matches[1]; - $params['region'] = $matches[2]; - return $params; - } - - return null; - } - - public function collectData() - { - $url = $this->getAjaxURI(); - - if ($this->queriedContext === 'By Author') { - $url = $this->getURI(); - } - - $html = getSimpleHTMLDOM($url); - $html = defaultLinkTo($html, $this->getURI()); - - if ($html->find('h1', 0)) { - $this->feedTitle = $html->find('h1', 0)->plaintext; - } - - if ($html->find('h2.title-v4', 0)) { - $html->find('span.tooltiptext', 0)->innertext = ''; - $this->feedTitle = $html->find('a.tooltipitem', 0)->plaintext; - } - - $items = $html->find('div.item'); - $limit = 5; - foreach (array_slice($items, 0, $limit) as $div) { - $this->items[] = $this->getArticle($div->find('a', 0)->href); - - if (count($this->items) >= $this->itemLimit) { - break; - } - } - } - - public function getURI() - { - switch ($this->queriedContext) { - case 'All News': - return self::URI . 'news'; - break; - case 'All Opinion': - return self::URI . 'people'; - break; - case 'By Tag': - return self::URI . $this->getInput('content') . '/?theme=' . $this->getInput('tag'); - case 'By Region': - return self::URI . $this->getInput('content') . '/?region=' . $this->getInput('region'); - break; - case 'By Author': - return self::URI . 'profile/?id=' . $this->getInput('profileId'); - break; - default: - return parent::getURI(); - } - } - - public function getName() - { - switch ($this->queriedContext) { - case 'All News': - return 'News - Openly'; - break; - case 'All Opinion': - return 'Opinion - Openly'; - break; - case 'By Tag': - if (empty($this->feedTitle)) { - $this->feedTitle = $this->getInput('tag'); - } - - if ($this->getInput('content') === 'people') { - return $this->feedTitle . ' - Opinion - Openly'; - } - - return $this->feedTitle . ' - Openly'; - break; - case 'By Region': - if (empty($this->feedTitle)) { - $this->feedTitle = $this->getInput('region'); - } - - if ($this->getInput('content') === 'people') { - return $this->feedTitle . ' - Opinion - Openly'; - } - - return $this->feedTitle . ' - Openly'; - break; - case 'By Author': - if (empty($this->feedTitle)) { - $this->feedTitle = $this->getInput('profileId'); - } - - return $this->feedTitle . ' - Author - Openly'; - break; - default: - return parent::getName(); - } - } - - private function getAjaxURI() - { - $part = '/ajax.html?'; - - switch ($this->queriedContext) { - case 'All News': - return self::URI . 'news' . $part; - break; - case 'All Opinion': - return self::URI . 'people' . $part; - break; - case 'By Tag': - return self::URI . $this->getInput('content') . $part . 'theme=' . $this->getInput('tag'); - break; - case 'By Region': - return self::URI . $this->getInput('content') . $part . 'region=' . $this->getInput('region'); - break; - } - } - - private function getArticle($url) - { - $article = getSimpleHTMLDOMCached($url, self::ARTICLE_CACHE_TIMEOUT); - $article = defaultLinkTo($article, $this->getURI()); - - $item = []; - $item['title'] = $article->find('h1', 0)->plaintext; - $item['uri'] = $url; - $item['content'] = $article->find('div.body-text', 0); - $item['enclosures'][] = $article->find('meta[name="twitter:image"]', 0)->content; - $item['timestamp'] = $article->find('div.meta.small', 0)->plaintext; - - if ($article->find('div.meta a', 0)) { - $item['author'] = $article->find('div.meta a', 0)->plaintext; - } - - foreach ($article->find('div.themes li') as $li) { - $item['categories'][] = trim(htmlspecialchars($li->plaintext, ENT_QUOTES)); - } - - return $item; - } -} diff --git a/bridges/PaulGrahamBridge.php b/bridges/PaulGrahamBridge.php new file mode 100644 index 00000000..928eea35 --- /dev/null +++ b/bridges/PaulGrahamBridge.php @@ -0,0 +1,95 @@ +find('body table'); + if (!isset($tables[0])) { + return; + } + + $tds = $tables[0]->find('td'); + if (!isset($tds[2])) { + return; + } + + $contentTd = $tds[2]; + + // Find all inner tables (each one holds a single essay link) + $essayTables = $contentTd->find('table'); + if (!isset($essayTables[1])) { + return; + } + + $essayTable = $essayTables[1]; + + // /html/body/table/tbody/tr/td[3]/table[2]/tbody/tr[2]/td/font/a + + $links = $essayTable->find('font'); + + $essayLinks = []; + foreach ($links as $t) { + $link = $t->find('a', 0); + if (!$link) { + continue; + } + + $href = trim($link->href); + $title = trim($link->plaintext); + + if (empty($href) || strpos($href, 'http') === 0 || !preg_match('/\.html$/', $href)) { + continue; + } + + $essayLinks[] = [ + 'title' => $title, + 'url' => 'https://www.paulgraham.com/' . $href, + ]; + } + + // Only fetch the first 10 (in display order) + $essayLinks = array_slice($essayLinks, 0, 10); + + foreach ($essayLinks as $essay) { + $item = [ + 'uri' => $essay['url'], + 'title' => $essay['title'], + 'uid' => $essay['url'], + 'content' => '', + ]; + + $essayHtml = getSimpleHTMLDOMCached($essay['url']); + if ($essayHtml) { + $essayTables = $essayHtml->find('body table'); + if (isset($essayTables[0])) { + $essayTds = $essayTables[0]->find('td'); + if (isset($essayTds[2])) { + $mainContent = $essayTds[2]->innertext; + $mainDom = str_get_html($mainContent); + + // Strip unwanted layout elements + foreach ($mainDom->find('map, img, script') as $el) { + $el->outertext = ''; + } + + $item['content'] = $mainDom->save(); + } + } + } + + $this->items[] = $item; + } + } +} + diff --git a/bridges/TelegramBridge.php b/bridges/TelegramBridge.php index 54a089bc..0a3f1a74 100644 --- a/bridges/TelegramBridge.php +++ b/bridges/TelegramBridge.php @@ -104,7 +104,7 @@ class TelegramBridge extends BridgeAbstract $notSupported = $messageDiv->find('div.message_media_not_supported_wrap', 0); if ($notSupported) { // For unknown reasons, the telegram preview page omits the content of this post - $message = 'RSS-Bridge was unable to find the content of this post.

' . $notSupported->innertext; + $message = (string) $notSupported->innertext; } if ($messageDiv->find('div.tgme_widget_message_forwarded_from', 0)) { diff --git a/lib/CacheFactory.php b/lib/CacheFactory.php index 47bbbf72..50d8cef9 100644 --- a/lib/CacheFactory.php +++ b/lib/CacheFactory.php @@ -92,6 +92,7 @@ class CacheFactory if (empty($port)) { throw new \Exception('"port" param is not set for ' . $section); } + $port = (string) $port; if (!ctype_digit($port)) { throw new \Exception('"port" param is invalid for ' . $section); } diff --git a/lib/Configuration.php b/lib/Configuration.php index 60bf80fb..79f2922c 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -7,7 +7,7 @@ */ final class Configuration { - private const VERSION = '2025-01-26'; + private const VERSION = '2025-06-03'; private static $config = [];