Refactoring: Rename dotpath into dotnotation (#6369)

* KIND_JSON_DOTPATH -> KIND_JSON_DOTNOTATION

* TYPE_JSON_DOTPATH => TYPE_JSON_DOTNOTATION

* json_dotpath => json_dotnotation

* dotPathsForStandardJsonFeed => dotNotationForStandardJsonFeed

* TYPE_JSON_DOTNOTATION = 'JSON+DotPath' => 'JSON+DotNotation'

* documentation: OPML.md

* convertJsonToRss()

* $dotpaths => $dotnotations

* FreshRSS_Feed_Exception

* comment

* Compatibility TYPE_JSON_DOTPATH

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
This commit is contained in:
maTh 2024-04-25 08:28:42 +02:00 committed by GitHub
parent 5e66adcc51
commit 154a36700c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 67 additions and 65 deletions

View File

@ -259,7 +259,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
if (!empty($xPathSettings)) {
$attributes['xpath'] = $xPathSettings;
}
} elseif ($feed_kind === FreshRSS_Feed::KIND_JSON_DOTPATH) {
} elseif ($feed_kind === FreshRSS_Feed::KIND_JSON_DOTNOTATION) {
$jsonSettings = [];
if (Minz_Request::paramString('jsonFeedTitle') !== '') {
$jsonSettings['feedTitle'] = Minz_Request::paramString('jsonFeedTitle', true);
@ -295,7 +295,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
$jsonSettings['itemUid'] = Minz_Request::paramString('jsonItemUid', true);
}
if (!empty($jsonSettings)) {
$attributes['json_dotpath'] = $jsonSettings;
$attributes['json_dotnotation'] = $jsonSettings;
}
}
@ -497,10 +497,10 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
if ($simplePie === null) {
throw new FreshRSS_Feed_Exception('XML+XPath parsing failed for [' . $feed->url(false) . ']');
}
} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSON_DOTPATH) {
} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSON_DOTNOTATION) {
$simplePie = $feed->loadJson();
if ($simplePie === null) {
throw new FreshRSS_Feed_Exception('JSON dotpath parsing failed for [' . $feed->url(false) . ']');
throw new FreshRSS_Feed_Exception('JSON dot notation parsing failed for [' . $feed->url(false) . ']');
}
} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSONFEED) {
$simplePie = $feed->loadJson();

View File

@ -238,7 +238,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
$xPathSettings['itemUid'] = Minz_Request::paramString('xPathItemUid', true);
if (!empty($xPathSettings))
$feed->_attribute('xpath', $xPathSettings);
} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSON_DOTPATH) {
} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSON_DOTNOTATION) {
$jsonSettings = [];
if (Minz_Request::paramString('jsonFeedTitle') !== '') {
$jsonSettings['feedTitle'] = Minz_Request::paramString('jsonFeedTitle', true);
@ -274,7 +274,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
$jsonSettings['itemUid'] = Minz_Request::paramString('jsonItemUid', true);
}
if (!empty($jsonSettings)) {
$feed->_attribute('json_dotpath', $jsonSettings);
$feed->_attribute('json_dotnotation', $jsonSettings);
}
}

View File

@ -31,7 +31,7 @@ class FreshRSS_Feed extends Minz_Model {
public const KIND_JSON_XPATH = 20;
public const KIND_JSONFEED = 25;
public const KIND_JSON_DOTPATH = 30;
public const KIND_JSON_DOTNOTATION = 30;
public const PRIORITY_IMPORTANT = 20;
public const PRIORITY_MAIN_STREAM = 10;
@ -621,7 +621,7 @@ class FreshRSS_Feed extends Minz_Model {
}
/** @return array<string,string> */
private function dotPathsForStandardJsonFeed(): array {
private function dotNotationForStandardJsonFeed(): array {
return [
'feedTitle' => 'title',
'item' => 'items',
@ -662,11 +662,11 @@ class FreshRSS_Feed extends Minz_Model {
return null;
}
/** @var array<string,string> $json_dotpath */
$json_dotpath = $this->attributeArray('json_dotpath') ?? [];
$dotPaths = $this->kind() === FreshRSS_Feed::KIND_JSONFEED ? $this->dotPathsForStandardJsonFeed() : $json_dotpath;
/** @var array<string,string> $json_dotnotation */
$json_dotnotation = $this->attributeArray('json_dotnotation') ?? [];
$dotnotations = $this->kind() === FreshRSS_Feed::KIND_JSONFEED ? $this->dotNotationForStandardJsonFeed() : $json_dotnotation;
$feedContent = FreshRSS_dotNotation_Util::convertJsonToRss($jf, $feedSourceUrl, $dotPaths, $this->name());
$feedContent = FreshRSS_dotNotation_Util::convertJsonToRss($jf, $feedSourceUrl, $dotnotations, $this->name());
if ($feedContent == null) {
return null;
}

View File

@ -20,7 +20,8 @@ class FreshRSS_Export_Service {
public const TYPE_HTML_XPATH = 'HTML+XPath';
public const TYPE_XML_XPATH = 'XML+XPath';
public const TYPE_RSS_ATOM = 'rss';
public const TYPE_JSON_DOTPATH = 'JSON+DotPath';
public const TYPE_JSON_DOTPATH = 'JSON+DotPath'; // Legacy 1.24.0-dev
public const TYPE_JSON_DOTNOTATION = 'JSON+DotNotation';
public const TYPE_JSONFEED = 'JSONFeed';
/**

View File

@ -161,8 +161,9 @@ class FreshRSS_Import_Service {
case strtolower(FreshRSS_Export_Service::TYPE_XML_XPATH):
$feed->_kind(FreshRSS_Feed::KIND_XML_XPATH);
break;
case strtolower(FreshRSS_Export_Service::TYPE_JSON_DOTNOTATION):
case strtolower(FreshRSS_Export_Service::TYPE_JSON_DOTPATH):
$feed->_kind(FreshRSS_Feed::KIND_JSON_DOTPATH);
$feed->_kind(FreshRSS_Feed::KIND_JSON_DOTNOTATION);
break;
case strtolower(FreshRSS_Export_Service::TYPE_JSONFEED):
$feed->_kind(FreshRSS_Feed::KIND_JSONFEED);
@ -254,7 +255,7 @@ class FreshRSS_Import_Service {
$jsonSettings['itemUid'] = $feed_elt['frss:jsonItemUid'];
}
if (!empty($jsonSettings)) {
$feed->_attribute('json_dotpath', $jsonSettings);
$feed->_attribute('json_dotnotation', $jsonSettings);
}
$curl_params = [];

View File

@ -97,11 +97,11 @@ final class FreshRSS_dotNotation_Util
*
* @param array<string> $jf json feed
* @param string $feedSourceUrl the source URL for the feed
* @param array<string,string> $dotPaths dot paths to map JSON into RSS
* @param string $defaultRssTitle Default title of the RSS feed, if not already provided in dotPath `feedTitle`
* @param array<string,string> $dotNotation dot notation to map JSON into RSS
* @param string $defaultRssTitle Default title of the RSS feed, if not already provided in dotNotation `feedTitle`
*/
public static function convertJsonToRss(array $jf, string $feedSourceUrl, array $dotPaths, string $defaultRssTitle = ''): ?string {
if (!isset($dotPaths['item']) || $dotPaths['item'] === '') {
public static function convertJsonToRss(array $jf, string $feedSourceUrl, array $dotNotation, string $defaultRssTitle = ''): ?string {
if (!isset($dotNotation['item']) || $dotNotation['item'] === '') {
return null; //no definition of item path, but we can't scrape anything without knowing this
}
@ -112,40 +112,40 @@ final class FreshRSS_dotNotation_Util
$view->html_url = $view->rss_url;
$view->entries = [];
$view->rss_title = isset($dotPaths['feedTitle'])
? (htmlspecialchars(FreshRSS_dotNotation_Util::getString($jf, $dotPaths['feedTitle']) ?? '', ENT_COMPAT, 'UTF-8') ?: $defaultRssTitle)
$view->rss_title = isset($dotNotation['feedTitle'])
? (htmlspecialchars(FreshRSS_dotNotation_Util::getString($jf, $dotNotation['feedTitle']) ?? '', ENT_COMPAT, 'UTF-8') ?: $defaultRssTitle)
: $defaultRssTitle;
$jsonItems = FreshRSS_dotNotation_Util::get($jf, $dotPaths['item']);
$jsonItems = FreshRSS_dotNotation_Util::get($jf, $dotNotation['item']);
if (!is_array($jsonItems) || count($jsonItems) === 0) {
return null;
}
foreach ($jsonItems as $jsonItem) {
$rssItem = [];
$rssItem['link'] = isset($dotPaths['itemUri']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemUri']) ?? '' : '';
$rssItem['link'] = isset($dotNotation['itemUri']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemUri']) ?? '' : '';
if (empty($rssItem['link'])) {
continue;
}
$rssItem['title'] = isset($dotPaths['itemTitle']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemTitle']) ?? '' : '';
$rssItem['author'] = isset($dotPaths['itemAuthor']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemAuthor']) ?? '' : '';
$rssItem['timestamp'] = isset($dotPaths['itemTimestamp']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemTimestamp']) ?? '' : '';
$rssItem['title'] = isset($dotNotation['itemTitle']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemTitle']) ?? '' : '';
$rssItem['author'] = isset($dotNotation['itemAuthor']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemAuthor']) ?? '' : '';
$rssItem['timestamp'] = isset($dotNotation['itemTimestamp']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemTimestamp']) ?? '' : '';
//get simple content, but if a path for HTML content has been provided, replace the simple content with HTML content
$rssItem['content'] = isset($dotPaths['itemContent']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemContent']) ?? '' : '';
$rssItem['content'] = isset($dotPaths['itemContentHTML'])
? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemContentHTML']) ?? ''
$rssItem['content'] = isset($dotNotation['itemContent']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemContent']) ?? '' : '';
$rssItem['content'] = isset($dotNotation['itemContentHTML'])
? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemContentHTML']) ?? ''
: $rssItem['content'];
if (isset($dotPaths['itemTimeFormat']) && is_string($dotPaths['itemTimeFormat'])) {
$dateTime = DateTime::createFromFormat($dotPaths['itemTimeFormat'], $rssItem['timestamp']);
if (isset($dotNotation['itemTimeFormat']) && is_string($dotNotation['itemTimeFormat'])) {
$dateTime = DateTime::createFromFormat($dotNotation['itemTimeFormat'], $rssItem['timestamp']);
if ($dateTime != false) {
$rssItem['timestamp'] = $dateTime->format(DateTime::ATOM);
}
}
if (isset($dotPaths['itemCategories'])) {
$jsonItemCategories = FreshRSS_dotNotation_Util::get($jsonItem, $dotPaths['itemCategories']);
if (isset($dotNotation['itemCategories'])) {
$jsonItemCategories = FreshRSS_dotNotation_Util::get($jsonItem, $dotNotation['itemCategories']);
if (is_string($jsonItemCategories) && $jsonItemCategories !== '') {
$rssItem['tags'] = [$jsonItemCategories];
} elseif (is_array($jsonItemCategories) && count($jsonItemCategories) > 0) {
@ -158,31 +158,31 @@ final class FreshRSS_dotNotation_Util
}
}
$rssItem['thumbnail'] = isset($dotPaths['itemThumbnail']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemThumbnail']) ?? '' : '';
$rssItem['thumbnail'] = isset($dotNotation['itemThumbnail']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemThumbnail']) ?? '' : '';
//Enclosures?
if (isset($dotPaths['itemAttachment'])) {
$jsonItemAttachments = FreshRSS_dotNotation_Util::get($jsonItem, $dotPaths['itemAttachment']);
if (isset($dotNotation['itemAttachment'])) {
$jsonItemAttachments = FreshRSS_dotNotation_Util::get($jsonItem, $dotNotation['itemAttachment']);
if (is_array($jsonItemAttachments) && count($jsonItemAttachments) > 0) {
$rssItem['attachments'] = [];
foreach ($jsonItemAttachments as $attachment) {
$rssAttachment = [];
$rssAttachment['url'] = isset($dotPaths['itemAttachmentUrl'])
? FreshRSS_dotNotation_Util::getString($attachment, $dotPaths['itemAttachmentUrl'])
$rssAttachment['url'] = isset($dotNotation['itemAttachmentUrl'])
? FreshRSS_dotNotation_Util::getString($attachment, $dotNotation['itemAttachmentUrl'])
: '';
$rssAttachment['type'] = isset($dotPaths['itemAttachmentType'])
? FreshRSS_dotNotation_Util::getString($attachment, $dotPaths['itemAttachmentType'])
$rssAttachment['type'] = isset($dotNotation['itemAttachmentType'])
? FreshRSS_dotNotation_Util::getString($attachment, $dotNotation['itemAttachmentType'])
: '';
$rssAttachment['length'] = isset($dotPaths['itemAttachmentLength'])
? FreshRSS_dotNotation_Util::get($attachment, $dotPaths['itemAttachmentLength'])
$rssAttachment['length'] = isset($dotNotation['itemAttachmentLength'])
? FreshRSS_dotNotation_Util::get($attachment, $dotNotation['itemAttachmentLength'])
: '';
$rssItem['attachments'][] = $rssAttachment;
}
}
}
if (isset($dotPaths['itemUid'])) {
$rssItem['guid'] = FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemUid']);
if (isset($dotNotation['itemUid'])) {
$rssItem['guid'] = FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemUid']);
}
if (empty($rssItem['guid'])) {

View File

@ -27,8 +27,8 @@ function feedsToOutlines(array $feeds, bool $excludeMutedFeeds = false): array {
case FreshRSS_Feed::KIND_XML_XPATH:
$outline['type'] = FreshRSS_Export_Service::TYPE_XML_XPATH;
break;
case FreshRSS_Feed::KIND_JSON_DOTPATH:
$outline['type'] = FreshRSS_Export_Service::TYPE_JSON_DOTPATH;
case FreshRSS_Feed::KIND_JSON_DOTNOTATION:
$outline['type'] = FreshRSS_Export_Service::TYPE_JSON_DOTNOTATION;
break;
case FreshRSS_Feed::KIND_JSONFEED:
$outline['type'] = FreshRSS_Export_Service::TYPE_JSONFEED;
@ -48,9 +48,9 @@ function feedsToOutlines(array $feeds, bool $excludeMutedFeeds = false): array {
$outline['frss:xPathItemThumbnail'] = $xPathSettings['itemThumbnail'] ?? null;
$outline['frss:xPathItemCategories'] = $xPathSettings['itemCategories'] ?? null;
$outline['frss:xPathItemUid'] = $xPathSettings['itemUid'] ?? null;
} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSON_DOTPATH) {
} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSON_DOTNOTATION) {
/** @var array<string,string> */
$jsonSettings = $feed->attributeArray('json_dotpath') ?? [];
$jsonSettings = $feed->attributeArray('json_dotnotation') ?? [];
$outline['frss:jsonItem'] = $jsonSettings['item'] ?? null;
$outline['frss:jsonItemTitle'] = $jsonSettings['itemTitle'] ?? null;
$outline['frss:jsonItemContent'] = $jsonSettings['itemContent'] ?? null;

View File

@ -413,7 +413,7 @@
<option value="<?= FreshRSS_Feed::KIND_HTML_XPATH ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_HTML_XPATH ? 'selected="selected"' : '' ?> data-show="html_xpath"><?= _t('sub.feed.kind.html_xpath') ?></option>
<option value="<?= FreshRSS_Feed::KIND_XML_XPATH ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_XML_XPATH ? 'selected="selected"' : '' ?> data-show="html_xpath"><?= _t('sub.feed.kind.xml_xpath') ?></option>
<option value="<?= FreshRSS_Feed::KIND_JSONFEED ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_JSONFEED ? 'selected="selected"' : '' ?>><?= _t('sub.feed.kind.jsonfeed') ?></option>
<option value="<?= FreshRSS_Feed::KIND_JSON_DOTPATH ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_JSON_DOTPATH ? 'selected="selected"' : '' ?> data-show="json_dotpath"><?= _t('sub.feed.kind.json_dotnotation') ?></option>
<option value="<?= FreshRSS_Feed::KIND_JSON_DOTNOTATION ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_JSON_DOTNOTATION ? 'selected="selected"' : '' ?> data-show="json_dotnotation"><?= _t('sub.feed.kind.json_dotnotation') ?></option>
</select>
</div>
</div>
@ -514,9 +514,9 @@
</div>
</fieldset>
<fieldset id="json_dotpath">
<fieldset id="json_dotnotation">
<?php
$jsonSettings = Minz_Helper::htmlspecialchars_utf8($this->feed->attributeArray('json_dotpath') ?? []);
$jsonSettings = Minz_Helper::htmlspecialchars_utf8($this->feed->attributeArray('json_dotnotation') ?? []);
?>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.json_dotnotation.help') ?></p>
<div class="form-group">

View File

@ -72,7 +72,7 @@
<option value="<?= FreshRSS_Feed::KIND_HTML_XPATH ?>" data-show="html_xpath"><?= _t('sub.feed.kind.html_xpath') ?></option>
<option value="<?= FreshRSS_Feed::KIND_XML_XPATH ?>" data-show="html_xpath"><?= _t('sub.feed.kind.xml_xpath') ?></option>
<option value="<?= FreshRSS_Feed::KIND_JSONFEED ?>"><?= _t('sub.feed.kind.jsonfeed') ?></option>
<option value="<?= FreshRSS_Feed::KIND_JSON_DOTPATH ?>" data-show="json_dotpath"><?= _t('sub.feed.kind.json_dotnotation') ?></option>
<option value="<?= FreshRSS_Feed::KIND_JSON_DOTNOTATION ?>" data-show="json_dotnotation"><?= _t('sub.feed.kind.json_dotnotation') ?></option>
</select>
</div>
</div>
@ -166,7 +166,7 @@
</div>
</div>
</fieldset>
<fieldset id="json_dotpath">
<fieldset id="json_dotnotation">
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.json_dotnotation.help') ?></p>
<div class="form-group">
<label class="group-name" for="jsonFeedTitle"><small><?= _t('sub.feed.kind.json_dotnotation.json') ?></small><br />

View File

@ -44,28 +44,28 @@ The following attributes are using similar naming conventions than [RSS-Bridge](
* `frss:xPathItemCategories`: XPath expression for extracting a list of categories (tags) from the item context.
* `frss:xPathItemUid`: XPath expression for extracting an items unique ID from the item context. If left empty, a hash is computed automatically.
### JSON+DotPath
### JSON+DotNotation
* `<outline type="JSON+DotPath" ...`: Similar to `HTML+XPath` but for JSON and using a dot/bracket syntax such as `object.object.array[2].property`.
* `<outline type="JSON+DotNotation" ...`: Similar to `HTML+XPath` but for JSON and using a dot/bracket syntax such as `object.object.array[2].property`.
* `frss:jsonItem`: JSON dot path for extracting the feed items from the source page.
* `frss:jsonItem`: JSON dot notation for extracting the feed items from the source page.
* Example: `data.items`
* `frss:jsonItemTitle`: JSON dot path for extracting the items title from the item context.
* `frss:jsonItemTitle`: JSON dot notation for extracting the items title from the item context.
* Example: `meta.title`
* `frss:jsonItemContent`: JSON dot path for extracting an items content from the item context.
* `frss:jsonItemContent`: JSON dot notation for extracting an items content from the item context.
* Example: `content`
* `frss:jsonItemUri`: JSON dot path for extracting an item link from the item context.
* `frss:jsonItemUri`: JSON dot notation for extracting an item link from the item context.
* Example: `meta.links[0]`
* `frss:jsonItemAuthor`: JSON dot path for extracting an item author from the item context.
* `frss:jsonItemTimestamp`: JSON dot path for extracting an item timestamp from the item context. The result will be parsed by [`strtotime()`](https://php.net/strtotime).
* `frss:jsonItemAuthor`: JSON dot notation for extracting an item author from the item context.
* `frss:jsonItemTimestamp`: JSON dot notation for extracting an item timestamp from the item context. The result will be parsed by [`strtotime()`](https://php.net/strtotime).
* `frss:jsonItemTimeFormat`: Date/Time format to parse the timestamp, according to [`DateTime::createFromFormat()`](https://php.net/datetime.createfromformat).
* `frss:jsonItemThumbnail`: JSON dot path for extracting an items thumbnail (image) URL from the item context.
* `frss:jsonItemCategories`: JSON dot path for extracting a list of categories (tags) from the item context.
* `frss:jsonItemUid`: JSON dot path for extracting an items unique ID from the item context. If left empty, a hash is computed automatically.
* `frss:jsonItemThumbnail`: JSON dot notation for extracting an items thumbnail (image) URL from the item context.
* `frss:jsonItemCategories`: JSON dot notation for extracting a list of categories (tags) from the item context.
* `frss:jsonItemUid`: JSON dot notation for extracting an items unique ID from the item context. If left empty, a hash is computed automatically.
### JSON Feed
* `<outline type="JSONFeed" ...`: Uses `JSON+DotPath` behind the scenes to parse a [JSON Feed](https://www.jsonfeed.org/).
* `<outline type="JSONFeed" ...`: Uses `JSON+DotNotation` behind the scenes to parse a [JSON Feed](https://www.jsonfeed.org/).
### cURL