aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2025-10-17 12:54:00 +0200
committerGravatar GitHub <noreply@github.com> 2025-10-17 12:54:00 +0200
commit1ef354a63e7a9de98f90961acb7d45f1d9aa893e (patch)
tree9ddd160a21b16a464a6f3943656f0ced81d71fe7
parentfbbb5a5e204755a3835383316fdd87ecdfd98d2b (diff)
GReader API frss:priority (#7583)
* GReader API frss:priority Experiment with a FreshRSS namespace in the GReader API to see whether there is any interest. fix https://github.com/FreshRSS/FreshRSS/issues/1868 `'frss:priority'` can be: `'important'`, `'main'`, `'category'`, `'feed'` (there is also the value `hidden`, but which is filtered out and as such never sent through the API at the moment) * Add visibility feed https://github.com/FreshRSS/FreshRSS/pull/7972
-rw-r--r--app/Models/Entry.php8
-rw-r--r--app/Models/EntryDAO.php8
-rw-r--r--p/api/greader.php39
3 files changed, 44 insertions, 11 deletions
diff --git a/app/Models/Entry.php b/app/Models/Entry.php
index ea124794a..d4f5016f0 100644
--- a/app/Models/Entry.php
+++ b/app/Models/Entry.php
@@ -1212,6 +1212,14 @@ HTML;
} elseif ($mode === 'freshrss') {
$item['origin']['feedUrl'] = htmlspecialchars_decode($feed->url());
}
+ if ($feed->priority() >= FreshRSS_Feed::PRIORITY_MAIN_STREAM) {
+ $item['categories'][] = 'user/-/state/org.freshrss/main';
+ if ($feed->priority() >= FreshRSS_Feed::PRIORITY_IMPORTANT) {
+ $item['categories'][] = 'user/-/state/org.freshrss/important';
+ }
+ } elseif ($feed->priority() <= FreshRSS_Feed::PRIORITY_HIDDEN) {
+ $item['categories'][] = 'user/-/state/org.freshrss/hidden';
+ }
}
foreach ($this->enclosures() as $enclosure) {
if (!empty($enclosure['url'])) {
diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php
index 6f60fb13f..d456b7711 100644
--- a/app/Models/EntryDAO.php
+++ b/app/Models/EntryDAO.php
@@ -1368,7 +1368,7 @@ SQL;
}
/**
- * @param 'a'|'A'|'i'|'s'|'S'|'c'|'f'|'t'|'T'|'ST'|'Z' $type
+ * @param 'a'|'A'|'c'|'f'|'i'|'s'|'S'|'ST'|'t'|'T'|'Z' $type
* @param int $id category/feed/tag ID
* @param numeric-string $id_min
* @param numeric-string $id_max
@@ -1462,7 +1462,7 @@ SQL;
}
/**
- * @param 'a'|'A'|'s'|'S'|'i'|'c'|'f'|'t'|'T'|'ST'|'Z' $type
+ * @param 'a'|'A'|'c'|'f'|'i'|'s'|'S'|'ST'|'t'|'T'|'Z' $type
* @param int $id category/feed/tag ID
* @param numeric-string $id_min
* @param numeric-string $id_max
@@ -1526,7 +1526,7 @@ SQL;
}
/**
- * @param 'a'|'A'|'s'|'S'|'i'|'c'|'f'|'t'|'T'|'ST'|'Z' $type
+ * @param 'a'|'A'|'c'|'f'|'i'|'s'|'S'|'ST'|'t'|'T'|'Z' $type
* @param int $id category/feed/tag ID
* @param numeric-string $id_min
* @param numeric-string $id_max
@@ -1595,7 +1595,7 @@ SQL;
}
/**
- * @param 'a'|'A'|'s'|'S'|'c'|'f'|'t'|'T'|'ST'|'Z' $type
+ * @param 'a'|'A'|'c'|'f'|'i'|'s'|'S'|'ST'|'t'|'T'|'Z' $type
* @param int $id category/feed/tag ID
* @param numeric-string $id_min
* @param numeric-string $id_max
diff --git a/p/api/greader.php b/p/api/greader.php
index bcf127986..fb2ea03f5 100644
--- a/p/api/greader.php
+++ b/p/api/greader.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
== Description ==
Server-side API compatible with Google Reader API layer 2
for the FreshRSS project https://freshrss.org
+FreshRSS-specific information is prefixed with 'frss:'
== Credits ==
* 2014-03: Released by Alexandre Alapetite https://alexandre.alapetite.fr
@@ -281,6 +282,10 @@ final class GReaderAPI {
$tags = [
['id' => 'user/-/state/com.google/starred'],
// ['id' => 'user/-/state/com.google/broadcast', 'sortid' => '2']
+ ['id' => 'user/-/state/com.google/reading-list'],
+ ['id' => 'user/-/state/org.freshrss/main'],
+ ['id' => 'user/-/state/org.freshrss/important'],
+ // ['id' => 'user/-/state/org.freshrss/hidden'],
];
$categoryDAO = FreshRSS_Factory::createCategoryDao();
$categories = $categoryDAO->listCategories(prePopulateFeeds: false, details: false);
@@ -359,6 +364,14 @@ final class GReaderAPI {
'iconUrl' => str_replace(
'/api/greader.php/reader/api/0/subscription', '', // Security if base_url is not set properly
$feed->favicon(absolute: true)),
+ 'frss:priority' => match ($feed->priority()) {
+ FreshRSS_Feed::PRIORITY_IMPORTANT => 'important',
+ FreshRSS_Feed::PRIORITY_MAIN_STREAM => 'main',
+ FreshRSS_Feed::PRIORITY_CATEGORY => 'category',
+ FreshRSS_Feed::PRIORITY_FEED => 'feed',
+ // FreshRSS_Feed::PRIORITY_HIDDEN => 'hidden', // Not returned by the API
+ default => 'main',
+ },
];
}
}
@@ -590,8 +603,8 @@ final class GReaderAPI {
}
/**
- * @param 'A'|'c'|'f'|'s' $type
- * @return array{'A'|'c'|'f'|'s'|'t',int,int,FreshRSS_BooleanSearch}
+ * @param 'A'|'a'|'c'|'f'|'i'|'s' $type
+ * @return array{'A'|'a'|'c'|'f'|'i'|'s'|'t',int,int,FreshRSS_BooleanSearch}
*/
private static function streamContentsFilters(string $type, int|string $streamId,
string $filter_target, string $exclude_target, int $start_time, int $stop_time): array {
@@ -672,6 +685,8 @@ final class GReaderAPI {
'feed' => 'f',
'label' => 'c',
'reading-list' => 'A', // All except PRIORITY_HIDDEN
+ 'main' => 'a',
+ 'important' => 'i',
default => 'A',
};
@@ -753,6 +768,12 @@ TXT;
} elseif ($streamId === 'user/-/state/com.google/starred') {
$type = 's';
$streamId = '';
+ } elseif ($streamId === 'user/-/state/org.freshrss/main') {
+ $type = 'a';
+ $streamId = '';
+ } elseif ($streamId === 'user/-/state/org.freshrss/important') {
+ $type = 'i';
+ $streamId = '';
} elseif ($streamId === 'user/-/state/com.google/read') {
$filter_target = $streamId;
$type = 'A';
@@ -1030,13 +1051,17 @@ TXT;
}
}
} elseif ($streamId === 'user/-/state/com.google/reading-list') {
- $entryDAO->markReadEntries($olderThanId, onlyFavorites: false);
+ $entryDAO->markReadEntries($olderThanId, priorityMin: FreshRSS_Feed::PRIORITY_HIDDEN + 1);
} elseif ($streamId === 'user/-/state/com.google/starred') {
- $entryDAO->markReadEntries($olderThanId, onlyFavorites: true);
+ $entryDAO->markReadEntries($olderThanId, onlyFavorites: true, priorityMin: FreshRSS_Feed::PRIORITY_HIDDEN + 1);
+ } elseif ($streamId === 'user/-/state/org.freshrss/main') {
+ $entryDAO->markReadEntries($olderThanId, priorityMin: FreshRSS_Feed::PRIORITY_MAIN_STREAM);
+ } elseif ($streamId === 'user/-/state/org.freshrss/important') {
+ $entryDAO->markReadEntries($olderThanId, priorityMin: FreshRSS_Feed::PRIORITY_IMPORTANT);
} elseif ($streamId === 'user/-/state/com.google/read') {
$entryDAO->markReadEntries($olderThanId, state: FreshRSS_Entry::STATE_READ);
} elseif ($streamId === 'user/-/state/com.google/unread') {
- $entryDAO->markReadEntries($olderThanId, state: FreshRSS_Entry::STATE_NOT_READ);
+ $entryDAO->markReadEntries($olderThanId, state: FreshRSS_Entry::STATE_NOT_READ, priorityMin: FreshRSS_Feed::PRIORITY_HIDDEN + 1);
} else {
self::badRequest();
}
@@ -1161,8 +1186,8 @@ TXT;
$count, $order, $filter_target, $exclude_target, $continuation);
} elseif (isset($pathInfos[8], $pathInfos[9]) && $pathInfos[6] === 'user') {
if ($pathInfos[8] === 'state') {
- if ($pathInfos[9] === 'com.google' && isset($pathInfos[10])) {
- if ($pathInfos[10] === 'reading-list' || $pathInfos[10] === 'starred') {
+ if (in_array($pathInfos[9], ['com.google', 'org.freshrss'], true) && isset($pathInfos[10])) {
+ if (in_array($pathInfos[10], ['reading-list', 'starred', 'main', 'important'], true)) {
$include_target = '';
self::streamContents($pathInfos[10], $include_target, $start_time, $stop_time, $count, $order,
$filter_target, $exclude_target, $continuation);