From d65c834a6fb8afa1afc12f6bbb47afa93ae54099 Mon Sep 17 00:00:00 2001 From: Jaidyn Ann Date: Thu, 6 May 2021 16:28:29 -0500 Subject: [PATCH] Refactor into a 'Source'-based structure --- Makefile | 1 - Makefile-Daemon | 3 - src/App.cpp | 6 +- src/AtomFeed.cpp | 140 ------------- src/AtomFeed.h | 27 --- src/Entry.cpp | 18 +- src/Entry.h | 4 +- src/Feed.cpp | 328 +++++++++---------------------- src/Feed.h | 59 +++--- src/FeedController.cpp | 92 +++------ src/FeedController.h | 4 +- src/FeedEditWindow.cpp | 65 ++----- src/FeedEditWindow.h | 5 +- src/FeedListItem.cpp | 8 +- src/FeedListItem.h | 4 +- src/FeedSource.cpp | 8 - src/FeedSource.h | 7 +- src/FeedsView.cpp | 13 +- src/LocalSource.cpp | 432 +++++++++++++++++++++++++++++++++++++++-- src/LocalSource.h | 39 +++- src/RssFeed.cpp | 111 ----------- src/RssFeed.h | 26 --- 22 files changed, 639 insertions(+), 761 deletions(-) delete mode 100644 src/AtomFeed.cpp delete mode 100644 src/AtomFeed.h delete mode 100644 src/FeedSource.cpp delete mode 100644 src/RssFeed.cpp delete mode 100644 src/RssFeed.h diff --git a/Makefile b/Makefile index d6be5dd..947c4c4 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,6 @@ SRCS = \ src/Feed.cpp \ src/FeedEditWindow.cpp \ src/FeedListItem.cpp \ - src/FeedSource.cpp \ src/FeedsView.cpp \ src/LocalSource.cpp \ src/MainWindow.cpp \ diff --git a/Makefile-Daemon b/Makefile-Daemon index 47859b7..0af3bcb 100644 --- a/Makefile-Daemon +++ b/Makefile-Daemon @@ -29,17 +29,14 @@ APP_MIME_SIG = application/x-vnd.PoggerDaemon # same name (source.c or source.cpp) are included from different directories. # Also note that spaces in folder names do not work well with this Makefile. SRCS = \ - src/AtomFeed.cpp \ src/Daemon.cpp \ src/DeskbarView.cpp \ src/Entry.cpp \ src/Feed.cpp \ src/FeedController.cpp \ - src/FeedSource.cpp \ src/LocalSource.cpp \ src/Notifier.cpp \ src/Preferences.cpp \ - src/RssFeed.cpp \ src/Util.cpp # Specify the resource definition files to use. Full or relative paths can be diff --git a/src/App.cpp b/src/App.cpp index 0827057..9a59f5e 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -10,7 +10,6 @@ #include #include -#include "AtomFeed.h" #include "Entry.h" #include "Feed.h" #include "FeedController.h" @@ -20,7 +19,6 @@ #include "Mimetypes.h" #include "Notifier.h" #include "Preferences.h" -#include "RssFeed.h" #include "Util.h" @@ -158,7 +156,9 @@ App::_OpenSourceFile(BMessage* refMessage) { entry_ref entryRef; refMessage->FindRef("refs", &entryRef); - FeedEditWindow* window = new FeedEditWindow(BEntry(&entryRef)); + BPath path(&entryRef); + + FeedEditWindow* window = new FeedEditWindow(BString(path.Path())); } diff --git a/src/AtomFeed.cpp b/src/AtomFeed.cpp deleted file mode 100644 index b14edd7..0000000 --- a/src/AtomFeed.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2020, Jaidyn Levesque - * All rights reserved. Distributed under the terms of the MIT license. - */ - -#include "AtomFeed.h" - -#include - -#include - -#include - -#include "App.h" -#include "Entry.h" -#include "Util.h" - - -#undef B_TRANSLATION_CONTEXT -#define B_TRANSLATION_CONTEXT "AtomFeed" - - -AtomFeed::AtomFeed() -{ - fTitle = BString(""); - fCachePath = BString(""); -} - - -AtomFeed::AtomFeed(Feed* feed) - : AtomFeed::AtomFeed() -{ - SetTitle(feed->Title()); - SetXmlUrl(feed->XmlUrl()); - SetCachePath(feed->CachePath()); -} - - -void -AtomFeed::Parse() -{ - fEntries = BObjectList(5, true); - tinyxml2::XMLDocument xml; - xml.LoadFile(CachePath().String()); - - Feed::Parse(); - - tinyxml2::XMLElement* xfeed = xml.FirstChildElement("feed"); - - RootParse(xfeed); - ParseEntries(xfeed); - - Filetize(); -} - - -void -AtomFeed::RootParse(tinyxml2::XMLElement* xfeed) -{ - tinyxml2::XMLElement* xentry = xfeed->FirstChildElement("entry"); - - bool set = false; - - _SetTitle(xfeed->FirstChildElement("title")); - - set = _SetDate(xfeed->FirstChildElement("updated")); - if (!set) - set = _SetDate(xfeed->FirstChildElement("published")); - if (!set && xentry) - set = _SetDate(xentry->FirstChildElement("updated")); - if (!set && xentry) - set = _SetDate(xentry->FirstChildElement("published")); - - BString logString(B_TRANSLATE("Channel '%source%' at %url%:\n")); - logString.ReplaceAll("%source%", fTitle.String()); - logString.ReplaceAll("%url%", fXmlUrl.UrlString()); - - std::cout << logString.String(); -} - - -void -AtomFeed::EntryParse(tinyxml2::XMLElement* xentry) -{ - Entry* newEntry = new Entry(); - - tinyxml2::XMLElement* xcontent = xentry->FirstChildElement("content"); - tinyxml2::XMLElement* xmedia = xentry->FirstChildElement("media:group"); - tinyxml2::XMLPrinter xprinter; - - newEntry->SetTitle(xentry->FirstChildElement("title")); - newEntry->SetPostUrl(xentry->FirstChildElement("link")->Attribute("href")); - newEntry->SetFeedTitle(fTitle); - - bool set = false; - set = newEntry->SetDescription(xentry->FirstChildElement("summary")); - if (!set) - set = newEntry->SetDescription(xentry->FirstChildElement("description")); - if (!set && xmedia) - set = newEntry->SetDescription( - xmedia->FirstChildElement("media:description")); - - set = newEntry->SetDate(xentry->FirstChildElement("updated")); - if (!set) - set = newEntry->SetDate(xentry->FirstChildElement("published")); - - if (fDate == NULL || fDate < newEntry->Date()) - _SetDate(newEntry->Date()); - - if (xcontent) { - xcontent->Accept(&xprinter); - newEntry->SetContent(xprinter.CStr()); - } - - _AddEntry(newEntry); -} - - -void -AtomFeed::ParseEntries(tinyxml2::XMLElement* xfeed) -{ - tinyxml2::XMLElement* xentry; - - xentry = xfeed->FirstChildElement("entry"); - - int entryCount = _XmlCountSiblings(xentry, "entry"); - fEntries = BObjectList(entryCount, true); - - BString logString(B_TRANSLATE("\t-%count% entries-\n")); - BString entryStr; - entryStr << entryCount; - logString.ReplaceAll("%count%", entryStr); - - std::cout << logString.String(); - - while (xentry) { - EntryParse(xentry); - xentry = xentry->NextSiblingElement("entry"); - } -} diff --git a/src/AtomFeed.h b/src/AtomFeed.h deleted file mode 100644 index 7f64171..0000000 --- a/src/AtomFeed.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2020, Jaidyn Levesque - * All rights reserved. Distributed under the terms of the MIT license. - */ -#ifndef ATOM_FEED_H -#define ATOM_FEED_H - - -#include - -#include "Feed.h" - - -class AtomFeed: public Feed { -public: - AtomFeed(); - AtomFeed(Feed*); - - void Parse(); - void RootParse(tinyxml2::XMLElement*); - void EntryParse(tinyxml2::XMLElement*); - void ParseEntries(tinyxml2::XMLElement*); -}; - - -#endif - diff --git a/src/Entry.cpp b/src/Entry.cpp index e47bf62..9093227 100644 --- a/src/Entry.cpp +++ b/src/Entry.cpp @@ -192,24 +192,10 @@ Entry::Date() bool -Entry::SetDate(const char* dateStr) +Entry::SetDate(BDateTime date) { - if (dateStr == NULL) - return false; - BDateTime newDate = feedDateToBDate(dateStr); - if (newDate == NULL) - return false; - fDate = newDate; + fDate = date; return true; } -bool -Entry::SetDate(tinyxml2::XMLElement* elem) -{ - if (elem != NULL) - return SetDate(elem->GetText()); - return false; -} - - diff --git a/src/Entry.h b/src/Entry.h index 53a54a8..dfdc996 100644 --- a/src/Entry.h +++ b/src/Entry.h @@ -42,9 +42,7 @@ public: bool SetPostUrl(tinyxml2::XMLElement*); BDateTime Date(); - bool SetDate(const char*); - bool SetDate(tinyxml2::XMLElement*); - + bool SetDate(BDateTime date); private: BString fTitle; diff --git a/src/Feed.cpp b/src/Feed.cpp index d0e6d12..37b419c 100644 --- a/src/Feed.cpp +++ b/src/Feed.cpp @@ -14,69 +14,18 @@ #include "Util.h" -Feed::Feed(BUrl xml, BString path) - : Feed() +Feed::Feed() + : fTitle(BString("")) { - SetXmlUrl(xml); - SetCachePath(path); + fLastDate = BDateTime::CurrentDateTime(B_LOCAL_TIME); } -Feed::Feed(BUrl xml) - : Feed() +Feed::Feed(const char* identifier, const char* title, const char* url) + : fTitle(BString(title)), + fIdentifier(BString(identifier)), + fUrl(BUrl(url)) { - SetXmlUrl(xml); - - BPath cache; - find_directory(B_USER_CACHE_DIRECTORY, &cache); - cache.Append("Pogger"); - - cache.Append(urlToFilename(fXmlUrl)); - SetCachePath(cache.Path()); -} - - -// For pre-existing feed -Feed::Feed(BEntry entry) - : Feed() -{ - BFile file(&entry, B_READ_ONLY); - BPath path; - entry.GetPath(&path); - SetCachePath(BString(path.Path())); - - BString name, url; - file.ReadAttrString("META:url", &url); - file.ReadAttrString("Feed:name", &name); - file.ReadAttrString("Feed:hash", &fLastHash); - - if (!url.IsEmpty()) - SetXmlUrl(BUrl(url)); - if (!name.IsEmpty()) - SetTitle(name); -} - - -Feed::Feed(const char* pathStr) - : Feed(BEntry(pathStr)) -{ -} - - -// For new feed -Feed::Feed(BUrl xml, BEntry entry) - : Feed() -{ - BPath path; - BString pathString; - entry.GetPath(&path); - pathString = path.Path(); - - if (entry.IsDirectory()) - pathString += BString(urlToFilename(xml)); - - SetCachePath(pathString); - SetXmlUrl(xml); } @@ -84,128 +33,10 @@ Feed::Feed(Feed* feed) : Feed() { SetTitle(feed->Title()); - SetXmlUrl(feed->XmlUrl()); -} - - -Feed::Feed() - : - fTitle(BString("")) -{ - fLastDate = BDateTime::CurrentDateTime(B_LOCAL_TIME); + SetUrl(feed->Url()); } -Feed::~Feed() -{ -} - - -void -Feed::Parse() -{ - BFile feedFile = BFile(fCachePath, B_READ_ONLY); - time_t tt_lastDate = 0; - - feedFile.ReadAttr("Feed:when", B_TIME_TYPE, 0, &tt_lastDate, sizeof(time_t)); - - if (tt_lastDate > 0) - fLastDate.SetTime_t(tt_lastDate); -} - - -// Download a remote feed's XML to the cache path. -bool -Feed::Fetch() -{ - BFile cacheFile = BFile(fCachePath, B_READ_WRITE | B_CREATE_FILE); - - int32 result = fetch(fXmlUrl, &cacheFile, &fHash, 30); - cacheFile.WriteAttrString("Feed:hash", &fHash); - - if (result == 0) - return true; - return false; -} - - -void -Feed::Filetize() -{ - BFile feedFile(fCachePath, B_WRITE_ONLY | B_CREATE_FILE); - time_t tt_date = fDate.Time_t(); - BString url = fXmlUrl.UrlString(); - BString name = Title(); - BString type("application/x-feed-source"); - - feedFile.WriteAttrString("Feed:name", &name); - feedFile.WriteAttrString("META:url", &url); - feedFile.WriteAttrString("BEOS:TYPE", &type); - feedFile.WriteAttr("Feed:when", B_TIME_TYPE, 0, &tt_date, sizeof(time_t)); - feedFile.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0, type.String(), - type.CountChars() + 1); -} - - -void -Feed::Unfiletize() -{ - BEntry entry(CachePath().String()); - entry.Remove(); -} - - -bool -Feed::IsRss() -{ - tinyxml2::XMLDocument xml; - xml.LoadFile(fCachePath.String()); - - if (xml.FirstChildElement("rss")) - return true; - return false; -} - - -bool -Feed::IsAtom() -{ - tinyxml2::XMLDocument xml; - xml.LoadFile(fCachePath.String()); - - if (xml.FirstChildElement("feed")) - return true; - return false; -} - - -bool -Feed::IsUpdated() -{ - return fLastHash != fHash; -} - - -// Count the amount of siblings to an element of given type name -int -Feed::_XmlCountSiblings (tinyxml2::XMLElement* xsibling, const char* sibling_name) -{ - int count = 0; - while (xsibling) { - count++; - xsibling = xsibling->NextSiblingElement(sibling_name); - } - return count; -} - - -bool -Feed::_AddEntry (Entry* newEntry) -{ - fEntries.AddItem(newEntry); - return true; -} - BObjectList Feed::Entries() @@ -228,22 +59,10 @@ Feed::NewEntries() } -bool -Feed::SetTitle(const char* titleStr) +void +Feed::SetEntries(BObjectList entries) { - if (titleStr != NULL) - fTitle = BString(titleStr); - else return false; - return true; -} - - -bool -Feed::_SetTitle(tinyxml2::XMLElement* elem) -{ - if (elem != NULL && fTitle.IsEmpty() == true) - return SetTitle(elem->GetText()); - else return false; + fEntries = entries; } @@ -255,65 +74,30 @@ Feed::Title() bool -Feed::SetXmlUrl(BUrl newUrl) +Feed::SetTitle(const char* titleStr) { - fXmlUrl = newUrl; + if (titleStr != NULL) + fTitle = BString(titleStr); + else return false; return true; } BUrl -Feed::XmlUrl() +Feed::Url() { - return fXmlUrl; + return fUrl; } bool -Feed::SetCachePath(BString path) +Feed::SetUrl(BUrl newUrl) { - fCachePath = path; + fUrl = newUrl; return true; } -BString -Feed::CachePath() -{ - return fCachePath; -} - - -// Set the latest date given by feed (from entry or from root) -bool -Feed::_SetDate(BDateTime newDate) -{ - if (newDate == NULL) - return false; - fDate = newDate; - return true; -} - - -bool -Feed::_SetDate(const char* dateCStr) -{ - if (dateCStr == NULL) - return false; - _SetDate(feedDateToBDate(dateCStr)); - return true; -} - - -bool -Feed::_SetDate(tinyxml2::XMLElement* elem) -{ - if (elem != NULL) - return _SetDate(elem->GetText()); - else return false; -} - - BDateTime Feed::Date() { @@ -321,3 +105,77 @@ Feed::Date() } +// Set the latest date given by feed (from entry or from metadata) +bool +Feed::SetDate(BDateTime newDate) +{ + if (newDate == NULL) + return false; + fDate = newDate; + return true; +} + + +BDateTime +Feed::LastDate() +{ + return fLastDate; +} + + +// Set the latest time the feed was fetched and parsed +bool +Feed::SetLastDate(BDateTime newDate) +{ + if (newDate == NULL) + return false; + fLastDate = newDate; + return true; +} + + +BString +Feed::Hash() +{ + return fHash; +} + + +bool +Feed::SetHash(BString hash) +{ + fHash = hash; + return true; +} + + +BString +Feed::LastHash() +{ + return fLastHash; +} + + +bool +Feed::SetLastHash(BString hash) +{ + fLastHash = hash; + return true; +} + + +BString +Feed::Identifier() +{ + return fIdentifier; +} + + +bool +Feed::SetIdentifier(BString id) +{ + fIdentifier = id; + return true; +} + + diff --git a/src/Feed.h b/src/Feed.h index 5af1c29..158dd6e 100644 --- a/src/Feed.h +++ b/src/Feed.h @@ -21,57 +21,42 @@ class BUrl; class Feed { public: - Feed(BUrl); - Feed(BUrl, BString); - Feed(BEntry); - Feed(const char* pathStr); - Feed(BUrl xml, BEntry entry); - Feed(Feed*); Feed(); - - ~Feed(); - - virtual void Parse(); + Feed(const char* identifier, const char* title, const char* url); + Feed(Feed*); BObjectList Entries(); BObjectList NewEntries(); - bool Fetch(); - - void Filetize(); - void Unfiletize(); - - bool IsRss(); - bool IsAtom(); - bool IsUpdated(); + void SetEntries(BObjectList entries); BString Title(); + bool SetTitle(const char*); + + BUrl Url(); + bool SetUrl(BUrl newUrl); + + BDateTime Date(); bool SetDate(BDateTime); - BUrl XmlUrl(); - BDateTime Date(); + BDateTime LastDate(); + bool SetLastDate(BDateTime); - bool SetTitle(const char*); - bool SetXmlUrl(BUrl newUrl); - bool SetCachePath(BString path); + BString Hash(); + bool SetHash(BString hash); - BString CachePath(); + BString LastHash(); + bool SetLastHash(BString hash); + + BString Identifier(); + bool SetIdentifier(BString id); protected: - bool _SetTitle(tinyxml2::XMLElement*); - bool _SetDate(const char*); - bool _SetDate(tinyxml2::XMLElement*); - bool _SetDate(BDateTime newDate); - - bool _AddEntry(Entry*); - - int _XmlCountSiblings(tinyxml2::XMLElement*, const char*); - BString fTitle; - BDateTime fDate; - BDateTime fLastDate; - BUrl fXmlUrl; - BString fCachePath; + BDateTime fDate; // Lastest date (of post/update) given by feed + BDateTime fLastDate; // Last time feed was parsed + BUrl fUrl; + BString fIdentifier; BString fHash; BString fLastHash; diff --git a/src/FeedController.cpp b/src/FeedController.cpp index 94d9e01..3266cef 100644 --- a/src/FeedController.cpp +++ b/src/FeedController.cpp @@ -16,10 +16,8 @@ #include #include "Daemon.h" -#include "AtomFeed.h" #include "Entry.h" #include "LocalSource.h" -#include "RssFeed.h" #undef B_TRANSLATION_CONTEXT @@ -32,7 +30,7 @@ FeedController::FeedController() fMainThread(find_thread(NULL)), fDownloadThread(0), fParseThread(0), - fDownloadQueue(new BStringList()), + fDownloadQueue(new BObjectList()), fMessageRunner(new BMessageRunner(be_app, BMessage(kControllerCheck), 50000, -1)) { @@ -61,21 +59,20 @@ FeedController::MessageReceived(BMessage* msg) { int i = 0; const void* data; - ssize_t size = sizeof(BString); - - BStringList paths; - msg->FindStrings("feedPaths", &paths); - fDownloadQueue->Add(paths); + ssize_t size = sizeof(Feed); + while (msg->HasData("feeds", B_RAW_TYPE, i)) { + msg->FindData("feeds", B_RAW_TYPE, i, &data, &size); + fDownloadQueue->AddItem((Feed*)data); + _SendProgress(); + } fMessageRunner->SetCount(-1); - _SendProgress(); break; } case kUpdateSubscribed: { - BStringList subFeeds = LocalSource::Feeds(); - fDownloadQueue->Add(subFeeds); - + BObjectList list = LocalSource::Feeds(); + fDownloadQueue->AddList(&list); _SendProgress(); break; } @@ -97,7 +94,7 @@ FeedController::MessageReceived(BMessage* msg) void FeedController::_SendProgress() { - int32 dqCount = fDownloadQueue->CountStrings(); + int32 dqCount = fDownloadQueue->CountItems(); if (fEnqueuedTotal < dqCount) fEnqueuedTotal = dqCount; @@ -116,19 +113,13 @@ void FeedController::_ProcessQueueItem() { if (has_data(fDownloadThread) && !fDownloadQueue->IsEmpty()) { - BString feed = fDownloadQueue->Remove(0); - Feed* buffer; - - if (BUrl(feed.String()).IsValid() == true) - buffer = new Feed(BUrl(feed.String())); - else - buffer = new Feed(feed.String()); - - send_data(fDownloadThread, 0, (void*)buffer, sizeof(Feed)); + Feed* feed = fDownloadQueue->ItemAt(0); + fDownloadQueue->RemoveItemAt(0); + send_data(fDownloadThread, 0, (void*)feed, sizeof(Feed)); BMessage downloadInit = BMessage(kDownloadStart); - downloadInit.AddString("feed_name", buffer->Title()); - downloadInit.AddString("feed_url", buffer->XmlUrl().UrlString()); + downloadInit.AddString("feed_name", feed->Title()); + downloadInit.AddString("feed_url", feed->Url().UrlString()); ((App*)be_app)->MessageReceived(&downloadInit); } } @@ -149,8 +140,7 @@ FeedController::_ReceiveStatus() { BMessage complete = BMessage(kDownloadComplete); complete.AddString("feed_name", feedBuffer->Title()); - complete.AddString("feed_url", - feedBuffer->XmlUrl().UrlString()); + complete.AddString("feed_url", feedBuffer->Url().UrlString()); ((App*)be_app)->MessageReceived(&complete); send_data(fParseThread, 0, (void*)feedBuffer, sizeof(Feed)); @@ -161,7 +151,7 @@ FeedController::_ReceiveStatus() BMessage failure = BMessage(kDownloadFail); failure.AddString("feed_name", feedBuffer->Title()); failure.AddString("feed_url", - feedBuffer->XmlUrl().UrlString()); + feedBuffer->Url().UrlString()); ((App*)be_app)->MessageReceived(&failure); _SendProgress(); break; @@ -170,7 +160,7 @@ FeedController::_ReceiveStatus() { BMessage failure = BMessage(kParseFail); failure.AddString("feed_name", feedBuffer->Title()); - failure.AddString("feed_url", feedBuffer->XmlUrl().UrlString()); + failure.AddString("feed_url", feedBuffer->Url().UrlString()); ((App*)be_app)->MessageReceived(&failure); _SendProgress(); break; @@ -179,7 +169,7 @@ FeedController::_ReceiveStatus() default: BMessage complete = BMessage(kParseComplete); complete.AddString("feed_name", feedBuffer->Title()); - complete.AddString("feed_url", feedBuffer->XmlUrl().UrlString()); + complete.AddString("feed_url", feedBuffer->Url().UrlString()); complete.AddInt32("entry_count", code); ((App*)be_app)->MessageReceived(&complete); _SendProgress(); @@ -201,9 +191,9 @@ FeedController::_DownloadLoop(void* data) receive_data(&sender, (void*)feedBuffer, sizeof(Feed)); std::cout << B_TRANSLATE("Downloading feed from ") - << feedBuffer->XmlUrl().UrlString() << "…\n"; + << feedBuffer->Url().UrlString() << "…\n"; - if (feedBuffer->Fetch()) { + if (LocalSource::Fetch(feedBuffer)) { send_data(main, kDownloadComplete, (void*)feedBuffer, sizeof(Feed)); } else { @@ -228,39 +218,19 @@ FeedController::_ParseLoop(void* data) BObjectList entries; int32 entriesCount = 0; BString feedTitle; - BUrl feedUrl = feedBuffer->XmlUrl(); + BUrl feedUrl = feedBuffer->Url(); - if (feedBuffer->IsAtom() && feedBuffer->IsUpdated()) { - AtomFeed feed(feedBuffer); - feed.Parse(); - entries = feed.NewEntries(); - entriesCount = entries.CountItems(); - feedTitle = feed.Title(); + LocalSource::Parse(feedBuffer); + entries = feedBuffer->NewEntries(); + entriesCount = entries.CountItems(); + feedTitle = feedBuffer->Title(); - for (int i = 0; i < entriesCount; i++) - entries.ItemAt(i)->Filetize(); - entries.MakeEmpty(); - } - else if (feedBuffer->IsRss() && feedBuffer->IsUpdated()) { - RssFeed feed(feedBuffer); - feed.Parse(); - entries = feed.NewEntries(); - entriesCount = entries.CountItems(); - feedTitle = feed.Title(); - - for (int i = 0; i < entriesCount; i++) - entries.ItemAt(i)->Filetize(); - entries.MakeEmpty(); - } - - - if (feedBuffer->IsAtom() || feedBuffer->IsRss()) { - send_data(main, entriesCount, (void*)feedBuffer, sizeof(Feed)); - } - else { - send_data(main, entriesCount, (void*)feedBuffer, sizeof(Feed)); - } + for (int i = 0; i < entriesCount; i++) + entries.ItemAt(i)->Filetize(); + entries.MakeEmpty(); + LocalSource::EditFeed(feedBuffer); + send_data(main, entriesCount, (void*)feedBuffer, sizeof(Feed)); free(feedBuffer); } diff --git a/src/FeedController.h b/src/FeedController.h index 1a681c7..c0b5c55 100644 --- a/src/FeedController.h +++ b/src/FeedController.h @@ -37,8 +37,6 @@ public: void MessageReceived(BMessage* msg); - static BStringList SubscribedFeeds(); - private: void _SendProgress(); @@ -54,7 +52,7 @@ private: thread_id fDownloadThread; thread_id fParseThread; - BStringList* fDownloadQueue; + BObjectList* fDownloadQueue; BMessageRunner* fMessageRunner; }; diff --git a/src/FeedEditWindow.cpp b/src/FeedEditWindow.cpp index 63492b3..16ff5ac 100644 --- a/src/FeedEditWindow.cpp +++ b/src/FeedEditWindow.cpp @@ -18,6 +18,7 @@ #include "FeedController.h" #include "FeedListItem.h" #include "FeedsView.h" +#include "LocalSource.h" #include "Util.h" @@ -33,26 +34,18 @@ FeedEditWindow::FeedEditWindow() { _InitInterface(); MoveOnScreen(); - fFeed = Feed(); + fFeed = new Feed(); } -FeedEditWindow::FeedEditWindow(BEntry feedEntry) - : - FeedEditWindow() +FeedEditWindow::FeedEditWindow(BString identifier) + : FeedEditWindow() { SetTitle(B_TRANSLATE("Edit feed")); - fFeed = Feed(feedEntry); + fFeed = LocalSource::GetFeed(identifier); - fFeedNameText->SetText(fFeed.Title().String()); - fFeedUrlText->SetText(fFeed.XmlUrl().UrlString().String()); -} - - -FeedEditWindow::FeedEditWindow(FeedListItem* feedItem) - : - FeedEditWindow(BEntry(feedItem->FeedPath())) -{ + fFeedNameText->SetText(fFeed->Title().String()); + fFeedUrlText->SetText(fFeed->Url().UrlString().String()); } @@ -128,22 +121,6 @@ FeedEditWindow::_InitInterface() void FeedEditWindow::_SaveFeed() { - BPath subPath; - find_directory(B_USER_SETTINGS_DIRECTORY, &subPath); - subPath.Append("Pogger"); - subPath.Append("Subscriptions"); - BDirectory subDir(subPath.Path()); - if (subDir.InitCheck() == B_ENTRY_NOT_FOUND) { - subDir.CreateDirectory(subPath.Path(), &subDir); - - BPath defaultSubPath(subPath); - defaultSubPath.Append("Haiku Project"); - Feed defaultSub(BUrl("https://www.haiku-os.org/blog/index.xml"), - BEntry(defaultSubPath.Path())); - defaultSub.SetTitle("Haiku Project"); - defaultSub.Filetize(); - } - BString title(fFeedNameText->Text()); const char* urlString = fFeedUrlText->Text(); BUrl url = BUrl(urlString); @@ -165,26 +142,20 @@ FeedEditWindow::_SaveFeed() return; } - BString filename; - if (title.IsEmpty()) - filename = BString(urlToFilename(BUrl(urlString))); - else - filename = BString(title); - subPath.Append(filename); - - if (fFeed.CachePath().IsEmpty()) - fFeed.SetCachePath(BString(subPath.Path())); - if (!title.IsEmpty()) - fFeed.SetTitle(title.String()); - fFeed.SetXmlUrl(BUrl(urlString)); - fFeed.Filetize(); + fFeed->SetTitle(title.String()); + fFeed->SetUrl(BUrl(urlString)); + + if (fFeed->Identifier().IsEmpty() == true) + LocalSource::AddFeed(fFeed); + else + LocalSource::EditFeed(fFeed); BMessage edited(kFeedsEdited); - BMessage enqueueUpdated(kEnqueueFeed); - enqueueUpdated.AddString("feedPaths", fFeed.CachePath()); - - ((App*)be_app)->MessageReceived(&enqueueUpdated); +// BMessage enqueueUpdated(kEnqueueFeed); +// enqueueUpdated.AddData("feeds", B_RAW_TYPE, &fFeed, sizeof(Feed)); +// +// ((App*)be_app)->MessageReceived(&enqueueUpdated); ((App*)be_app)->PostMessage(&edited); Quit(); } diff --git a/src/FeedEditWindow.h b/src/FeedEditWindow.h index 1029e62..98fdf52 100644 --- a/src/FeedEditWindow.h +++ b/src/FeedEditWindow.h @@ -26,8 +26,7 @@ enum class FeedEditWindow : public BWindow { public: FeedEditWindow(); - FeedEditWindow(BEntry feedEntry); - FeedEditWindow(FeedListItem* feedItem); + FeedEditWindow(BString feedIdentifier); ~FeedEditWindow(); void MessageReceived(BMessage* msg); @@ -38,7 +37,7 @@ private: void _SaveFeed(); BString fFeedPath; - Feed fFeed; + Feed* fFeed; BStringView* fFeedNameLabel; BTextControl* fFeedNameText; diff --git a/src/FeedListItem.cpp b/src/FeedListItem.cpp index 28ee1a4..918893b 100644 --- a/src/FeedListItem.cpp +++ b/src/FeedListItem.cpp @@ -20,8 +20,8 @@ FeedListItem::FeedListItem(Feed* feed) : BStringItem(feed->Title().String(), 0, false), fStatus(kClearStatus), - fFeedUrl(feed->XmlUrl()), - fFeedPath(feed->CachePath()) + fFeedUrl(feed->Url()), + fFeedIdentifier(feed->Identifier()) { if (feed->Title().IsEmpty() == true) SetText(B_TRANSLATE("Untitled Feed")); @@ -59,9 +59,9 @@ FeedListItem::DrawItem(BView* owner, BRect frame, bool complete) BString -FeedListItem::FeedPath() +FeedListItem::FeedIdentifier() { - return fFeedPath; + return fFeedIdentifier; } diff --git a/src/FeedListItem.h b/src/FeedListItem.h index a400473..6b44005 100644 --- a/src/FeedListItem.h +++ b/src/FeedListItem.h @@ -29,14 +29,14 @@ public: void DrawItem(BView* owner, BRect frame, bool complete); BUrl FeedUrl(); - BString FeedPath(); + BString FeedIdentifier(); void SetStatus(int8 status); private: int8 fStatus; BUrl fFeedUrl; - BString fFeedPath; + BString fFeedIdentifier; }; diff --git a/src/FeedSource.cpp b/src/FeedSource.cpp deleted file mode 100644 index f1bbb04..0000000 --- a/src/FeedSource.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2021, Jaidyn Levesque - * All rights reserved. Distributed under the terms of the MIT license. - */ - - -#include "FeedSource.h" - diff --git a/src/FeedSource.h b/src/FeedSource.h index 352c411..e28c32a 100644 --- a/src/FeedSource.h +++ b/src/FeedSource.h @@ -7,14 +7,17 @@ #include +#include "Feed.h" + // Hierarchy: FeedSource → Feed → Entry // TODO: RemoveFeed(), AddFeed(), etc. class FeedSource { public: - BStringList Feeds(); + static BStringList FeedIdentifiers(); - const char* name = ""; + Feed RemoveFeed(Feed feed); + Feed RemoveFeed(const char* identifier); }; diff --git a/src/FeedsView.cpp b/src/FeedsView.cpp index 8507d6f..04995a1 100644 --- a/src/FeedsView.cpp +++ b/src/FeedsView.cpp @@ -189,7 +189,7 @@ FeedsView::_EditSelectedFeed() { int32 selIndex = fFeedsListView->CurrentSelection(); FeedListItem* selected = (FeedListItem*)fFeedsListView->ItemAt(selIndex); - FeedEditWindow* edit = new FeedEditWindow(selected); + FeedEditWindow* edit = new FeedEditWindow(selected->FeedIdentifier()); edit->Show(); edit->Activate(); @@ -211,24 +211,23 @@ FeedsView::_RemoveSelectedFeed() int32 selIndex = fFeedsListView->CurrentSelection(); FeedListItem* selected = (FeedListItem*)fFeedsListView->ItemAt(selIndex); - Feed delFeed = Feed(BEntry(selected->FeedPath())); - delFeed.Unfiletize(); + LocalSource::RemoveFeed(LocalSource::GetFeed(selected->FeedIdentifier())); } void FeedsView::_PopulateFeedList() { - BStringList feeds = LocalSource::Feeds(); + BObjectList feeds = LocalSource::Feeds(); int32 selected = fFeedsListView->CurrentSelection(); for (int i = fFeedsListView->CountItems(); i >= 0; i--) delete ((FeedListItem*)fFeedsListView->RemoveItem(i)); - for (int i = 0; i < feeds.CountStrings(); i++) { - Feed feed = Feed(feeds.StringAt(i).String()); - FeedListItem* item = new FeedListItem(&feed); + for (int i = 0; i < feeds.CountItems(); i++) { + Feed* feed = feeds.ItemAt(i); + FeedListItem* item = new FeedListItem(feed); fFeedsListView->AddItem(item); } diff --git a/src/LocalSource.cpp b/src/LocalSource.cpp index c50d3a7..6d56c9f 100644 --- a/src/LocalSource.cpp +++ b/src/LocalSource.cpp @@ -5,40 +5,432 @@ #include "LocalSource.h" +#include + +#include #include #include +#include #include #include #include "Feed.h" +#include "Util.h" + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "LocalSource" -BStringList +LocalSource::LocalSource() +{ + BDirectory subDir = BDirectory(_SubscriptionPath().Path()); + if (subDir.InitCheck() == B_ENTRY_NOT_FOUND) { +// subDir.CreateDirectory(subPath.Path(), &subDir); + +// subPath.Append("Haiku Project"); +// Feed defaultSub(BUrl("https://www.haiku-os.org/blog/index.xml"), +// BEntry(subPath.Path())); +// defaultSub.SetTitle("Haiku Project"); +// defaultSub.Filetize(); + } +} + + +BObjectList LocalSource::Feeds() +{ + BDirectory subDir = BDirectory(_SubscriptionPath().Path()); + BEntry feedEntry; + BPath feedPath; + + BObjectList feeds; + + while (subDir.GetNextEntry(&feedEntry) == B_OK + && feedEntry.GetPath(&feedPath) == B_OK) + { + Feed* feed = GetFeed(feedPath.Path()); + feeds.AddItem(feed); + } + + return feeds; +} + + +Feed* +LocalSource::GetFeed(const char* identifier) +{ + BFile file(identifier, B_READ_ONLY); + time_t tt_lastDate = 0; + BDateTime lastDate; + BString title; + BString url; + BString hash; + + file.ReadAttrString("Feed:name", &title); + file.ReadAttrString("META:url", &url); + file.ReadAttrString("Feed:hash", &hash); + file.ReadAttr("Feed:when", B_TIME_TYPE, 0, &tt_lastDate, sizeof(time_t)); + lastDate.SetTime_t(tt_lastDate); + + Feed* feed = new Feed(identifier, title.String(), url.String()); + feed->SetHash(hash); + feed->SetLastDate(lastDate); + return feed; +} + + +bool +LocalSource::Fetch(Feed* feed) +{ + BFile cacheFile = BFile(feed->Identifier(), B_READ_WRITE | B_CREATE_FILE); + BString hash; + + int32 result = fetch(feed->Url(), &cacheFile, &hash, 30); + feed->SetHash(hash); + + if (result == 0) + return true; + return false; +} + + +bool +LocalSource::Parse(Feed* feed) +{ + if (IsUpdated(feed) == false) + return true; + + if (_IsAtom(feed) == true) + return _AtomParse(feed); + else if (_IsRss(feed) == true) + return _RssParse(feed); + return false; +} + + +void +LocalSource::AddFeed(Feed* newFeed) +{ + if (newFeed->Identifier().IsEmpty() == true) { + BPath subPath = _SubscriptionPath(); + subPath.Append(urlToFilename(newFeed->Url())); + newFeed->SetIdentifier(subPath.Path()); + } + EditFeed(newFeed); +} + + +void +LocalSource::EditFeed(Feed* updated) +{ + Feed* old = GetFeed(updated->Identifier()); + BFile file(updated->Identifier(), B_READ_WRITE | B_CREATE_FILE); + + if (old->Title() != updated->Title()) { + BString title = updated->Title(); + file.WriteAttrString("Feed:name", &title); + } + if (old->Url() != updated->Url()) { + BString url = updated->Url().UrlString(); + file.WriteAttrString("META:url", &url); + } + if (old->Hash() != updated->Hash()) { + BString hash = updated->Hash(); + file.WriteAttrString("Feed:hash", &hash); + } + if (old->Date() != updated->Date()) { + time_t tt_date = updated->Date().Time_t(); + file.WriteAttr("Feed:when", B_TIME_TYPE, 0, &tt_date, sizeof(time_t)); + } + + BString type("application/x-feed-source"); + file.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0, type.String(), + type.CountChars() + 1); +} + + +void +LocalSource::RemoveFeed(Feed* mortonta) +{ + BEntry entry(mortonta->Identifier().String()); + entry.Remove(); +} + + +bool +LocalSource::IsUpdated(Feed* feed) +{ + return (GetFeed(feed->Identifier())->Hash() != feed->Hash()); +} + + +bool +LocalSource::_IsAtom(Feed* feed) +{ + tinyxml2::XMLDocument xml; + xml.LoadFile(feed->Identifier().String()); + + if (xml.FirstChildElement("feed")) + return true; + return false; +} + + +bool +LocalSource::_IsRss(Feed* feed) +{ + tinyxml2::XMLDocument xml; + xml.LoadFile(feed->Identifier().String()); + + if (xml.FirstChildElement("rss")) + return true; + return false; +} + + +bool +LocalSource::_AtomParse(Feed* atomFeed) +{ + tinyxml2::XMLDocument xml; + xml.LoadFile(atomFeed->Identifier().String()); + + tinyxml2::XMLElement* xfeed = xml.FirstChildElement("feed"); + + _AtomRootParse(atomFeed, xfeed); + _AtomEntriesParse(atomFeed, xfeed); + return true; +} + + +void +LocalSource::_AtomRootParse(Feed* feed, tinyxml2::XMLElement* xfeed) +{ + tinyxml2::XMLElement* xentry = xfeed->FirstChildElement("entry"); + + bool set = false; + + _SetTitle(feed, xfeed->FirstChildElement("title")); + + set = _SetDate(feed, xfeed->FirstChildElement("updated")); + if (!set) + set = _SetDate(feed, xfeed->FirstChildElement("published")); + if (!set && xentry) + set = _SetDate(feed, xentry->FirstChildElement("updated")); + if (!set && xentry) + set = _SetDate(feed, xentry->FirstChildElement("published")); + + BString logString(B_TRANSLATE("Channel '%source%' at %url%:\n")); + logString.ReplaceAll("%source%", feed->Title().String()); + logString.ReplaceAll("%url%", feed->Url().UrlString()); + + std::cout << logString.String(); +} + + +void +LocalSource::_AtomEntriesParse(Feed* feed, tinyxml2::XMLElement* xfeed) +{ + tinyxml2::XMLElement* xentry; + + xentry = xfeed->FirstChildElement("entry"); + + int entryCount = _XmlCountSiblings(xentry, "entry"); + BObjectList entries(entryCount, true); + + BString logString(B_TRANSLATE("\t-%count% entries-\n")); + BString entryStr; + entryStr << entryCount; + logString.ReplaceAll("%count%", entryStr); + + std::cout << logString.String(); + + while (xentry) { + Entry* newEntry = _AtomEntryParse(feed, xentry); + if (newEntry != NULL) + entries.AddItem(newEntry); + xentry = xentry->NextSiblingElement("entry"); + } + + feed->SetEntries(entries); +} + + +Entry* +LocalSource::_AtomEntryParse(Feed* feed, tinyxml2::XMLElement* xentry) +{ + Entry* newEntry = new Entry(); + + tinyxml2::XMLElement* xcontent = xentry->FirstChildElement("content"); + tinyxml2::XMLElement* xmedia = xentry->FirstChildElement("media:group"); + tinyxml2::XMLPrinter xprinter; + + newEntry->SetTitle(xentry->FirstChildElement("title")); + newEntry->SetPostUrl(xentry->FirstChildElement("link")->Attribute("href")); + newEntry->SetFeedTitle(feed->Title()); + + bool set = false; + set = newEntry->SetDescription(xentry->FirstChildElement("summary")); + if (!set) + set = newEntry->SetDescription(xentry->FirstChildElement("description")); + if (!set && xmedia) + set = newEntry->SetDescription( + xmedia->FirstChildElement("media:description")); + + set = _SetDate(newEntry, xentry->FirstChildElement("updated")); + if (!set) + set = _SetDate(newEntry, xentry->FirstChildElement("published")); + + if (feed->Date() == NULL || feed->Date() < newEntry->Date()) + feed->SetDate(newEntry->Date()); + + if (xcontent) { + xcontent->Accept(&xprinter); + newEntry->SetContent(xprinter.CStr()); + } + + return newEntry; +} + + +bool +LocalSource::_RssParse(Feed* feed) +{ + tinyxml2::XMLDocument xml; + xml.LoadFile(feed->Identifier().String()); + + tinyxml2::XMLElement* xchan = xml.FirstChildElement("rss")->FirstChildElement("channel"); + + _RssRootParse(feed, xchan); + _RssEntriesParse(feed, xchan); + return true; +} + + +void +LocalSource::_RssRootParse(Feed* feed, tinyxml2::XMLElement* xchan) +{ + _SetTitle(feed, xchan->FirstChildElement("title")); + _SetDate(feed, xchan->FirstChildElement("lastBuildDate")); + + BString logString(B_TRANSLATE("Channel '%source%' at %url%:\n")); + logString.ReplaceAll("%source%", feed->Title().String()); + logString.ReplaceAll("%url%", feed->Url().UrlString()); + + std::cout << logString.String(); +} + + +void +LocalSource::_RssEntriesParse(Feed* feed, tinyxml2::XMLElement* xchan) +{ + tinyxml2::XMLElement* xitem; + + xitem = xchan->FirstChildElement("item"); + + int entryCount = _XmlCountSiblings(xitem, "item"); + BObjectList entries = BObjectList(entryCount, true); + + BString logString(B_TRANSLATE("\t-%count% entries-\n")); + BString entryStr; + entryStr << entryCount; + logString.ReplaceAll("%count%", entryStr); + + std::cout << logString.String(); + + while (xitem) { + entries.AddItem(_RssEntryParse(feed, xitem)); + xitem = xitem->NextSiblingElement("item"); + } + feed->SetEntries(entries); +} + + +Entry* +LocalSource::_RssEntryParse(Feed* feed, tinyxml2::XMLElement* xitem) +{ + Entry* newEntry = new Entry(); + + newEntry->SetTitle(xitem->FirstChildElement("title")); + newEntry->SetDescription(xitem->FirstChildElement("description")); + _SetDate(newEntry, xitem->FirstChildElement("pubDate")); + newEntry->SetPostUrl(xitem->FirstChildElement("link")); + newEntry->SetContent(xitem->FirstChildElement("content:encoded")); + newEntry->SetFeedTitle(feed->Title()); + + if (feed->Date() == NULL || feed->Date() < newEntry->Date()) + feed->SetDate(newEntry->Date()); + + return newEntry; +} + + +bool +LocalSource::_SetTitle(Feed* feed, tinyxml2::XMLElement* elem) +{ + if (elem != NULL && feed->Title().IsEmpty() == true) + return feed->SetTitle(elem->GetText()); + return false; +} + +bool +LocalSource::_SetDate(Feed* feed, const char* dateCStr) +{ + if (dateCStr == NULL) + return false; + return feed->SetDate(feedDateToBDate(dateCStr)); +} + + +bool +LocalSource::_SetDate(Feed* feed, tinyxml2::XMLElement* elem) +{ + if (elem == NULL) + return false; + return _SetDate(feed, elem->GetText()); +} + + +bool +LocalSource::_SetDate(Entry* entry, const char* dateStr) +{ + if (dateStr == NULL) + return false; + return entry->SetDate(feedDateToBDate(dateStr)); +} + + +bool +LocalSource::_SetDate(Entry* entry, tinyxml2::XMLElement* elem) +{ + if (elem == NULL) + return false; + + return _SetDate(entry, elem->GetText()); +} + + +// Count the amount of siblings to an element of given type name +int +LocalSource::_XmlCountSiblings (tinyxml2::XMLElement* xsibling, + const char* sibling_name) +{ + int count = 0; + while (xsibling) { + count++; + xsibling = xsibling->NextSiblingElement(sibling_name); + } + return count; +} + + +BPath +LocalSource::_SubscriptionPath() { BPath subPath; find_directory(B_USER_SETTINGS_DIRECTORY, &subPath); subPath.Append("Pogger"); subPath.Append("Subscriptions"); - BDirectory subDir(subPath.Path()); - if (subDir.InitCheck() == B_ENTRY_NOT_FOUND) { - subDir.CreateDirectory(subPath.Path(), &subDir); - - subPath.Append("Haiku Project"); - Feed defaultSub(BUrl("https://www.haiku-os.org/blog/index.xml"), - BEntry(subPath.Path())); - defaultSub.SetTitle("Haiku Project"); - defaultSub.Filetize(); - } - - BEntry feedEntry; - BPath feedPath; - BStringList feeds; - - while (subDir.GetNextEntry(&feedEntry) == B_OK - && feedEntry.GetPath(&feedPath) == B_OK) - feeds.Add(feedPath.Path()); - return feeds; + return subPath; } diff --git a/src/LocalSource.h b/src/LocalSource.h index 6527b96..8c2534c 100644 --- a/src/LocalSource.h +++ b/src/LocalSource.h @@ -9,9 +9,44 @@ class LocalSource : public FeedSource { public: - static BStringList Feeds(); + LocalSource(); - const char* name = "Local"; + static BObjectList Feeds(); + + static Feed* GetFeed(const char* identifier); + + static bool Fetch(Feed* feed); + static bool Parse(Feed* feed); + + static void AddFeed(Feed* newFeed); + static void EditFeed(Feed* updated); + static void RemoveFeed(Feed* mortonta); + + static bool IsUpdated(Feed* feed); + +private: + static bool _IsAtom(Feed* feed); + static bool _IsRss(Feed* feed); + + static bool _AtomParse(Feed* feed); + static void _AtomRootParse(Feed* feed, tinyxml2::XMLElement*); + static void _AtomEntriesParse(Feed* feed, tinyxml2::XMLElement*); + static Entry* _AtomEntryParse(Feed* feed, tinyxml2::XMLElement*); + + static bool _RssParse(Feed* feed); + static void _RssRootParse(Feed* feed, tinyxml2::XMLElement*); + static void _RssEntriesParse(Feed* feed, tinyxml2::XMLElement*); + static Entry* _RssEntryParse(Feed* feed, tinyxml2::XMLElement*); + + static bool _SetTitle(Feed* feed, tinyxml2::XMLElement*); + + static bool _SetDate(Feed* feed, const char*); + static bool _SetDate(Feed* feed, tinyxml2::XMLElement*); + static bool _SetDate(Entry* entry, const char*); + static bool _SetDate(Entry* entry, tinyxml2::XMLElement*); + + static int _XmlCountSiblings(tinyxml2::XMLElement*, const char*); + static BPath _SubscriptionPath(); }; diff --git a/src/RssFeed.cpp b/src/RssFeed.cpp deleted file mode 100644 index 247bcce..0000000 --- a/src/RssFeed.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2020, Jaidyn Levesque - * All rights reserved. Distributed under the terms of the MIT license. - */ - -#include "RssFeed.h" - -#include - -#include - -#include "App.h" -#include "Entry.h" -#include "Util.h" - - -#undef B_TRANSLATION_CONTEXT -#define B_TRANSLATION_CONTEXT "RssFeed" - - -RssFeed::RssFeed() -{ - fTitle = BString(""); - fXmlUrl = BString(""); -} - - -RssFeed::RssFeed(Feed* feed) - : RssFeed::RssFeed() -{ - SetTitle(feed->Title()); - SetXmlUrl(feed->XmlUrl()); - SetCachePath(feed->CachePath()); -} - - -void -RssFeed::Parse() -{ - tinyxml2::XMLDocument xml; - fEntries = BObjectList(5, true); - - Feed::Parse(); - - xml.LoadFile(CachePath().String()); - tinyxml2::XMLElement* xchan = xml.FirstChildElement("rss")->FirstChildElement("channel"); - - RootParse(xchan); - ParseEntries(xchan); - - Filetize(); -} - - -void -RssFeed::RootParse(tinyxml2::XMLElement* xchan) -{ - _SetTitle(xchan->FirstChildElement("title")); - _SetDate(xchan->FirstChildElement("lastBuildDate")); - - BString logString(B_TRANSLATE("Channel '%source%' at %url%:\n")); - logString.ReplaceAll("%source%", fTitle.String()); - logString.ReplaceAll("%url%", fXmlUrl.UrlString()); - - std::cout << logString.String(); -} - - -void -RssFeed::EntryParse(tinyxml2::XMLElement* xitem) -{ - Entry* newEntry = new Entry(); - - newEntry->SetTitle(xitem->FirstChildElement("title")); - newEntry->SetDescription(xitem->FirstChildElement("description")); - newEntry->SetDate(xitem->FirstChildElement("pubDate")); - newEntry->SetPostUrl(xitem->FirstChildElement("link")); - newEntry->SetContent(xitem->FirstChildElement("content:encoded")); - newEntry->SetFeedTitle(fTitle); - - if (fDate == NULL || fDate < newEntry->Date()) - fDate = newEntry->Date(); - - _AddEntry(newEntry); -} - - -void -RssFeed::ParseEntries(tinyxml2::XMLElement* xchan) -{ - tinyxml2::XMLElement* xitem; - - xitem = xchan->FirstChildElement("item"); - - int entryCount = _XmlCountSiblings(xitem, "item"); - fEntries = BObjectList(entryCount, true); - - BString logString(B_TRANSLATE("\t-%count% entries-\n")); - BString entryStr; - entryStr << entryCount; - logString.ReplaceAll("%count%", entryStr); - - std::cout << logString.String(); - - while (xitem) { - EntryParse(xitem); - xitem = xitem->NextSiblingElement("item"); - } -} - - diff --git a/src/RssFeed.h b/src/RssFeed.h deleted file mode 100644 index 46d8f6f..0000000 --- a/src/RssFeed.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2020, Jaidyn Levesque - * All rights reserved. Distributed under the terms of the MIT license. - */ -#ifndef RSS_FEED_H -#define RSS_FEED_H - -#include - -#include "Feed.h" - - -class RssFeed: public Feed { -public: - RssFeed(); - RssFeed(Feed*); - - void Parse(); - void RootParse(tinyxml2::XMLElement*); - void EntryParse(tinyxml2::XMLElement*); - void ParseEntries(tinyxml2::XMLElement*); -}; - - -#endif -