diff options
| author | 2022-10-09 15:43:30 +0200 | |
|---|---|---|
| committer | 2022-10-09 15:43:30 +0200 | |
| commit | 648a876d77a7591eac6c4ad5f14b30988e18ce20 (patch) | |
| tree | 5832c068fd7d4d0a1fa80096849dde18a25887d4 | |
| parent | 72265c1eca41424f761246abc5a7fe84fd8bc0f9 (diff) | |
Add support for custom XPath date/time format (#4703)
* Add support for custom XPath date/time format
#fix https://github.com/FreshRSS/FreshRSS/issues/4701
Improvement of https://github.com/FreshRSS/FreshRSS/pull/4220
* Format is not XPath
* Remove TODOs in en-GB
29 files changed, 137 insertions, 32 deletions
diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 7030c27c1..09b5ed88c 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -211,6 +211,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { if (Minz_Request::param('xPathItemUri', '') != '') $xPathSettings['itemUri'] = Minz_Request::param('xPathItemUri', '', true); if (Minz_Request::param('xPathItemAuthor', '') != '') $xPathSettings['itemAuthor'] = Minz_Request::param('xPathItemAuthor', '', true); if (Minz_Request::param('xPathItemTimestamp', '') != '') $xPathSettings['itemTimestamp'] = Minz_Request::param('xPathItemTimestamp', '', true); + if (Minz_Request::param('xPathItemTimeFormat', '') != '') $xPathSettings['itemTimeFormat'] = Minz_Request::param('xPathItemTimeFormat', '', true); if (Minz_Request::param('xPathItemThumbnail', '') != '') $xPathSettings['itemThumbnail'] = Minz_Request::param('xPathItemThumbnail', '', true); if (Minz_Request::param('xPathItemCategories', '') != '') $xPathSettings['itemCategories'] = Minz_Request::param('xPathItemCategories', '', true); if (Minz_Request::param('xPathItemUid', '') != '') $xPathSettings['itemUid'] = Minz_Request::param('xPathItemUid', '', true); diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php index eab45db26..a3a55293a 100644 --- a/app/Controllers/subscriptionController.php +++ b/app/Controllers/subscriptionController.php @@ -213,6 +213,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController { if (Minz_Request::param('xPathItemUri', '') != '') $xPathSettings['itemUri'] = Minz_Request::param('xPathItemUri', '', true); if (Minz_Request::param('xPathItemAuthor', '') != '') $xPathSettings['itemAuthor'] = Minz_Request::param('xPathItemAuthor', '', true); if (Minz_Request::param('xPathItemTimestamp', '') != '') $xPathSettings['itemTimestamp'] = Minz_Request::param('xPathItemTimestamp', '', true); + if (Minz_Request::param('xPathItemTimeFormat', '') != '') $xPathSettings['itemTimeFormat'] = Minz_Request::param('xPathItemTimeFormat', '', true); if (Minz_Request::param('xPathItemThumbnail', '') != '') $xPathSettings['itemThumbnail'] = Minz_Request::param('xPathItemThumbnail', '', true); if (Minz_Request::param('xPathItemCategories', '') != '') $xPathSettings['itemCategories'] = Minz_Request::param('xPathItemCategories', '', true); if (Minz_Request::param('xPathItemUid', '') != '') $xPathSettings['itemUid'] = Minz_Request::param('xPathItemUid', '', true); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index a81f1c561..5efe55006 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -612,6 +612,7 @@ class FreshRSS_Feed extends Minz_Model { $xPathItemUri = $xPathSettings['itemUri'] ?? ''; $xPathItemAuthor = $xPathSettings['itemAuthor'] ?? ''; $xPathItemTimestamp = $xPathSettings['itemTimestamp'] ?? ''; + $xPathItemTimeFormat = $xPathSettings['itemTimeFormat'] ?? ''; $xPathItemThumbnail = $xPathSettings['itemThumbnail'] ?? ''; $xPathItemCategories = $xPathSettings['itemCategories'] ?? ''; $xPathItemUid = $xPathSettings['itemUid'] ?? ''; @@ -652,6 +653,12 @@ class FreshRSS_Feed extends Minz_Model { $item['link'] = $xPathItemUri == '' ? '' : @$xpath->evaluate('normalize-space(' . $xPathItemUri . ')', $node); $item['author'] = $xPathItemAuthor == '' ? '' : @$xpath->evaluate('normalize-space(' . $xPathItemAuthor . ')', $node); $item['timestamp'] = $xPathItemTimestamp == '' ? '' : @$xpath->evaluate('normalize-space(' . $xPathItemTimestamp . ')', $node); + if ($xPathItemTimeFormat != '') { + $dateTime = DateTime::createFromFormat($xPathItemTimeFormat, $item['timestamp'] ?? ''); + if ($dateTime != false) { + $item['timestamp'] = $dateTime->format(DateTime::ATOM); + } + } $item['thumbnail'] = $xPathItemThumbnail == '' ? '' : @$xpath->evaluate('normalize-space(' . $xPathItemThumbnail . ')', $node); if ($xPathItemCategories != '') { $itemCategories = @$xpath->query($xPathItemCategories, $node); diff --git a/app/Services/ImportService.php b/app/Services/ImportService.php index 4910e9cc4..a4ef547ba 100644 --- a/app/Services/ImportService.php +++ b/app/Services/ImportService.php @@ -174,6 +174,7 @@ class FreshRSS_Import_Service { case 'xPathItemUri': $xPathSettings['itemUri'] = $value['value']; break; case 'xPathItemAuthor': $xPathSettings['itemAuthor'] = $value['value']; break; case 'xPathItemTimestamp': $xPathSettings['itemTimestamp'] = $value['value']; break; + case 'xPathItemTimeFormat': $xPathSettings['itemTimeFormat'] = $value['value']; break; case 'xPathItemThumbnail': $xPathSettings['itemThumbnail'] = $value['value']; break; case 'xPathItemCategories': $xPathSettings['itemCategories'] = $value['value']; break; case 'xPathItemUid': $xPathSettings['itemUid'] = $value['value']; break; diff --git a/app/i18n/cz/sub.php b/app/i18n/cz/sub.php index 8734a559f..e5c2b1f1c 100644 --- a/app/i18n/cz/sub.php +++ b/app/i18n/cz/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'náhled položky', 'help' => 'Příklad: <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => 'datum položky', 'help' => 'Výsledek bude zpracován pomocí <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', diff --git a/app/i18n/de/sub.php b/app/i18n/de/sub.php index f45c8f021..a2af5bc03 100644 --- a/app/i18n/de/sub.php +++ b/app/i18n/de/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'Artikel-Vorschaubild', 'help' => 'Beispiel: <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => 'Artikel-Datum', 'help' => 'Das Ergebnis wird durch <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a> geparst', diff --git a/app/i18n/en-us/sub.php b/app/i18n/en-us/sub.php index b0c6c8a1b..8b7e17a7e 100644 --- a/app/i18n/en-us/sub.php +++ b/app/i18n/en-us/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'item thumbnail', // IGNORE 'help' => 'Example: <code>descendant::img/@src</code>', // IGNORE ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // IGNORE + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // IGNORE + ), 'item_timestamp' => array( '_' => 'item date', // IGNORE 'help' => 'The result will be parsed by <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', // IGNORE diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php index adc35d0c7..c8ee78947 100644 --- a/app/i18n/en/conf.php +++ b/app/i18n/en/conf.php @@ -68,9 +68,9 @@ return array( ), 'logs' => array( 'loglist' => array( - 'level' => 'Log Level', // TODO - 'message' => 'Log Message', // TODO - 'timestamp' => 'Timestamp', // TODO + 'level' => 'Log Level', + 'message' => 'Log Message', + 'timestamp' => 'Timestamp', ), 'pagination' => array( 'first' => 'First', @@ -139,28 +139,28 @@ return array( 'always_show_favorites' => 'Show all articles in favourites by default', 'article' => array( 'authors_date' => array( - '_' => 'Authors and date', // TODO - 'both' => 'In header and footer', // TODO - 'footer' => 'In footer', // TODO - 'header' => 'In header', // TODO - 'none' => 'None', // TODO + '_' => 'Authors and date', + 'both' => 'In header and footer', + 'footer' => 'In footer', + 'header' => 'In header', + 'none' => 'None', ), 'feed_name' => array( - 'above_title' => 'Above title/tags', // TODO - 'none' => 'None', // TODO - 'with_authors' => 'In authors and date row', // TODO + 'above_title' => 'Above title/tags', + 'none' => 'None', + 'with_authors' => 'In authors and date row', ), - 'feed_title' => 'Feed title', // TODO + 'feed_title' => 'Feed title', 'tags' => array( - '_' => 'Tags', // TODO - 'both' => 'In header and footer', // TODO - 'footer' => 'In footer', // TODO - 'header' => 'In header', // TODO - 'none' => 'None', // TODO + '_' => 'Tags', + 'both' => 'In header and footer', + 'footer' => 'In footer', + 'header' => 'In header', + 'none' => 'None', ), 'tags_max' => array( - '_' => 'Max number of tags shown', // TODO - 'help' => '0 means: show all tags and do not collapse them', // TODO + '_' => 'Max number of tags shown', + 'help' => '0 means: show all tags and do not collapse them', ), ), 'articles_per_page' => 'Number of articles per page', @@ -171,7 +171,7 @@ return array( 'display_categories_unfolded' => 'Categories to unfold', 'headline' => array( 'articles' => 'Articles: Open/Close', - 'articles_header_footer' => 'Articles: header/footer', // TODO + 'articles_header_footer' => 'Articles: header/footer', 'categories' => 'Left navigation: Categories', 'mark_as_read' => 'Mark article as read', 'misc' => 'Miscellaneous', @@ -187,7 +187,7 @@ return array( 'article_viewed' => 'when the article is viewed', 'keep_max_n_unread' => 'Max number of articles to keep unread', 'scroll' => 'while scrolling', - 'upon_gone' => 'when it is no longer in the upstream news feed', // TODO + 'upon_gone' => 'when it is no longer in the upstream news feed', 'upon_reception' => 'upon receiving the article', 'when' => 'Mark an article as read…', 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', @@ -222,7 +222,7 @@ return array( '_' => 'Sharing', 'add' => 'Add a sharing method', 'blogotext' => 'Blogotext', - 'deprecated' => 'This service is deprecated and will be removed from FreshRSS in a <a href="https://freshrss.github.io/FreshRSS/en/users/08_sharing_services.html" title="Open documentation for more information" target="_blank">future release</a>.', // TODO + 'deprecated' => 'This service is deprecated and will be removed from FreshRSS in a <a href="https://freshrss.github.io/FreshRSS/en/users/08_sharing_services.html" title="Open documentation for more information" target="_blank">future release</a>.', 'diaspora' => 'Diaspora*', 'email' => 'Email', 'facebook' => 'Facebook', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 5a6cbc9b9..c052f17fd 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -18,7 +18,7 @@ return array( 'back_to_rss_feeds' => '← Go back to your RSS feeds', 'cancel' => 'Cancel', 'create' => 'Create', - 'delete_muted_feeds' => 'Delete muted feeds', // TODO + 'delete_muted_feeds' => 'Delete muted feeds', 'demote' => 'Demote', 'disable' => 'Disable', 'empty' => 'Empty', @@ -32,7 +32,7 @@ return array( 'open_url' => 'Open URL', 'promote' => 'Promote', 'purge' => 'Purge', - 'refresh_opml' => 'Refresh OPML', // TODO + 'refresh_opml' => 'Refresh OPML', 'remove' => 'Remove', 'rename' => 'Rename', 'see_website' => 'See website', @@ -130,7 +130,7 @@ return array( 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favourites and user queries. It cannot be cancelled!', 'feedback' => array( 'body_new_articles' => 'There are %%d new articles to read on FreshRSS.', - 'body_unread_articles' => '(unread: %%d)', // TODO + 'body_unread_articles' => '(unread: %%d)', 'request_failed' => 'A request has failed, it may have been caused by internet connection problems.', 'title_new_articles' => 'FreshRSS: new articles!', ), diff --git a/app/i18n/en/sub.php b/app/i18n/en/sub.php index c5c15a435..e9b11383e 100644 --- a/app/i18n/en/sub.php +++ b/app/i18n/en/sub.php @@ -25,12 +25,12 @@ return array( 'add' => 'Add a category', 'archiving' => 'Archiving', 'dynamic_opml' => array( - '_' => 'Dynamic OPML', // TODO - 'help' => 'Provide the URL to an <a href=http://opml.org/ target=_blank>OPML file</a> to dynamically populate this category with feeds', // TODO + '_' => 'Dynamic OPML', + 'help' => 'Provide the URL to an <a href=http://opml.org/ target=_blank>OPML file</a> to dynamically populate this category with feeds', ), 'empty' => 'Empty category', 'information' => 'Information', - 'opml_url' => 'OPML URL', // TODO + 'opml_url' => 'OPML URL', 'position' => 'Display position', 'position_help' => 'To control category sort order', 'title' => 'Title', @@ -61,7 +61,7 @@ return array( 'css_path' => 'Article CSS selector on original website', 'css_path_filter' => array( '_' => 'CSS selector of the elements to remove', - 'help' => 'A CSS selector may be a list such as: <kbd>.footer, .aside</kbd>', // TODO + 'help' => 'A CSS selector may be a list such as: <kbd>.footer, .aside</kbd>', ), 'description' => 'Description', 'empty' => 'This feed is empty. Please verify that it is still maintained.', @@ -98,6 +98,10 @@ return array( '_' => 'item thumbnail', 'help' => 'Example: <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', + ), 'item_timestamp' => array( '_' => 'item date', 'help' => 'The result will be parsed by <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', @@ -107,8 +111,8 @@ return array( 'help' => 'Use in particular the <a href="https://developer.mozilla.org/docs/Web/XPath/Axes" target="_blank">XPath axis</a> <code>descendant::</code> like <code>descendant::h2</code>', ), 'item_uid' => array( - '_' => 'item unique ID', // TODO - 'help' => 'Optional. Example: <code>descendant::div/@data-uri</code>', // TODO + '_' => 'item unique ID', + 'help' => 'Optional. Example: <code>descendant::div/@data-uri</code>', ), 'item_uri' => array( '_' => 'item link (URL)', @@ -198,7 +202,7 @@ return array( '_' => 'Subscription management', 'add' => 'Add a feed or category', 'add_category' => 'Add a category', - 'add_dynamic_opml' => 'Add dynamic OPML', // TODO + 'add_dynamic_opml' => 'Add dynamic OPML', 'add_feed' => 'Add a feed', 'add_label' => 'Add a label', 'delete_label' => 'Delete a label', diff --git a/app/i18n/es/sub.php b/app/i18n/es/sub.php index 7918a9437..75bceed61 100755 --- a/app/i18n/es/sub.php +++ b/app/i18n/es/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'item thumbnail', // TODO 'help' => 'Example: <code>descendant::img/@src</code>', // TODO ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => 'item date', // TODO 'help' => 'The result will be parsed by <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', // TODO diff --git a/app/i18n/fr/sub.php b/app/i18n/fr/sub.php index f199fefbd..1d6233808 100644 --- a/app/i18n/fr/sub.php +++ b/app/i18n/fr/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'miniature de l’article', 'help' => 'Exemple : <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Format personnalisé pour interpréter la date', + 'help' => 'Optionnel. Un format supporté par <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> comme <code>d-m-Y H:i:s</code>', + ), 'item_timestamp' => array( '_' => 'date de l’article', 'help' => 'Le résultat sera passé à la fonction <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', diff --git a/app/i18n/he/sub.php b/app/i18n/he/sub.php index 033a0a7e5..748f13f0b 100644 --- a/app/i18n/he/sub.php +++ b/app/i18n/he/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'item thumbnail', // TODO 'help' => 'Example: <code>descendant::img/@src</code>', // TODO ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => 'item date', // TODO 'help' => 'The result will be parsed by <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', // TODO diff --git a/app/i18n/it/sub.php b/app/i18n/it/sub.php index 93988aa9d..b33c9c237 100644 --- a/app/i18n/it/sub.php +++ b/app/i18n/it/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'oggetto miniatura', 'help' => 'Esempio: <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => 'oggetto data', 'help' => 'Il risultato verrà analizzato da <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', diff --git a/app/i18n/ja/sub.php b/app/i18n/ja/sub.php index a6cf81bc3..9de8f07f7 100644 --- a/app/i18n/ja/sub.php +++ b/app/i18n/ja/sub.php @@ -98,6 +98,10 @@ return array( '_' => '項目のサムネイル', 'help' => '例: <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => '項目の日付', 'help' => '結果は<a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>によってパースされます', diff --git a/app/i18n/ko/sub.php b/app/i18n/ko/sub.php index ef21d9ca1..2ff0347df 100644 --- a/app/i18n/ko/sub.php +++ b/app/i18n/ko/sub.php @@ -98,6 +98,10 @@ return array( '_' => '기사 섬네일', 'help' => '예제: <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => '기사 날짜', 'help' => '결과 값은 <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>에서 파싱한 값을 이용합니다.', diff --git a/app/i18n/nl/sub.php b/app/i18n/nl/sub.php index 85a01a97a..f4f05131e 100644 --- a/app/i18n/nl/sub.php +++ b/app/i18n/nl/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'miniatuur van bericht', 'help' => 'Voorbeeld: <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => 'datum van bericht', 'help' => 'Het resultaat zal worden geparset door <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', diff --git a/app/i18n/oc/sub.php b/app/i18n/oc/sub.php index b1869f983..58bbe9ca8 100644 --- a/app/i18n/oc/sub.php +++ b/app/i18n/oc/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'item vinheta', 'help' => 'Exemple : <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => 'item data', 'help' => 'Lo resultats serà formatat per la foncion <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', diff --git a/app/i18n/pl/sub.php b/app/i18n/pl/sub.php index 54c69eb00..1abc85a94 100644 --- a/app/i18n/pl/sub.php +++ b/app/i18n/pl/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'miniaturki', 'help' => 'Przykład: <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => 'daty', 'help' => 'Wynik zostanie przetworzony za pomocą funkcji <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', diff --git a/app/i18n/pt-br/sub.php b/app/i18n/pt-br/sub.php index d8e146b77..b24f76a3b 100644 --- a/app/i18n/pt-br/sub.php +++ b/app/i18n/pt-br/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'Miniatura do item', 'help' => 'Exemplo: <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => 'Data do Item', 'help' => 'O resultado será parecido com: <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', diff --git a/app/i18n/ru/sub.php b/app/i18n/ru/sub.php index 347162296..929da0d2b 100644 --- a/app/i18n/ru/sub.php +++ b/app/i18n/ru/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'эскиза элемента', 'help' => 'Пример: <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => 'даты элемента', 'help' => 'Результат будет распарсен с <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', diff --git a/app/i18n/sk/sub.php b/app/i18n/sk/sub.php index 914d6315c..e6324d800 100644 --- a/app/i18n/sk/sub.php +++ b/app/i18n/sk/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'položka miniatúra', 'help' => 'Príklad: <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => 'položka dátum', 'help' => 'Výsledok spracuje <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', // DIRTY diff --git a/app/i18n/tr/sub.php b/app/i18n/tr/sub.php index 3fb1ff520..a77f60f0e 100644 --- a/app/i18n/tr/sub.php +++ b/app/i18n/tr/sub.php @@ -98,6 +98,10 @@ return array( '_' => 'item thumbnail', // TODO 'help' => 'Example: <code>descendant::img/@src</code>', // TODO ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => 'item date', // TODO 'help' => 'The result will be parsed by <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a>', // TODO diff --git a/app/i18n/zh-cn/sub.php b/app/i18n/zh-cn/sub.php index ad6307472..89b36ebc5 100644 --- a/app/i18n/zh-cn/sub.php +++ b/app/i18n/zh-cn/sub.php @@ -98,6 +98,10 @@ return array( '_' => '文章缩略图', 'help' => '例如 <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => '文章日期:', 'help' => '结果将被 <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a> 解析', diff --git a/app/i18n/zh-tw/sub.php b/app/i18n/zh-tw/sub.php index 8b448cfd8..8afc67716 100644 --- a/app/i18n/zh-tw/sub.php +++ b/app/i18n/zh-tw/sub.php @@ -98,6 +98,10 @@ return array( '_' => '文章縮圖', 'help' => '例如 <code>descendant::img/@src</code>', ), + 'item_timeFormat' => array( + '_' => 'Custom date/time format', // TODO + 'help' => 'Optional. A format supported by <a href="https://php.net/datetime.createfromformat" target="_blank"><code>DateTime::createFromFormat()</code></a> such as <code>d-m-Y H:i:s</code>', // TODO + ), 'item_timestamp' => array( '_' => '文章日期:', 'help' => '結果將被 <a href="https://php.net/strtotime" target="_blank"><code>strtotime()</code></a> 解析', diff --git a/app/views/helpers/export/opml.phtml b/app/views/helpers/export/opml.phtml index 677bb03b5..1ee030cdf 100644 --- a/app/views/helpers/export/opml.phtml +++ b/app/views/helpers/export/opml.phtml @@ -26,6 +26,7 @@ function feedsToOutlines($feeds, $excludeMutedFeeds = false): array { $outline['frss:xPathItemUri'] = ['namespace' => FreshRSS_Export_Service::FRSS_NAMESPACE, 'value' => $xPathSettings['itemUri'] ?? null]; $outline['frss:xPathItemAuthor'] = ['namespace' => FreshRSS_Export_Service::FRSS_NAMESPACE, 'value' => $xPathSettings['itemAuthor'] ?? null]; $outline['frss:xPathItemTimestamp'] = ['namespace' => FreshRSS_Export_Service::FRSS_NAMESPACE, 'value' => $xPathSettings['itemTimestamp'] ?? null]; + $outline['frss:xPathItemTimeformat'] = ['namespace' => FreshRSS_Export_Service::FRSS_NAMESPACE, 'value' => $xPathSettings['itemTimeformat'] ?? null]; $outline['frss:xPathItemThumbnail'] = ['namespace' => FreshRSS_Export_Service::FRSS_NAMESPACE, 'value' => $xPathSettings['itemThumbnail'] ?? null]; $outline['frss:xPathItemCategories'] = ['namespace' => FreshRSS_Export_Service::FRSS_NAMESPACE, 'value' => $xPathSettings['itemCategories'] ?? null]; $outline['frss:xPathItemUid'] = ['namespace' => FreshRSS_Export_Service::FRSS_NAMESPACE, 'value' => $xPathSettings['itemUid'] ?? null]; diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index 80782fc57..12437d8f0 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -466,6 +466,15 @@ </div> </div> <div class="form-group"> + <label class="group-name" for="xPathItemTimeFormat"><small> + <?= _t('sub.feed.kind.html_xpath.item_timeFormat') ?></label> + <div class="group-controls"> + <textarea class="w100" name="xPathItemTimeFormat" id="xPathItemTimeFormat" rows="2" cols="64" spellcheck="false" + data-leave-validation="<?= $xpath['itemTimeFormat'] ?? '' ?>"><?= $xpath['itemTimeFormat'] ?? '' ?></textarea> + <p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_xpath.item_timeFormat.help') ?></p> + </div> + </div> + <div class="form-group"> <label class="group-name" for="xPathItemCategories"><small><?= _t('sub.feed.kind.html_xpath.relative') ?></small><br /> <?= _t('sub.feed.kind.html_xpath.item_categories') ?></label> <div class="group-controls"> diff --git a/app/views/subscription/add.phtml b/app/views/subscription/add.phtml index a2b7f1289..800093bed 100644 --- a/app/views/subscription/add.phtml +++ b/app/views/subscription/add.phtml @@ -141,6 +141,14 @@ </div> </div> <div class="form-group"> + <label class="group-name" for="xPathItemTimeFormat"> + <?= _t('sub.feed.kind.html_xpath.item_timeFormat') ?></label> + <div class="group-controls"> + <textarea name="xPathItemTimeFormat" id="xPathItemTimeFormat" rows="2" cols="64" spellcheck="false"></textarea> + <p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_xpath.item_timeFormat.help') ?></p> + </div> + </div> + <div class="form-group"> <label class="group-name" for="xPathItemCategories"><small><?= _t('sub.feed.kind.html_xpath.relative') ?></small><br /> <?= _t('sub.feed.kind.html_xpath.item_categories') ?></label> <div class="group-controls"> diff --git a/docs/en/developers/OPML.md b/docs/en/developers/OPML.md index 859d99c72..2190a1de3 100644 --- a/docs/en/developers/OPML.md +++ b/docs/en/developers/OPML.md @@ -36,6 +36,7 @@ The following attributes are using similar naming conventions than [RSS-Bridge]( * `frss:xPathItemAuthor`: XPath expression for extracting an item author from the item context. * Example: `"Anonymous"` * `frss:xPathItemTimestamp`: XPath expression for extracting an item timestamp from the item context. The result will be parsed by [`strtotime()`](https://php.net/strtotime). +* `frss:xPathItemTimeFormat`: Date/Time format to parse the timestamp, according to [`DateTime::createFromFormat()`](https://php.net/datetime.createfromformat). * `frss:xPathItemThumbnail`: XPath expression for extracting an item’s thumbnail (image) URL from the item context. * Example: `descendant::img/@src` * `frss:xPathItemCategories`: XPath expression for extracting a list of categories (tags) from the item context. |
