Some Feed and Entry refacotring

This commit is contained in:
Jaidyn Ann 2021-01-11 18:08:15 -06:00
parent 08d5a73f89
commit d596cef76a
11 changed files with 197 additions and 261 deletions

View File

@ -37,7 +37,6 @@ SRCS = \
src/Feed.cpp, \
src/FeedController.cpp \
src/FeedsView.cpp, \
src/Invocation.cpp \
src/MainWindow.cpp, \
src/Mimetypes.cpp, \
src/ProtocolListener.cpp, \

View File

@ -82,12 +82,14 @@ void
App::ArgvReceived(int32 argc, char** argv)
{
for (int i = 1; i < argc; i++) {
Feed* newFeed = new Feed(argv[i]);
if (BUrl(argv[i]).IsValid()) {
Feed* newFeed = new Feed(BUrl(argv[i]));
BMessage* enqueue = new BMessage(kEnqueueFeed);
enqueue->AddData("feeds", B_RAW_TYPE, (void*)newFeed, sizeof(Feed));
BMessage* enqueue = new BMessage(kEnqueueFeed);
enqueue->AddData("feeds", B_RAW_TYPE, (void*)newFeed, sizeof(Feed));
MessageReceived(enqueue);
MessageReceived(enqueue);
}
}
}

View File

@ -16,11 +16,8 @@
AtomFeed::AtomFeed()
{
title = BString("Untitled Feed");
description = BString("");
homeUrl = BString("");
xmlUrl = BString("");
cachePath = BString("");
outputDir = ((App*)be_app)->cfg->outDir;
}
@ -45,9 +42,9 @@ AtomFeed::Parse ()
RootParse(xfeed);
ParseEntries(xfeed);
BFile* feedFile = new BFile(GetCachePath().String(), B_READ_WRITE);
time_t tt_lastDate = lastDate.Time_t();
feedFile->WriteAttr("LastDate", B_TIME_TYPE, 0, &tt_lastDate,
BFile* feedFile = new BFile(cachePath, B_READ_WRITE);
time_t tt_date = date.Time_t();
feedFile->WriteAttr("LastDate", B_TIME_TYPE, 0, &tt_date,
sizeof(time_t));
}
@ -63,7 +60,6 @@ AtomFeed::RootParse(tinyxml2::XMLElement* xfeed)
bool set = false;
SetTitle(xfeed->FirstChildElement("title"));
SetDesc( xfeed->FirstChildElement("description"));
set = SetDate(xfeed->FirstChildElement("updated"));
if (!set)
@ -73,14 +69,8 @@ AtomFeed::RootParse(tinyxml2::XMLElement* xfeed)
if (!set && xentry)
set = SetDate(xentry->FirstChildElement("published"));
set = SetHomeUrl(xlink->Attribute("href"));
if (!set && xauthor)
set = SetHomeUrl(xauthor->FirstChildElement("uri"));
if (!set && xauthlink)
set = SetHomeUrl(xauthlink->Attribute("href"));
if (((App*)be_app)->cfg->verbose)
printf("Channel '%s' at '%s':\n", title.String(), homeUrl.String());
printf("Channel '%s' at '%s':\n", title.String(),
xmlUrl.UrlString().String());
}
@ -88,7 +78,7 @@ void
AtomFeed::EntryParse(tinyxml2::XMLElement* xentry)
{
Entry* newEntry = (Entry*)malloc(sizeof(Entry));
newEntry = new Entry(outputDir);
newEntry = new Entry();
tinyxml2::XMLElement* xcontent = xentry->FirstChildElement("content");
tinyxml2::XMLElement* xmedia = xentry->FirstChildElement("media:group");
@ -109,8 +99,8 @@ AtomFeed::EntryParse(tinyxml2::XMLElement* xentry)
if (!set)
set = newEntry->SetDate(xentry->FirstChildElement("published"));
if (lastDate == NULL || lastDate < newEntry->date)
lastDate = newEntry->date;
if (date == NULL || date < newEntry->GetDate())
SetDate(newEntry->GetDate());
if (xcontent) {
xcontent->Accept(&xprinter);
@ -131,8 +121,7 @@ AtomFeed::ParseEntries(tinyxml2::XMLElement* xfeed)
int entryCount = xmlCountSiblings(xentry, "entry");
entries = BList(entryCount);
if (((App*)be_app)->cfg->verbose)
printf("\t-%i entries-\n", entryCount);
printf("\t-%i entries-\n", entryCount);
while (xentry) {
EntryParse(xentry);

View File

@ -14,25 +14,23 @@
#include "Util.h"
Entry::Entry(BString outputPath)
Entry::Entry()
{
title = BString("");
description = BString("");
feedTitle = BString("");
postUrl = BString("");
content = BString("");
outputDir = outputPath;
}
bool
Entry::Filetize(bool onlyIfNew = false)
Entry::Filetize(BDirectory outDir)
{
BDirectory* dir = new BDirectory(outputDir);
BFile* file = new BFile(title.String(), B_READ_WRITE);
time_t tt_date = date.Time_t();
dir->CreateFile(title.String(), file);
outDir.CreateFile(title.String(), file);
BString betype = BString("text/x-feed-entry");
file->WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0, betype.String(),
@ -57,7 +55,8 @@ Entry::Filetize(bool onlyIfNew = false)
bool
Entry::SetTitle(const char* titleStr) {
Entry::SetTitle(const char* titleStr)
{
if (titleStr != NULL)
title = BString(titleStr);
else return false;
@ -66,7 +65,8 @@ Entry::SetTitle(const char* titleStr) {
bool
Entry::SetTitle(tinyxml2::XMLElement* elem) {
Entry::SetTitle(tinyxml2::XMLElement* elem)
{
if (elem != NULL)
return SetTitle(elem->GetText());
return false;
@ -74,7 +74,8 @@ Entry::SetTitle(tinyxml2::XMLElement* elem) {
bool
Entry::SetDesc(const char* descStr) {
Entry::SetDesc(const char* descStr)
{
if (descStr != NULL)
description = BString(descStr);
else return false;
@ -83,7 +84,8 @@ Entry::SetDesc(const char* descStr) {
bool
Entry::SetDesc(tinyxml2::XMLElement* elem) {
Entry::SetDesc(tinyxml2::XMLElement* elem)
{
if (elem != NULL)
return SetDesc(elem->GetText());
return false;
@ -91,7 +93,8 @@ Entry::SetDesc(tinyxml2::XMLElement* elem) {
bool
Entry::SetFeedTitle(BString titleStr) {
Entry::SetFeedTitle(BString titleStr)
{
if (titleStr != NULL)
feedTitle = titleStr;
else return false;
@ -119,7 +122,8 @@ Entry::SetContent(tinyxml2::XMLElement* elem)
bool
Entry::SetPostUrl(const char* urlStr) {
Entry::SetPostUrl(const char* urlStr)
{
if (urlStr != NULL)
postUrl = BString(urlStr);
else return false;
@ -128,7 +132,8 @@ Entry::SetPostUrl(const char* urlStr) {
bool
Entry::SetPostUrl(tinyxml2::XMLElement* elem) {
Entry::SetPostUrl(tinyxml2::XMLElement* elem)
{
if (elem != NULL)
return SetPostUrl(elem->GetText());
return false;
@ -136,7 +141,8 @@ Entry::SetPostUrl(tinyxml2::XMLElement* elem) {
bool
Entry::SetDate(const char* dateStr) {
Entry::SetDate(const char* dateStr)
{
if (dateStr == NULL)
return false;
BDateTime newDate = feedDateToBDate(dateStr);
@ -148,10 +154,18 @@ Entry::SetDate(const char* dateStr) {
bool
Entry::SetDate(tinyxml2::XMLElement* elem) {
Entry::SetDate(tinyxml2::XMLElement* elem)
{
if (elem != NULL)
return SetDate(elem->GetText());
return false;
}
BDateTime
Entry::GetDate()
{
return date;
}

View File

@ -19,9 +19,9 @@
class Entry {
public:
Entry(BString);
Entry();
bool Filetize(bool);
bool Filetize(BDirectory outDir);
bool SetTitle(const char*);
bool SetTitle(tinyxml2::XMLElement*);
@ -34,6 +34,7 @@ public:
bool SetPostUrl(tinyxml2::XMLElement*);
bool SetDate(const char*);
bool SetDate(tinyxml2::XMLElement*);
BDateTime GetDate();
BString title;
BString description;
@ -41,7 +42,6 @@ public:
BDateTime date;
BString postUrl;
BString content;
BString outputDir;
};

View File

@ -13,106 +13,77 @@
#include "Util.h"
Feed::Feed(BString path)
Feed::Feed(BUrl xml, BString path)
: Feed()
{
title = BString("Untitled Feed");
description = BString("Nondescript, N/A.");
homeUrl = BString("");
xmlUrl = BString("");
updated = true;
fetched = false;
inputPath = path;
SetCachePath(path);
xmlUrl = xml;
cachePath = path;
}
Feed::Feed(BUrl xml)
: Feed()
{
xmlUrl = xml;
BString cache("/boot/home/config/cache/Pogger/");
cache.Append(urlToFilename(xmlUrl));
SetCachePath(cache);
}
Feed::Feed(Feed* feed)
: Feed()
{
SetCachePath(feed->GetCachePath());
SetTitle(feed->GetTitle());
SetXmlUrl(feed->GetXmlUrl());
}
Feed::Feed()
:
title(BString("Untitled Feed"))
{
title = BString("");
description = BString("");
homeUrl = BString("");
xmlUrl = BString("");
lastDate = BDateTime::CurrentDateTime(B_LOCAL_TIME);
}
void
Feed::Parse()
{
BFile* feedFile = new BFile(GetCachePath().String(), B_READ_ONLY);
BDateTime attrLastDate = BDateTime();
BFile feedFile = BFile(cachePath, B_READ_ONLY);
time_t tt_lastDate = 0;
feedFile->ReadAttr("LastDate", B_TIME_TYPE, 0, &tt_lastDate,
sizeof(time_t));
feedFile.ReadAttr("LastDate", B_TIME_TYPE, 0, &tt_lastDate, sizeof(time_t));
if (tt_lastDate > 0 && ((App*)be_app)->cfg->updateFeeds == true) {
attrLastDate.SetTime_t(tt_lastDate);
minDate = attrLastDate;
}
if (tt_lastDate > 0)
lastDate.SetTime_t(tt_lastDate);
}
// Download a remote feed's XML to the cache path.
BString
Feed::FetchRemoteFeed()
Feed::Fetch()
{
BUrl givenUrl = BUrl(inputPath);
time_t tt_lastDate = 0;
BDateTime* lastDate = new BDateTime();
BString newHash;
BString oldHash;
BFile cacheFile = BFile(cachePath, B_READ_WRITE | B_CREATE_FILE);
BFile* cacheFile = new BFile(GetCachePath(), B_READ_WRITE | B_CREATE_FILE);
cacheFile.ReadAttrString("LastHash", &lastHash);
// cacheFile->ReadAttr("LastHash", B_STRING_TYPE, 0, oldHash, 41);
cacheFile->ReadAttrString("LastHash", &oldHash);
fetch(xmlUrl, &cacheFile, &hash, 30);
cacheFile.WriteAttrString("LastHash", &hash);
if (((App*)be_app)->cfg->verbose)
printf("Saving %s...\n", inputPath.String());
fetch(BUrl(inputPath), cacheFile, &newHash, 30);
cacheFile->WriteAttrString("LastHash", &newHash);
// cacheFile->WriteAttr("LastHash", B_STRING_TYPE, 0,
// newHash.String(), newHash.CountChars());
if (newHash == oldHash)
if (hash == lastHash)
updated = false;
fetched = true;
return GetCachePath();
return cachePath;
}
// return whether or not the feed's given URI/path is remote.
bool
Feed::IsRemote ()
Feed::IsRss()
{
return isRemotePath(inputPath);
}
// return whether or not the feed seems to have been updated
bool
Feed::IsUpdated ()
{
return updated;
}
// return whether or not feed is RSS
bool
Feed::IsRss ()
{
EnsureCached();
tinyxml2::XMLDocument xml;
xml.LoadFile(GetCachePath().String());
xml.LoadFile(cachePath.String());
if (xml.FirstChildElement("rss"))
return true;
@ -120,12 +91,11 @@ Feed::IsRss ()
}
// return whether or not feed is Atom
bool
Feed::IsAtom ()
Feed::IsAtom()
{
tinyxml2::XMLDocument xml;
xml.LoadFile(GetCachePath().String());
xml.LoadFile(cachePath.String());
if (xml.FirstChildElement("feed"))
return true;
@ -133,49 +103,10 @@ Feed::IsAtom ()
}
// ensure the feed XML is available at the cache path.
// if necessary, download it.
void
Feed::EnsureCached ()
bool
Feed::IsUpdated()
{
if (IsRemote() && fetched == false)
FetchRemoteFeed();
}
// Return the 'cachePath' (location of XML file locally)
BString
Feed::GetCachePath ()
{
if (cachePath == NULL)
SetCachePath(inputPath);
return cachePath;
}
// Select a 'cachePath' (location of XML file locally)
// For remote files, a cache file is created in ~/config/cache/Pogger/ by default
// For local files, the same local file is used.
BString
Feed::SetCachePath (BString givenPath)
{
BUrl givenUrl = BUrl(givenPath);
BString protocol = givenUrl.Protocol().String();
if (protocol == NULL && givenUrl.UrlString() != NULL) {
cachePath = givenPath;
return givenPath;
}
BString splitName = givenUrl.Host();
splitName.Append(givenUrl.Path());
splitName.ReplaceAll("/", "_");
BString filename = ((App*)be_app)->cfg->cacheDir;
filename.Append(splitName);
cachePath = filename;
return filename;
return lastHash != hash;
}
@ -192,17 +123,11 @@ Feed::xmlCountSiblings (tinyxml2::XMLElement* xsibling, const char* sibling_name
}
// Add the given entry to the feed, if appropriate
bool
Feed::AddEntry (Entry* newEntry)
{
Config* cfg = ((App*)be_app)->cfg;
if (!withinDateRange(cfg->minDate, newEntry->date, cfg->maxDate) ||
!withinDateRange(minDate, newEntry->date, maxDate))
return false;
if (cfg->verbose == true)
printf("\t%s\n", newEntry->title.String());
entries.AddItem(newEntry);
return true;
}
@ -215,6 +140,20 @@ Feed::GetEntries()
}
BList
Feed::GetNewEntries()
{
BList newEntries;
for (int i = 0; i < entries.CountItems(); i++) {
Entry* entry = ((Entry*)entries.ItemAt(i));
if (entry->GetDate() > lastDate)
newEntries.AddItem(entry);
}
return newEntries;
}
bool
Feed::SetTitle(const char* titleStr)
{
@ -242,75 +181,52 @@ Feed::GetTitle()
bool
Feed::SetDesc(const char* descStr)
Feed::SetXmlUrl(BUrl newUrl)
{
if (descStr != NULL)
description = BString(descStr);
else return false;
xmlUrl = newUrl;
return true;
}
bool
Feed::SetDesc(tinyxml2::XMLElement* elem)
{
if (elem != NULL)
return SetDesc(elem->GetText());
else return false;
}
BString
Feed::GetDesc()
{
return description;
}
// set a feed's «home URL»
bool
Feed::SetHomeUrl(const char* homepageStr)
{
if (homepageStr != NULL)
homeUrl = BString(homepageStr);
else return false;
return true;
}
bool
Feed::SetHomeUrl(tinyxml2::XMLElement* elem)
{
if (elem != NULL)
return SetHomeUrl(elem->GetText());
else return false;
}
BString
Feed::GetHomeUrl()
{
return homeUrl;
}
BString
BUrl
Feed::GetXmlUrl()
{
return xmlUrl;
}
// set the update time for a feed
bool
Feed::SetCachePath(BString path)
{
cachePath = path;
return true;
}
BString
Feed::GetCachePath()
{
return cachePath;
}
// Set the latest date given by feed (from entry or from root)
bool
Feed::SetDate(BDateTime newDate)
{
if (newDate == NULL)
return false;
date = newDate;
return true;
}
bool
Feed::SetDate(const char* dateCStr)
{
if (dateCStr == NULL)
return false;
BDateTime newDate = feedDateToBDate(dateCStr);
if (newDate == NULL)
return false;
date = newDate;
SetDate(feedDateToBDate(dateCStr));
return true;
}

View File

@ -19,53 +19,49 @@ class BUrl;
class Feed {
public:
Feed(BString);
Feed(BUrl);
Feed(BUrl, BString);
Feed(Feed*);
Feed();
virtual void Parse();
bool IsRemote();
bool IsUpdated();
bool IsRss();
bool IsAtom();
BString FetchRemoteFeed();
bool AddEntry(Entry*);
BList GetEntries();
bool SetTitle(const char*);
bool SetTitle(tinyxml2::XMLElement*);
BList GetNewEntries();
BString Fetch();
bool IsRss();
bool IsAtom();
bool IsUpdated();
BString GetTitle();
bool SetDesc(const char*);
bool SetDesc(tinyxml2::XMLElement*);
BString GetDesc();
bool SetHomeUrl(const char*);
bool SetHomeUrl(tinyxml2::XMLElement*);
BString GetHomeUrl();
BString GetXmlUrl();
bool SetDate(const char*);
bool SetDate(tinyxml2::XMLElement*);
BUrl GetXmlUrl();
BDateTime GetDate();
BString SetCachePath(BString);
BString GetCachePath();
protected:
void EnsureCached();
int xmlCountSiblings(tinyxml2::XMLElement*, const char*);
bool SetTitle(const char*);
bool SetTitle(tinyxml2::XMLElement*);
bool SetDate(BDateTime);
bool SetDate(const char*);
bool SetDate(tinyxml2::XMLElement*);
bool SetXmlUrl(BUrl newUrl);
bool SetCachePath(BString path);
bool AddEntry(Entry*);
int xmlCountSiblings(tinyxml2::XMLElement*, const char*);
BString title;
BString description;
BDateTime date;
BDateTime lastDate;
BDateTime minDate;
BDateTime maxDate;
BString homeUrl;
BString inputPath;
BString xmlUrl;
BUrl xmlUrl;
BString cachePath;
BString outputDir;
BString hash;
BString lastHash;
BList entries;
bool fetched;
bool updated;

View File

@ -89,7 +89,7 @@ FeedController::_DownloadLoop(void* ignored)
while (receive_data(&sender, (void*)feedBuffer, sizeof(Feed)) != 0) {
printf( "%s\n\n", feedBuffer->GetCachePath().String());
feedBuffer->FetchRemoteFeed();
feedBuffer->Fetch();
BMessage* downloaded = new BMessage(kDownloadComplete);
downloaded->AddData("feeds", B_RAW_TYPE, feedBuffer, sizeof(Feed));
@ -110,24 +110,26 @@ FeedController::_ParseLoop(void* ignored)
while (receive_data(&sender, (void*)feedBuffer, sizeof(Feed)) != 0) {
BList entries;
BDirectory outDir = BDirectory(((App*)be_app)->cfg->outDir);
if (feedBuffer->IsAtom()) {
AtomFeed* feed = (AtomFeed*)malloc(sizeof(AtomFeed));
feed = new AtomFeed(feedBuffer);
feed->Parse();
entries = feed->GetEntries();
entries = feed->GetNewEntries();
delete(feed);
}
if (feedBuffer->IsRss()) {
else if (feedBuffer->IsRss()) {
RssFeed* feed = (RssFeed*)malloc(sizeof(RssFeed));
feed = new RssFeed(feedBuffer);
feed->Parse();
entries = feed->GetEntries();
entries = feed->GetNewEntries();
delete(feed);
}
for (int i = 0; i < entries.CountItems(); i++)
((Entry*)entries.ItemAt(i))->Filetize(true);
if (feedBuffer->IsAtom() || feedBuffer->IsRss())
for (int i = 0; i < entries.CountItems(); i++)
((Entry*)entries.ItemAt(i))->Filetize(outDir);
}
delete (feedBuffer);

View File

@ -14,15 +14,15 @@
RssFeed::RssFeed()
{
title = BString("Untitled Feed");
description = BString("");
homeUrl = BString("");
xmlUrl = BString("");
outputDir = ((App*)be_app)->cfg->outDir;
}
RssFeed::RssFeed(Feed* feed) : RssFeed::RssFeed()
{ SetCachePath(feed->GetCachePath()); }
RssFeed::RssFeed(Feed* feed)
: RssFeed::RssFeed()
{
SetCachePath(feed->GetCachePath());
}
void
@ -39,9 +39,9 @@ RssFeed::Parse()
RootParse(xchan);
ParseEntries(xchan);
time_t tt_lastDate = lastDate.Time_t();
BFile* feedFile = new BFile(GetCachePath().String(), B_READ_ONLY);
feedFile->WriteAttr("LastDate", B_TIME_TYPE, 0, &tt_lastDate, sizeof(time_t));
time_t tt_date = date.Time_t();
BFile* feedFile = new BFile(cachePath, B_READ_ONLY);
feedFile->WriteAttr("LastDate", B_TIME_TYPE, 0, &tt_date, sizeof(time_t));
}
@ -49,12 +49,10 @@ void
RssFeed::RootParse(tinyxml2::XMLElement* xchan)
{
SetTitle(xchan->FirstChildElement("title"));
SetDesc(xchan->FirstChildElement("description"));
SetHomeUrl(xchan->FirstChildElement("link"));
SetDate(xchan->FirstChildElement("lastBuildDate"));
if (((App*)be_app)->cfg->verbose)
printf("Channel '%s' at '%s':\n", title.String(), homeUrl.String());
printf("Channel '%s' at '%s':\n", title.String(),
xmlUrl.UrlString().String());
}
@ -62,7 +60,7 @@ void
RssFeed::EntryParse(tinyxml2::XMLElement* xitem)
{
Entry* newEntry = (Entry*)malloc(sizeof(Entry));
newEntry = new Entry(outputDir);
newEntry = new Entry();
newEntry->SetTitle(xitem->FirstChildElement("title"));
newEntry->SetDesc(xitem->FirstChildElement("description"));
@ -71,8 +69,8 @@ RssFeed::EntryParse(tinyxml2::XMLElement* xitem)
newEntry->SetContent(xitem->FirstChildElement("content:encoded"));
newEntry->SetFeedTitle(title);
if (lastDate == NULL || lastDate < newEntry->date)
lastDate = newEntry->date;
if (date == NULL || date < newEntry->GetDate())
date = newEntry->date;
AddEntry(newEntry);
}
@ -88,8 +86,7 @@ RssFeed::ParseEntries(tinyxml2::XMLElement* xchan)
int entryCount = xmlCountSiblings(xitem, "item");
entries = BList(entryCount);
if (((App*)be_app)->cfg->verbose)
printf("\t-%i entries-\n", entryCount);
printf("\t-%i entries-\n", entryCount);
while (xitem) {
EntryParse(xitem);

View File

@ -84,7 +84,8 @@ withinDateRange(BDateTime minDate, BDateTime nowDate, BDateTime maxDate)
// return whether or not the given path is remote
bool
isRemotePath(BString path) {
isRemotePath(BString path)
{
BUrl givenUrl = BUrl(path);
BString protocol = givenUrl.Protocol().String();
@ -95,6 +96,24 @@ isRemotePath(BString path) {
}
BString
urlToFilename(BUrl url)
{
BString protocol = url.Protocol().String();
if (protocol == NULL && url.UrlString() != NULL) {
return BString("");
}
BString filename = url.Host();
filename.Append(url.Path());
filename.ReplaceAll("/", "_");
return filename;
}
int32
fetch(BUrl url, BDataIO* reply, BString* hash, int timeout)
{

View File

@ -23,6 +23,8 @@ bool withinDateRange(BDateTime, BDateTime, BDateTime);
bool isRemotePath(BString);
BString urlToFilename(BUrl url);
int32 fetch(BUrl url, BDataIO* reply, BString* hash, int timeout);