aboutsummaryrefslogtreecommitdiff
path: root/app/Models/Category.php
diff options
context:
space:
mode:
authorGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2022-07-04 09:53:26 +0200
committerGravatar GitHub <noreply@github.com> 2022-07-04 09:53:26 +0200
commit509c8cae6381ec46af7c8303eb92fda6ce496a4a (patch)
tree653f7f44df842f9d7135decd89467879a0098c50 /app/Models/Category.php
parent57d571230eeb2d3ede57e640b640f17c7a2298a2 (diff)
Dynamic OPML (#4407)
* Dynamic OPML draft #fix https://github.com/FreshRSS/FreshRSS/issues/4191 * Export dynamic OPML http://opml.org/spec2.opml#1629043127000 * Restart with simpler approach * Minor revert * Export dynamic OPML also for single feeds * Special category type for importing dynamic OPML * Parameter for excludeMutedFeeds * Details * More draft * i18n * Fix update * Draft manual import working * Working manual refresh * Draft automatic update * Working Web refresh + fixes * Import/export dynamic OPML settings * Annoying numerous lines in SQL logs * Fix minor JavaScript error * Fix auto adding new columns * Add require * Add missing 🗲 * Missing space * Disable adding new feeds to dynamic categories * Link from import * i18n typo * Improve theme icon function * Fix pink-dark
Diffstat (limited to 'app/Models/Category.php')
-rw-r--r--app/Models/Category.php136
1 files changed, 131 insertions, 5 deletions
diff --git a/app/Models/Category.php b/app/Models/Category.php
index b67818e19..d75d7e21e 100644
--- a/app/Models/Category.php
+++ b/app/Models/Category.php
@@ -1,17 +1,38 @@
<?php
class FreshRSS_Category extends Minz_Model {
+
+ /**
+ * Normal
+ * @var int
+ */
+ const KIND_NORMAL = 0;
+
+ /**
+ * Category tracking a third-party Dynamic OPML
+ * @var int
+ */
+ const KIND_DYNAMIC_OPML = 2;
+
+ const TTL_DEFAULT = 0;
+
/**
* @var int
*/
private $id = 0;
+ /** @var int */
+ private $kind = 0;
private $name;
private $nbFeeds = -1;
private $nbNotRead = -1;
+ /** @var array<FreshRSS_Feed>|null */
private $feeds = null;
private $hasFeedsWithError = false;
- private $isDefault = false;
private $attributes = [];
+ /** @var int */
+ private $lastUpdate = 0;
+ /** @var bool */
+ private $error = false;
public function __construct(string $name = '', $feeds = null) {
$this->_name($name);
@@ -30,11 +51,26 @@ class FreshRSS_Category extends Minz_Model {
public function id(): int {
return $this->id;
}
+ public function kind(): int {
+ return $this->kind;
+ }
public function name(): string {
return $this->name;
}
+ public function lastUpdate(): int {
+ return $this->lastUpdate;
+ }
+ public function _lastUpdate(int $value) {
+ $this->lastUpdate = $value;
+ }
+ public function inError(): bool {
+ return $this->error;
+ }
+ public function _error($value) {
+ $this->error = (bool)$value;
+ }
public function isDefault(): bool {
- return $this->isDefault;
+ return $this->id == FreshRSS_CategoryDAO::DEFAULTCATEGORYID;
}
public function nbFeeds(): int {
if ($this->nbFeeds < 0) {
@@ -52,6 +88,8 @@ class FreshRSS_Category extends Minz_Model {
return $this->nbNotRead;
}
+
+ /** @return array<FreshRSS_Feed> */
public function feeds(): array {
if ($this->feeds === null) {
$feedDAO = FreshRSS_Factory::createFeedDao();
@@ -90,12 +128,15 @@ class FreshRSS_Category extends Minz_Model {
$this->_name(_t('gen.short.default_category'));
}
}
+
+ public function _kind(int $kind) {
+ $this->kind = $kind;
+ }
+
public function _name($value) {
$this->name = mb_strcut(trim($value), 0, 255, 'UTF-8');
}
- public function _isDefault($value) {
- $this->isDefault = $value;
- }
+ /** @param array<FreshRSS_Feed>|FreshRSS_Feed $values */
public function _feeds($values) {
if (!is_array($values)) {
$values = array($values);
@@ -104,6 +145,17 @@ class FreshRSS_Category extends Minz_Model {
$this->feeds = $values;
}
+ /**
+ * To manually add feeds to this category (not committing to database).
+ * @param FreshRSS_Feed $feed
+ */
+ public function addFeed($feed) {
+ if ($this->feeds === null) {
+ $this->feeds = [];
+ }
+ $this->feeds[] = $feed;
+ }
+
public function _attributes($key, $value) {
if ('' == $key) {
if (is_string($value)) {
@@ -118,4 +170,78 @@ class FreshRSS_Category extends Minz_Model {
$this->attributes[$key] = $value;
}
}
+
+ public static function cacheFilename(string $url, array $attributes): string {
+ $simplePie = customSimplePie($attributes);
+ $filename = $simplePie->get_cache_filename($url);
+ return CACHE_PATH . '/' . $filename . '.opml.xml';
+ }
+
+ public function refreshDynamicOpml(): bool {
+ $url = $this->attributes('opml_url');
+ if ($url == '') {
+ return false;
+ }
+ $ok = true;
+ $attributes = []; //TODO
+ $cachePath = self::cacheFilename($url, $attributes);
+ $opml = httpGet($url, $cachePath, 'opml', $attributes);
+ if ($opml == '') {
+ Minz_Log::warning('Error getting dynamic OPML for category ' . $this->id() . '! ' .
+ SimplePie_Misc::url_remove_credentials($url));
+ $ok = false;
+ } else {
+ $dryRunCategory = new FreshRSS_Category();
+ $importService = new FreshRSS_Import_Service();
+ $importService->importOpml($opml, $dryRunCategory, true, true);
+ if ($importService->lastStatus()) {
+ $feedDAO = FreshRSS_Factory::createFeedDao();
+
+ /** @var array<string,FreshRSS_Feed> */
+ $dryRunFeeds = [];
+ foreach ($dryRunCategory->feeds() as $dryRunFeed) {
+ $dryRunFeeds[$dryRunFeed->url()] = $dryRunFeed;
+ }
+
+ /** @var array<string,FreshRSS_Feed> */
+ $existingFeeds = [];
+ foreach ($this->feeds() as $existingFeed) {
+ $existingFeeds[$existingFeed->url()] = $existingFeed;
+ if (empty($dryRunFeeds[$existingFeed->url()])) {
+ // The feed does not exist in the new dynamic OPML, so mute (disable) that feed
+ $existingFeed->_mute(true);
+ $ok &= ($feedDAO->updateFeed($existingFeed->id(), [
+ 'ttl' => $existingFeed->ttl(true),
+ ]) !== false);
+ }
+ }
+
+ foreach ($dryRunCategory->feeds() as $dryRunFeed) {
+ if (empty($existingFeeds[$dryRunFeed->url()])) {
+ // The feed does not exist in the current category, so add that feed
+ $dryRunFeed->_category($this->id());
+ $ok &= ($feedDAO->addFeedObject($dryRunFeed) !== false);
+ } else {
+ $existingFeed = $existingFeeds[$dryRunFeed->url()];
+ if ($existingFeed->mute()) {
+ // The feed already exists in the current category but was muted (disabled), so unmute (enable) again
+ $existingFeed->_mute(false);
+ $ok &= ($feedDAO->updateFeed($existingFeed->id(), [
+ 'ttl' => $existingFeed->ttl(true),
+ ]) !== false);
+ }
+ }
+ }
+ } else {
+ $ok = false;
+ Minz_Log::warning('Error loading dynamic OPML for category ' . $this->id() . '! ' .
+ SimplePie_Misc::url_remove_credentials($url));
+ }
+ }
+
+ $catDAO = FreshRSS_Factory::createCategoryDao();
+ $catDAO->updateLastUpdate($this->id(), !$ok);
+
+ return $ok;
+ }
}