diff options
| -rwxr-xr-x | app/Controllers/feedController.php | 5 | ||||
| -rw-r--r-- | app/Controllers/importExportController.php | 25 | ||||
| -rw-r--r-- | app/Controllers/subscriptionController.php | 2 | ||||
| -rw-r--r-- | app/Models/Category.php | 2 | ||||
| -rw-r--r-- | app/Models/CategoryDAO.php | 2 | ||||
| -rw-r--r-- | app/Models/Context.php | 2 | ||||
| -rw-r--r-- | app/Models/Entry.php | 148 | ||||
| -rw-r--r-- | app/Models/EntryDAO.php | 11 | ||||
| -rw-r--r-- | app/Models/Feed.php | 35 | ||||
| -rw-r--r-- | app/Models/FeedDAO.php | 24 | ||||
| -rw-r--r-- | app/Models/TagDAO.php | 2 | ||||
| -rw-r--r-- | app/Models/View.php | 2 | ||||
| -rw-r--r-- | app/Services/ExportService.php | 18 | ||||
| -rw-r--r-- | app/Services/ImportService.php | 2 | ||||
| -rw-r--r-- | app/views/helpers/export/articles.phtml | 49 | ||||
| -rw-r--r-- | app/views/helpers/feed/update.phtml | 2 | ||||
| -rw-r--r-- | app/views/index/normal.phtml | 4 | ||||
| -rw-r--r-- | app/views/index/reader.phtml | 8 | ||||
| -rw-r--r-- | p/api/fever.php | 4 | ||||
| -rw-r--r-- | p/api/greader.php | 86 |
20 files changed, 232 insertions, 201 deletions
diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 0699844d8..31875fa56 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -74,7 +74,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { $feed->_kind($kind); $feed->_attributes('', $attributes); $feed->_httpAuth($http_auth); - $feed->_category($cat_id); + $feed->_categoryId($cat_id); switch ($kind) { case FreshRSS_Feed::KIND_RSS: case FreshRSS_Feed::KIND_RSS_FORCED: @@ -425,6 +425,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { //Minz_Log::debug('Entry with GUID `' . $entry->guid() . '` updated in feed ' . $feed->url(false) . //', old hash ' . $existingHash . ', new hash ' . $entry->hash()); $entry->_isRead($mark_updated_article_unread ? false : null); //Change is_read according to policy. + $entry->_isFavorite(null); // Do not change favourite state /** @var FreshRSS_Entry|null */ $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); @@ -908,7 +909,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { } //Get feed. - $feed = $entry->feed(true); + $feed = $entry->feed(); if (!$feed) { $this->view->fatalError = _t('feedback.sub.feed.selector_preview.no_feed'); diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 8402e840d..a1e1106c1 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -249,6 +249,7 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { 'feedUrl' => isset($item['feed_url']) ? $item['feed_url'] : '', ); $item['id'] = isset($item['guid']) ? $item['guid'] : (isset($item['feed_url']) ? $item['feed_url'] : $item['published']); + $item['guid'] = $item['id']; $table['items'][$i] = $item; } return json_encode($table); @@ -284,7 +285,10 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { // First, we check feeds of articles are in DB (and add them if needed). foreach ($items as $item) { - if (empty($item['id'])) { + if (!isset($item['guid']) && isset($item['id'])) { + $item['guid'] = $item['id']; + } + if (empty($item['guid'])) { continue; } if (empty($item['origin'])) { @@ -326,11 +330,11 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { } if ($feed != null) { - $article_to_feed[$item['id']] = $feed->id(); + $article_to_feed[$item['guid']] = $feed->id(); if (!isset($newFeedGuids['f_' . $feed->id()])) { $newFeedGuids['f_' . $feed->id()] = array(); } - $newFeedGuids['f_' . $feed->id()][] = safe_ascii($item['id']); + $newFeedGuids['f_' . $feed->id()][] = safe_ascii($item['guid']); } } @@ -354,14 +358,14 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { $newGuids = array(); $this->entryDAO->beginTransaction(); foreach ($items as $item) { - if (empty($item['id']) || empty($article_to_feed[$item['id']])) { + if (empty($item['guid']) || empty($article_to_feed[$item['guid']])) { // Related feed does not exist for this entry, do nothing. continue; } - $feed_id = $article_to_feed[$item['id']]; + $feed_id = $article_to_feed[$item['guid']]; $author = isset($item['author']) ? $item['author'] : ''; - $is_starred = false; + $is_starred = null; // null is used to preserve the current state if that item exists and is already starred $is_read = null; $tags = empty($item['categories']) ? array() : $item['categories']; $labels = array(); @@ -429,7 +433,7 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { } $entry = new FreshRSS_Entry( - $feed_id, $item['id'], $title, $author, + $feed_id, $item['guid'], $title, $author, $content, $url, $published, $is_read, $is_starred ); $entry->_id(uTimeString()); @@ -463,7 +467,7 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { } $knownLabels[$labelName]['articles'][] = array( //'id' => $entry->id(), //ID changes after commitNewEntries() - 'id_feed' => $entry->feed(), + 'id_feed' => $entry->feedId(), 'guid' => $entry->guid(), ); } @@ -480,6 +484,9 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { $this->entryDAO->beginTransaction(); foreach ($knownLabels as $labelName => $knownLabel) { $labelId = $knownLabel['id']; + if (!$labelId) { + continue; + } foreach ($knownLabel['articles'] as $article) { $entryId = $this->entryDAO->searchIdByGuid($article['id_feed'], $article['guid']); if ($entryId != null) { @@ -521,7 +528,7 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { try { // Create a Feed object and add it in database. $feed = new FreshRSS_Feed($url); - $feed->_category(FreshRSS_CategoryDAO::DEFAULTCATEGORYID); + $feed->_categoryId(FreshRSS_CategoryDAO::DEFAULTCATEGORYID); $feed->_name($name); $feed->_website($website); if (!empty($origin['disable'])) { diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php index cdf30b378..b699e9213 100644 --- a/app/Controllers/subscriptionController.php +++ b/app/Controllers/subscriptionController.php @@ -244,7 +244,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController { } if ($feedDAO->updateFeed($id, $values) !== false) { - $feed->_category($cat); + $feed->_categoryId($cat); $feed->faviconPrepare(); Minz_Request::good(_t('feedback.sub.feed.updated'), $url_redirect); diff --git a/app/Models/Category.php b/app/Models/Category.php index d75d7e21e..e5da764d3 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -219,7 +219,7 @@ class FreshRSS_Category extends Minz_Model { 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()); + $dryRunFeed->_categoryId($this->id()); $ok &= ($feedDAO->addFeedObject($dryRunFeed) !== false); } else { $existingFeed = $existingFeeds[$dryRunFeed->url()]; diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index cef8e6d63..e9b873d72 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -108,7 +108,7 @@ SQL; $valuesTmp['name'], ); - if ($stm && $stm->execute($values)) { + if ($stm && $stm->execute($values) && $stm->rowCount() > 0) { return $this->pdo->lastInsertId('`_category_id_seq`'); } else { $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo(); diff --git a/app/Models/Context.php b/app/Models/Context.php index ab855966b..db8dd1f09 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -299,7 +299,7 @@ class FreshRSS_Context { } } self::$current_get['feed'] = $id; - self::$current_get['category'] = $feed->category(); + self::$current_get['category'] = $feed->categoryId(); self::$name = $feed->name(); self::$description = $feed->description(); self::$get_unread = $feed->nbNotRead(); diff --git a/app/Models/Entry.php b/app/Models/Entry.php index 72e59e38c..e383f9060 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -31,6 +31,7 @@ class FreshRSS_Entry extends Minz_Model { * @var bool|null */ private $is_read; + /** @var bool|null */ private $is_favorite; /** @@ -213,17 +214,22 @@ class FreshRSS_Entry extends Minz_Model { public function isFavorite() { return $this->is_favorite; } - public function feed($object = false) { - if ($object) { - if ($this->feed == null) { - $feedDAO = FreshRSS_Factory::createFeedDao(); - $this->feed = $feedDAO->searchById($this->feedId); - } - return $this->feed; - } else { - return $this->feedId; + + /** + * @return FreshRSS_Feed|null|false + */ + public function feed() { + if ($this->feed === null) { + $feedDAO = FreshRSS_Factory::createFeedDao(); + $this->feed = $feedDAO->searchById($this->feedId); } + return $this->feed; } + + public function feedId(): int { + return $this->feedId; + } + public function tags($asString = false) { if ($asString) { return $this->tags == null ? '' : '#' . implode(' #', $this->tags); @@ -331,18 +337,21 @@ class FreshRSS_Entry extends Minz_Model { $this->is_read = $value === null ? null : (bool)$value; } public function _isFavorite($value) { - $this->is_favorite = $value; + $this->is_favorite = $value === null ? null : (bool)$value; } - public function _feed($value) { - if ($value != null) { - $this->feed = $value; - $this->feedId = $this->feed->id(); - } + + /** @param FreshRSS_Feed|null $feed */ + public function _feed($feed) { + $this->feed = $feed; + $this->feedId = $this->feed == null ? 0 : $this->feed->id(); } - private function _feedId($value) { + + /** @param int|string $id */ + private function _feedId($id) { $this->feed = null; - $this->feedId = intval($value); + $this->feedId = intval($id); } + public function _tags($value) { $this->hash = ''; if (!is_array($value)) { @@ -558,7 +567,7 @@ class FreshRSS_Entry extends Minz_Model { public function loadCompleteContent(bool $force = false): bool { // Gestion du contenu // Trying to fetch full article content even when feeds do not propose it - $feed = $this->feed(true); + $feed = $this->feed(); if ($feed != null && trim($feed->pathEntries()) != '') { $entryDAO = FreshRSS_Factory::createEntryDao(); $entry = $force ? null : $entryDAO->searchByGuid($this->feedId, $this->guid); @@ -613,9 +622,110 @@ class FreshRSS_Entry extends Minz_Model { 'hash' => $this->hash(), 'is_read' => $this->isRead(), 'is_favorite' => $this->isFavorite(), - 'id_feed' => $this->feed(), + 'id_feed' => $this->feedId(), 'tags' => $this->tags(true), 'attributes' => $this->attributes(), ); } + + /** + * Integer format conversion for Google Reader API format + * @param string|int $dec Decimal number + * @return string 64-bit hexa http://code.google.com/p/google-reader-api/wiki/ItemId + */ + private static function dec2hex($dec): string { + return PHP_INT_SIZE < 8 ? // 32-bit ? + str_pad(gmp_strval(gmp_init($dec, 10), 16), 16, '0', STR_PAD_LEFT) : + str_pad(dechex($dec), 16, '0', STR_PAD_LEFT); + } + + /** + * N.B.: To avoid expensive lookups, ensure to set `$entry->_feed($feed)` before calling this function. + * N.B.: You might have to populate `$entry->_tags()` prior to calling this function. + * @param string $mode Set to `'compat'` to use an alternative Unicode representation for problematic HTML special characters not decoded by some clients; + * set to `'freshrss'` for using FreshRSS additions for internal use (e.g. export/import). + * @return array<string,mixed> A representation of this entry in a format compatible with Google Reader API + */ + public function toGReader(string $mode = ''): array { + + $feed = $this->feed(); + $category = $feed == null ? null : $feed->category(); + + $item = [ + 'id' => 'tag:google.com,2005:reader/item/' . self::dec2hex($this->id()), + 'crawlTimeMsec' => substr($this->dateAdded(true, true), 0, -3), + 'timestampUsec' => '' . $this->dateAdded(true, true), //EasyRSS & Reeder + 'published' => $this->date(true), + // 'updated' => $this->date(true), + 'title' => $this->title(), + 'summary' => ['content' => $this->content()], + 'canonical' => [ + ['href' => htmlspecialchars_decode($this->link(), ENT_QUOTES)], + ], + 'alternate' => [ + [ + 'href' => htmlspecialchars_decode($this->link(), ENT_QUOTES), + 'type' => 'text/html', + ], + ], + 'categories' => [ + 'user/-/state/com.google/reading-list', + ], + 'origin' => [ + 'streamId' => 'feed/' . $this->feedId, + ], + ]; + if ($mode === 'compat') { + $item['title'] = escapeToUnicodeAlternative($this->title(), false); + } elseif ($mode === 'freshrss') { + $item['guid'] = $this->guid(); + unset($item['summary']); + $item['content'] = ['content' => $this->content()]; + } + if ($category != null && $mode !== 'freshrss') { + $item['categories'][] = 'user/-/label/' . htmlspecialchars_decode($category->name(), ENT_QUOTES); + } + if ($feed != null) { + $item['origin']['htmlUrl'] = htmlspecialchars_decode($feed->website()); + $item['origin']['title'] = $feed->name(); //EasyRSS + if ($mode === 'compat') { + $item['origin']['title'] = escapeToUnicodeAlternative($feed->name(), true); + } elseif ($mode === 'freshrss') { + $item['origin']['feedUrl'] = htmlspecialchars_decode($feed->url()); + } + } + foreach ($this->enclosures() as $enclosure) { + if (!empty($enclosure['url']) && !empty($enclosure['type'])) { + $media = [ + 'href' => $enclosure['url'], + 'type' => $enclosure['type'], + ]; + if (!empty($enclosure['length'])) { + $media['length'] = intval($enclosure['length']); + } + $item['enclosure'][] = $media; + } + } + $author = $this->authors(true); + $author = trim($author, '; '); + if ($author != '') { + if ($mode === 'compat') { + $item['author'] = escapeToUnicodeAlternative($author, false); + } else { + $item['author'] = $author; + } + } + if ($this->isRead()) { + $item['categories'][] = 'user/-/state/com.google/read'; + } elseif ($mode === 'freshrss') { + $item['categories'][] = 'user/-/state/com.google/unread'; + } + if ($this->isFavorite()) { + $item['categories'][] = 'user/-/state/com.google/starred'; + } + foreach ($this->tags() as $tagName) { + $item['categories'][] = 'user/-/label/' . htmlspecialchars_decode($tagName, ENT_QUOTES); + } + return $item; + } } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 5faaac1fb..d69702c60 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -218,6 +218,9 @@ SQL; if (!isset($valuesTmp['is_read'])) { $valuesTmp['is_read'] = null; } + if (!isset($valuesTmp['is_favorite'])) { + $valuesTmp['is_favorite'] = null; + } if ($this->updateEntryPrepared === null) { $sql = 'UPDATE `_entry` ' @@ -226,6 +229,7 @@ SQL; . ', link=:link, date=:date, `lastSeen`=:last_seen' . ', hash=' . static::sqlHexDecode(':hash') . ', is_read=COALESCE(:is_read, is_read)' + . ', is_favorite=COALESCE(:is_favorite, is_favorite)' . ', tags=:tags, attributes=:attributes ' . 'WHERE id_feed=:id_feed AND guid=:guid'; $this->updateEntryPrepared = $this->pdo->prepare($sql); @@ -254,6 +258,11 @@ SQL; } else { $this->updateEntryPrepared->bindValue(':is_read', $valuesTmp['is_read'] ? 1 : 0, PDO::PARAM_INT); } + if ($valuesTmp['is_favorite'] === null) { + $this->updateEntryPrepared->bindValue(':is_favorite', null, PDO::PARAM_NULL); + } else { + $this->updateEntryPrepared->bindValue(':is_favorite', $valuesTmp['is_favorite'] ? 1 : 0, PDO::PARAM_INT); + } $this->updateEntryPrepared->bindParam(':id_feed', $valuesTmp['id_feed'], PDO::PARAM_INT); $valuesTmp['tags'] = mb_strcut($valuesTmp['tags'], 0, 1023, 'UTF-8'); $valuesTmp['tags'] = safe_utf8($valuesTmp['tags']); @@ -1102,7 +1111,7 @@ SQL; . ($limit > 0 ? ' LIMIT ' . intval($limit) : '')); //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ } - public function listWhereRaw($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, + private function listWhereRaw($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filters = null, $date_min = 0) { list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filters, $date_min); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index e39109b49..4de61167b 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -39,7 +39,9 @@ class FreshRSS_Feed extends Minz_Model { /** @var int */ private $kind = 0; /** @var int */ - private $category = 1; + private $categoryId = 1; + /** @var FreshRSS_Category|null */ + private $category; /** @var int */ private $nbEntries = -1; /** @var int */ @@ -119,9 +121,22 @@ class FreshRSS_Feed extends Minz_Model { public function hubUrl(): string { return $this->hubUrl; } - public function category(): int { + + /** + * @return FreshRSS_Category|null|false + */ + public function category() { + if ($this->category === null) { + $catDAO = FreshRSS_Factory::createCategoryDao(); + $this->category = $catDAO->searchById($this->categoryId); + } return $this->category; } + + public function categoryId(): int { + return $this->categoryId; + } + public function entries() { Minz_Log::warning(__method__ . ' is deprecated since FreshRSS 1.16.1!'); $simplePie = $this->load(false, true); @@ -253,10 +268,16 @@ class FreshRSS_Feed extends Minz_Model { $this->kind = $value; } - /** @param int $value */ - public function _category($value) { - $value = intval($value); - $this->category = $value >= 0 ? $value : 0; + /** @param FreshRSS_Category|null $cat */ + public function _category($cat) { + $this->category = $cat; + $this->categoryId = $this->category == null ? 0 : $this->category->id(); + } + + /** @param int|string $id */ + public function _categoryId($id) { + $this->category = null; + $this->categoryId = intval($id); } public function _name(string $value) { @@ -700,7 +721,7 @@ class FreshRSS_Feed extends Minz_Model { $archiving = $this->attributes('archiving'); if ($archiving == null) { $catDAO = FreshRSS_Factory::createCategoryDao(); - $category = $catDAO->searchById($this->category()); + $category = $catDAO->searchById($this->categoryId); $archiving = $category == null ? null : $category->attributes('archiving'); if ($archiving == null) { $archiving = FreshRSS_Context::$user_conf->archiving; diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 8d54e7be2..233d2a715 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -82,7 +82,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { 'id' => $feed->id(), 'url' => $feed->url(), 'kind' => $feed->kind(), - 'category' => $feed->category(), + 'category' => $feed->categoryId(), 'name' => $feed->name(), 'website' => $feed->website(), 'description' => $feed->description(), @@ -341,26 +341,6 @@ SQL; } /** - * For API - */ - public function arrayFeedCategoryNames(): array { - $sql = <<<'SQL' -SELECT f.id, f.name, c.name as c_name FROM `_feed` f -INNER JOIN `_category` c ON c.id = f.category -SQL; - $stm = $this->pdo->query($sql); - $res = $stm->fetchAll(PDO::FETCH_ASSOC); - $feedCategoryNames = array(); - foreach ($res as $line) { - $feedCategoryNames[$line['id']] = array( - 'name' => $line['name'], - 'c_name' => $line['c_name'], - ); - } - return $feedCategoryNames; - } - - /** * Use $defaultCacheDuration == -1 to return all feeds, without filtering them by TTL. * @return array<FreshRSS_Feed> */ @@ -596,7 +576,7 @@ SQL; $myFeed = new FreshRSS_Feed($dao['url'] ?? '', false); $myFeed->_kind($dao['kind'] ?? FreshRSS_Feed::KIND_RSS); - $myFeed->_category($category); + $myFeed->_categoryId($category); $myFeed->_name($dao['name']); $myFeed->_website($dao['website'] ?? '', false); $myFeed->_description($dao['description'] ?? ''); diff --git a/app/Models/TagDAO.php b/app/Models/TagDAO.php index 49abbdefd..f232b2f9f 100644 --- a/app/Models/TagDAO.php +++ b/app/Models/TagDAO.php @@ -61,7 +61,7 @@ SQL; $valuesTmp['name'], ); - if ($stm && $stm->execute($values)) { + if ($stm && $stm->execute($values) && $stm->rowCount() > 0) { return $this->pdo->lastInsertId('`_tag_id_seq`'); } else { $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo(); diff --git a/app/Models/View.php b/app/Models/View.php index 0169f130a..ab1780405 100644 --- a/app/Models/View.php +++ b/app/Models/View.php @@ -72,8 +72,6 @@ class FreshRSS_View extends Minz_View { // Export / Import public $content; - public $entriesRaw; - public $entriesId; public $entryIdsTagNames; public $list_title; public $queryId; diff --git a/app/Services/ExportService.php b/app/Services/ExportService.php index b5630f57f..ad0f5f5a8 100644 --- a/app/Services/ExportService.php +++ b/app/Services/ExportService.php @@ -71,17 +71,17 @@ class FreshRSS_Export_Service { */ public function generateStarredEntries($type) { $view = new FreshRSS_View(); - $view->categories = $this->category_dao->listCategories(); + $view->categories = $this->category_dao->listCategories(true); $day = date('Y-m-d'); $view->list_title = _t('sub.import_export.starred_list'); $view->type = 'starred'; - $view->entriesId = $this->entry_dao->listIdsWhere( + $entriesId = $this->entry_dao->listIdsWhere( $type, '', FreshRSS_Entry::STATE_ALL, 'ASC', -1 ); - $view->entryIdsTagNames = $this->tag_dao->getEntryIdsTagNames($view->entriesId); + $view->entryIdsTagNames = $this->tag_dao->getEntryIdsTagNames($entriesId); // The following is a streamable query, i.e. must be last - $view->entriesRaw = $this->entry_dao->listWhereRaw( + $view->entries = $this->entry_dao->listWhere( $type, '', FreshRSS_Entry::STATE_ALL, 'ASC', -1 ); @@ -107,19 +107,19 @@ class FreshRSS_Export_Service { } $view = new FreshRSS_View(); - $view->categories = $this->category_dao->listCategories(); + $view->categories = $this->category_dao->listCategories(true); $view->feed = $feed; $day = date('Y-m-d'); - $filename = "feed_{$day}_" . $feed->category() . '_' . $feed->id() . '.json'; + $filename = "feed_{$day}_" . $feed->categoryId() . '_' . $feed->id() . '.json'; $view->list_title = _t('sub.import_export.feed_list', $feed->name()); $view->type = 'feed/' . $feed->id(); - $view->entriesId = $this->entry_dao->listIdsWhere( + $entriesId = $this->entry_dao->listIdsWhere( 'f', $feed->id(), FreshRSS_Entry::STATE_ALL, 'ASC', $max_number_entries ); - $view->entryIdsTagNames = $this->tag_dao->getEntryIdsTagNames($view->entriesId); + $view->entryIdsTagNames = $this->tag_dao->getEntryIdsTagNames($entriesId); // The following is a streamable query, i.e. must be last - $view->entriesRaw = $this->entry_dao->listWhereRaw( + $view->entries = $this->entry_dao->listWhere( 'f', $feed->id(), FreshRSS_Entry::STATE_ALL, 'ASC', $max_number_entries ); diff --git a/app/Services/ImportService.php b/app/Services/ImportService.php index 4cd866377..3fde32bb0 100644 --- a/app/Services/ImportService.php +++ b/app/Services/ImportService.php @@ -148,7 +148,7 @@ class FreshRSS_Import_Service { try { // Create a Feed object and add it in DB $feed = new FreshRSS_Feed($url); - $feed->_category($parent_cat->id()); + $feed->_categoryId($parent_cat->id()); $parent_cat->addFeed($feed); $feed->_name($name); $feed->_website($website); diff --git a/app/views/helpers/export/articles.phtml b/app/views/helpers/export/articles.phtml index ad5210968..fd95ff741 100644 --- a/app/views/helpers/export/articles.phtml +++ b/app/views/helpers/export/articles.phtml @@ -18,51 +18,20 @@ if (empty($this->entryIdsTagNames)) { $this->entryIdsTagNames = array(); } -foreach ($this->entriesRaw as $entryRaw) { - if ($entryRaw == null) { +foreach ($this->entries as $entry) { + if ($entry == null) { continue; } - $entry = FreshRSS_Entry::fromArray($entryRaw); - if (!isset($this->feed)) { - $feed = FreshRSS_CategoryDAO::findFeed($this->categories, $entry->feed()); - if ($feed === null) { - $feed = $entry->feed(true); - } - } else { - $feed = $this->feed; - } - $article = array( - 'id' => $entry->guid(), - 'timestampUsec' => '' . $entry->id(), - 'categories' => array_values($entry->tags()), - 'title' => $entry->title(), - 'author' => $entry->authors(true), - 'published' => $entry->date(true), - 'updated' => $entry->date(true), - 'alternate' => array(array( - 'href' => htmlspecialchars_decode($entry->link(), ENT_QUOTES), - 'type' => 'text/html', - )), - 'content' => array( - 'content' => $entry->content(), - ), - 'origin' => array( - 'streamId' => $feed == null ? '' : $feed->id(), - 'title' => $feed == null ? '' : $feed->name(), - 'htmlUrl' => $feed == null ? '' : $feed->website(), - 'feedUrl' => $feed == null ? '' : $feed->url(), - ) - ); - $article['categories'][] = $entry->isRead() ? 'user/-/state/com.google/read' : 'user/-/state/com.google/unread'; - if ($entry->isFavorite()) { - $article['categories'][] = 'user/-/state/com.google/starred'; - } - $tagNames = isset($this->entryIdsTagNames['e_' . $entry->id()]) ? $this->entryIdsTagNames['e_' . $entry->id()] : array(); - foreach ($tagNames as $tagName) { - $article['categories'][] = 'user/-/label/' . $tagName; + $feed = $this->feed ?? FreshRSS_CategoryDAO::findFeed($this->categories, $entry->feedId()); + $entry->_feed($feed); + + if (isset($this->entryIdsTagNames['e_' . $entry->id()])) { + $entry->_tags($this->entryIdsTagNames['e_' . $entry->id()]); } + $article = $entry->toGReader('freshrss'); + $line = json_encode($article, $options); if ($line != '') { if ($first) { diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index 6f6044463..1e9e9afd2 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -69,7 +69,7 @@ <div class="group-controls"> <select name="category" id="category" class="w100"> <?php foreach ($this->categories as $cat) { ?> - <option value="<?= $cat->id() ?>"<?= $cat->id() == $this->feed->category() ? ' selected="selected"' : '' ?>> + <option value="<?= $cat->id() ?>"<?= $cat->id() == $this->feed->categoryId() ? ' selected="selected"' : '' ?>> <?= $cat->name() ?> </option> <?php } ?> diff --git a/app/views/index/normal.phtml b/app/views/index/normal.phtml index 348a42e89..6a4cb77eb 100644 --- a/app/views/index/normal.phtml +++ b/app/views/index/normal.phtml @@ -37,9 +37,9 @@ $today = @strtotime('today'); $this->entry = $item; // We most likely already have the feed object in cache - $this->feed = FreshRSS_CategoryDAO::findFeed($this->categories, $this->entry->feed()); + $this->feed = FreshRSS_CategoryDAO::findFeed($this->categories, $this->entry->feedId()); if ($this->feed == null) { - $this->feed = $this->entry->feed(true); + $this->feed = $this->entry->feed(); if ($this->feed == null) { $this->feed = FreshRSS_Feed::example(); } diff --git a/app/views/index/reader.phtml b/app/views/index/reader.phtml index c9ef7fbd9..334cd4189 100644 --- a/app/views/index/reader.phtml +++ b/app/views/index/reader.phtml @@ -47,12 +47,12 @@ $MAX_TAGS_DISPLAYED = FreshRSS_Context::$user_conf->show_tags_max; } ?><div class="flux<?= !$item->isRead() ? ' not_read' : '' ?><?= $item->isFavorite() ? ' favorite' : '' ?>" id="flux_<?= $item->id() ?>"> <article class="flux_content" dir="auto"> - + <div class="content <?= $content_width ?>"> <header> <?php - $feed = FreshRSS_CategoryDAO::findFeed($this->categories, $item->feed()); //We most likely already have the feed object in cache - if (empty($feed)) $feed = $item->feed(true); + $feed = FreshRSS_CategoryDAO::findFeed($this->categories, $item->feedId()); //We most likely already have the feed object in cache + if ($feed == null) $feed = $item->feed(); $favoriteUrl = array('c' => 'entry', 'a' => 'bookmark', 'params' => array('id' => $item->id())); if ($item->isFavorite()) { $favoriteUrl['params']['is_favorite'] = 0; @@ -134,7 +134,7 @@ $MAX_TAGS_DISPLAYED = FreshRSS_Context::$user_conf->show_tags_max; </div> <?php } ?> </header> - + <div class="text"> <?= $item->content() ?> </div> diff --git a/p/api/fever.php b/p/api/fever.php index d7d4ca603..b7f9b9167 100644 --- a/p/api/fever.php +++ b/p/api/fever.php @@ -365,7 +365,7 @@ class FeverAPI /** @var FreshRSS_Feed $feed */ foreach ($myFeeds as $feed) { - $ids[$feed->category()][] = $feed->id(); + $ids[$feed->categoryId()][] = $feed->id(); } foreach($ids as $category => $feedIds) { @@ -493,7 +493,7 @@ class FeverAPI } $items[] = array( 'id' => '' . $entry->id(), - 'feed_id' => $entry->feed(false), + 'feed_id' => $entry->feedId(), 'title' => escapeToUnicodeAlternative($entry->title(), false), 'author' => escapeToUnicodeAlternative(trim($entry->authors(true), '; '), false), 'html' => $entry->content(), diff --git a/p/api/greader.php b/p/api/greader.php index 9a96823d7..1ceb68f0d 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -30,13 +30,6 @@ $ORIGINAL_INPUT = file_get_contents('php://input', false, null, 0, 1048576); if (PHP_INT_SIZE < 8) { //32-bit /** - * @param string|int $dec - * @return string - */ - function dec2hex($dec) { - return str_pad(gmp_strval(gmp_init($dec, 10), 16), 16, '0', STR_PAD_LEFT); - } - /** * @param string $hex * @return string */ @@ -46,14 +39,6 @@ if (PHP_INT_SIZE < 8) { //32-bit } } else { //64-bit /** - * @param string|int $dec - * @return string - */ - function dec2hex($dec) { - //http://code.google.com/p/google-reader-api/wiki/ItemId - return str_pad(dechex($dec), 16, '0', STR_PAD_LEFT); - } - /** * @param string $hex * @return string */ @@ -526,8 +511,9 @@ function entriesToArray($entries) { if (empty($entries)) { return array(); } - $feedDAO = FreshRSS_Factory::createFeedDao(); - $arrayFeedCategoryNames = $feedDAO->arrayFeedCategoryNames(); + $catDAO = FreshRSS_Factory::createCategoryDao(); + $categories = $catDAO->listCategories(true); + $tagDAO = FreshRSS_Factory::createTagDao(); $entryIdsTagNames = $tagDAO->getEntryIdsTagNames($entries); if ($entryIdsTagNames == false) { @@ -541,65 +527,15 @@ function entriesToArray($entries) { if ($entry == null) { continue; } - $f_id = $entry->feed(); - if (isset($arrayFeedCategoryNames[$f_id])) { - $c_name = $arrayFeedCategoryNames[$f_id]['c_name']; - $f_name = $arrayFeedCategoryNames[$f_id]['name']; - } else { - $c_name = '_'; - $f_name = '_'; - } - $item = array( - 'id' => 'tag:google.com,2005:reader/item/' . dec2hex($entry->id()), //64-bit hexa http://code.google.com/p/google-reader-api/wiki/ItemId - 'crawlTimeMsec' => substr($entry->dateAdded(true, true), 0, -3), - 'timestampUsec' => '' . $entry->dateAdded(true, true), //EasyRSS & Reeder - 'published' => $entry->date(true), - 'title' => escapeToUnicodeAlternative($entry->title(), false), - 'summary' => array('content' => $entry->content()), - 'canonical' => array( - array('href' => htmlspecialchars_decode($entry->link(), ENT_QUOTES)), - ), - 'alternate' => array( - array('href' => htmlspecialchars_decode($entry->link(), ENT_QUOTES)), - ), - 'categories' => array( - 'user/-/state/com.google/reading-list', - 'user/-/label/' . htmlspecialchars_decode($c_name, ENT_QUOTES), - ), - 'origin' => array( - 'streamId' => 'feed/' . $f_id, - 'title' => escapeToUnicodeAlternative($f_name, true), //EasyRSS - //'htmlUrl' => $line['f_website'], - ), - ); - foreach ($entry->enclosures() as $enclosure) { - if (!empty($enclosure['url']) && !empty($enclosure['type'])) { - $media = [ - 'href' => $enclosure['url'], - 'type' => $enclosure['type'], - ]; - if (!empty($enclosure['length'])) { - $media['length'] = intval($enclosure['length']); - } - $item['enclosure'][] = $media; - } - } - $author = $entry->authors(true); - $author = trim($author, '; '); - if ($author != '') { - $item['author'] = escapeToUnicodeAlternative($author, false); - } - if ($entry->isRead()) { - $item['categories'][] = 'user/-/state/com.google/read'; - } - if ($entry->isFavorite()) { - $item['categories'][] = 'user/-/state/com.google/starred'; - } - $tagNames = isset($entryIdsTagNames['e_' . $entry->id()]) ? $entryIdsTagNames['e_' . $entry->id()] : array(); - foreach ($tagNames as $tagName) { - $item['categories'][] = 'user/-/label/' . htmlspecialchars_decode($tagName, ENT_QUOTES); + + $feed = FreshRSS_CategoryDAO::findFeed($categories, $entry->feedId()); + $entry->_feed($feed); + + if (isset($entryIdsTagNames['e_' . $entry->id()])) { + $entry->_tags($entryIdsTagNames['e_' . $entry->id()]); } - $items[] = $item; + + $items[] = $entry->toGReader('compat'); } return $items; } |
