Store additional properties of RSS feed in metadata.

This commit is contained in:
akwizgran
2022-12-09 17:57:20 +00:00
parent 1a2f85f701
commit b920382e44
9 changed files with 146 additions and 55 deletions

View File

@@ -28,8 +28,7 @@ class RssFeedAdapter extends ListAdapter<Feed, RssFeedAdapter.FeedViewHolder> {
super(new DiffUtil.ItemCallback<Feed>() { super(new DiffUtil.ItemCallback<Feed>() {
@Override @Override
public boolean areItemsTheSame(Feed a, Feed b) { public boolean areItemsTheSame(Feed a, Feed b) {
return a.getUrl().equals(b.getUrl()) && return a.getBlogId().equals(b.getBlogId()) &&
a.getBlogId().equals(b.getBlogId()) &&
a.getAdded() == b.getAdded(); a.getAdded() == b.getAdded();
} }
@@ -86,8 +85,8 @@ class RssFeedAdapter extends ListAdapter<Feed, RssFeedAdapter.FeedViewHolder> {
delete.setOnClickListener(v -> listener.onDeleteClick(item)); delete.setOnClickListener(v -> listener.onDeleteClick(item));
// Author // Author
if (item.getRssAuthor() != null) { if (item.getProperties().getAuthor() != null) {
author.setText(item.getRssAuthor()); author.setText(item.getProperties().getAuthor());
author.setVisibility(VISIBLE); author.setVisibility(VISIBLE);
authorLabel.setVisibility(VISIBLE); authorLabel.setVisibility(VISIBLE);
} else { } else {
@@ -100,8 +99,8 @@ class RssFeedAdapter extends ListAdapter<Feed, RssFeedAdapter.FeedViewHolder> {
updated.setText(formatDate(ctx, item.getUpdated())); updated.setText(formatDate(ctx, item.getUpdated()));
// Description // Description
if (item.getDescription() != null) { if (item.getProperties().getDescription() != null) {
description.setText(item.getDescription()); description.setText(item.getProperties().getDescription());
description.setVisibility(VISIBLE); description.setVisibility(VISIBLE);
} else { } else {
description.setVisibility(GONE); description.setVisibility(GONE);

View File

@@ -168,7 +168,9 @@ class RssFeedViewModel extends DbViewModel {
List<Feed> list = getList(feeds); List<Feed> list = getList(feeds);
if (list != null) { if (list != null) {
for (Feed feed : list) { for (Feed feed : list) {
if (url.equals(feed.getUrl())) { // TODO: Fetch the feed and also match it against feeds that
// were imported from files?
if (url.equals(feed.getProperties().getUrl())) {
return true; return true;
} }
} }

View File

@@ -5,47 +5,27 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.Blog;
import org.briarproject.nullsafety.NotNullByDefault; import org.briarproject.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class Feed implements Comparable<Feed> { public class Feed implements Comparable<Feed> {
private final String url;
private final Blog blog; private final Blog blog;
private final LocalAuthor localAuthor; private final LocalAuthor localAuthor;
@Nullable private final RssProperties properties;
private final String description, rssAuthor;
private final long added, updated, lastEntryTime; private final long added, updated, lastEntryTime;
public Feed(String url, Blog blog, LocalAuthor localAuthor, public Feed(Blog blog, LocalAuthor localAuthor, RssProperties properties,
@Nullable String description, @Nullable String rssAuthor,
long added, long updated, long lastEntryTime) { long added, long updated, long lastEntryTime) {
this.url = url;
this.blog = blog; this.blog = blog;
this.localAuthor = localAuthor; this.localAuthor = localAuthor;
this.description = description; this.properties = properties;
this.rssAuthor = rssAuthor;
this.added = added; this.added = added;
this.updated = updated; this.updated = updated;
this.lastEntryTime = lastEntryTime; this.lastEntryTime = lastEntryTime;
} }
public Feed(String url, Blog blog, LocalAuthor localAuthor,
@Nullable String description, @Nullable String rssAuthor,
long added) {
this(url, blog, localAuthor, description, rssAuthor, added, 0L, 0L);
}
public Feed(String url, Blog blog, LocalAuthor localAuthor, long added) {
this(url, blog, localAuthor, null, null, added, 0L, 0L);
}
public String getUrl() {
return url;
}
public GroupId getBlogId() { public GroupId getBlogId() {
return blog.getId(); return blog.getId();
} }
@@ -62,14 +42,8 @@ public class Feed implements Comparable<Feed> {
return blog.getName(); return blog.getName();
} }
@Nullable public RssProperties getProperties() {
public String getDescription() { return properties;
return description;
}
@Nullable
public String getRssAuthor() {
return rssAuthor;
} }
public long getAdded() { public long getAdded() {
@@ -103,4 +77,8 @@ public class Feed implements Comparable<Feed> {
return 0; return 0;
} }
@Override
public int hashCode() {
return blog.hashCode();
}
} }

View File

@@ -22,6 +22,9 @@ public interface FeedConstants {
String KEY_FEED_PRIVATE_KEY = "feedPrivateKey"; String KEY_FEED_PRIVATE_KEY = "feedPrivateKey";
String KEY_FEED_DESC = "feedDesc"; String KEY_FEED_DESC = "feedDesc";
String KEY_FEED_RSS_AUTHOR = "feedRssAuthor"; String KEY_FEED_RSS_AUTHOR = "feedRssAuthor";
String KEY_FEED_RSS_TITLE = "feedRssTitle";
String KEY_FEED_RSS_LINK = "feedRssLink";
String KEY_FEED_RSS_URI = "feedRssUri";
String KEY_FEED_ADDED = "feedAdded"; String KEY_FEED_ADDED = "feedAdded";
String KEY_FEED_UPDATED = "feedUpdated"; String KEY_FEED_UPDATED = "feedUpdated";
String KEY_FEED_LAST_ENTRY = "feedLastEntryTime"; String KEY_FEED_LAST_ENTRY = "feedLastEntryTime";

View File

@@ -0,0 +1,86 @@
package org.briarproject.briar.api.feed;
import org.briarproject.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* The properties of an RSS feed, which may have been imported from a URL
* or a file.
*/
@Immutable
@NotNullByDefault
public class RssProperties {
@Nullable
private final String url, title, description, author, link, uri;
public RssProperties(@Nullable String url, @Nullable String title,
@Nullable String description, @Nullable String author,
@Nullable String link, @Nullable String uri) {
this.url = url;
this.title = title;
this.description = description;
this.author = author;
this.link = link;
this.uri = uri;
}
/**
* Returns the URL from which the RSS feed was imported, or null if the
* feed was imported from a file.
*/
@Nullable
public String getUrl() {
return url;
}
/**
* Returns the title property of the RSS feed, or null if no title was
* specified.
*/
@Nullable
public String getTitle() {
return title;
}
/**
* Returns the description property of the RSS feed, or null if no
* description was specified.
*/
@Nullable
public String getDescription() {
return description;
}
/**
* Returns the author property of the RSS feed, or null if no author was
* specified.
*/
@Nullable
public String getAuthor() {
return author;
}
/**
* Returns the link property of the RSS feed, or null if no link was
* specified. This is usually the URL of a webpage where the equivalent
* content can be viewed in a browser.
*/
@Nullable
public String getLink() {
return link;
}
/**
* Returns the URI property of the RSS feed, or null if no URI was
* specified. This may be a URL from which the feed can be downloaded,
* or it may be an opaque identifier such as a number that serves to
* distinguish this feed from other feeds produced by the same creator.
*/
@Nullable
public String getUri() {
return uri;
}
}

View File

@@ -17,6 +17,7 @@ import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.Blog;
import org.briarproject.briar.api.blog.BlogFactory; import org.briarproject.briar.api.blog.BlogFactory;
import org.briarproject.briar.api.feed.Feed; import org.briarproject.briar.api.feed.Feed;
import org.briarproject.briar.api.feed.RssProperties;
import javax.inject.Inject; import javax.inject.Inject;
@@ -27,6 +28,9 @@ import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_DESC;
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_LAST_ENTRY; import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_LAST_ENTRY;
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_PRIVATE_KEY; import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_PRIVATE_KEY;
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_RSS_AUTHOR; import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_RSS_AUTHOR;
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_RSS_LINK;
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_RSS_TITLE;
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_RSS_URI;
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_UPDATED; import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_UPDATED;
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_URL; import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEED_URL;
@@ -56,20 +60,20 @@ class FeedFactoryImpl implements FeedFactory {
Blog blog = blogFactory.createFeedBlog(localAuthor); Blog blog = blogFactory.createFeedBlog(localAuthor);
long added = clock.currentTimeMillis(); long added = clock.currentTimeMillis();
return new Feed(url, blog, localAuthor, added); RssProperties properties =
new RssProperties(url, null, null, null, null, null);
return new Feed(blog, localAuthor, properties, added, 0, 0);
} }
@Override @Override
public Feed createFeed(Feed feed, SyndFeed f, long lastEntryTime) { public Feed createFeed(Feed feed, SyndFeed f, long lastEntryTime) {
long updated = clock.currentTimeMillis(); long updated = clock.currentTimeMillis();
return new Feed(feed.getUrl(), feed.getBlog(), feed.getLocalAuthor(), return new Feed(feed.getBlog(), feed.getLocalAuthor(),
f.getDescription(), f.getAuthor(), feed.getAdded(), updated, feed.getProperties(), feed.getAdded(), updated, lastEntryTime);
lastEntryTime);
} }
@Override @Override
public Feed createFeed(BdfDictionary d) throws FormatException { public Feed createFeed(BdfDictionary d) throws FormatException {
String url = d.getString(KEY_FEED_URL);
BdfList authorList = d.getList(KEY_FEED_AUTHOR); BdfList authorList = d.getList(KEY_FEED_AUTHOR);
PrivateKey privateKey = PrivateKey privateKey =
@@ -80,14 +84,21 @@ class FeedFactoryImpl implements FeedFactory {
author.getPublicKey(), privateKey); author.getPublicKey(), privateKey);
Blog blog = blogFactory.createFeedBlog(localAuthor); Blog blog = blogFactory.createFeedBlog(localAuthor);
String desc = d.getOptionalString(KEY_FEED_DESC); String url = d.getOptionalString(KEY_FEED_URL);
String description = d.getOptionalString(KEY_FEED_DESC);
String rssAuthor = d.getOptionalString(KEY_FEED_RSS_AUTHOR); String rssAuthor = d.getOptionalString(KEY_FEED_RSS_AUTHOR);
String title = d.getOptionalString(KEY_FEED_RSS_TITLE);
String link = d.getOptionalString(KEY_FEED_RSS_LINK);
String uri = d.getOptionalString(KEY_FEED_RSS_URI);
RssProperties properties = new RssProperties(url, title, description,
rssAuthor, link, uri);
long added = d.getLong(KEY_FEED_ADDED, 0L); long added = d.getLong(KEY_FEED_ADDED, 0L);
long updated = d.getLong(KEY_FEED_UPDATED, 0L); long updated = d.getLong(KEY_FEED_UPDATED, 0L);
long lastEntryTime = d.getLong(KEY_FEED_LAST_ENTRY, 0L); long lastEntryTime = d.getLong(KEY_FEED_LAST_ENTRY, 0L);
return new Feed(url, blog, localAuthor, desc, rssAuthor, added, return new Feed(blog, localAuthor, properties, added, updated,
updated, lastEntryTime); lastEntryTime);
} }
@Override @Override
@@ -95,17 +106,25 @@ class FeedFactoryImpl implements FeedFactory {
LocalAuthor localAuthor = feed.getLocalAuthor(); LocalAuthor localAuthor = feed.getLocalAuthor();
BdfList authorList = clientHelper.toList(localAuthor); BdfList authorList = clientHelper.toList(localAuthor);
BdfDictionary d = BdfDictionary.of( BdfDictionary d = BdfDictionary.of(
new BdfEntry(KEY_FEED_URL, feed.getUrl()),
new BdfEntry(KEY_FEED_AUTHOR, authorList), new BdfEntry(KEY_FEED_AUTHOR, authorList),
new BdfEntry(KEY_FEED_PRIVATE_KEY, localAuthor.getPrivateKey()), new BdfEntry(KEY_FEED_PRIVATE_KEY, localAuthor.getPrivateKey()),
new BdfEntry(KEY_FEED_ADDED, feed.getAdded()), new BdfEntry(KEY_FEED_ADDED, feed.getAdded()),
new BdfEntry(KEY_FEED_UPDATED, feed.getUpdated()), new BdfEntry(KEY_FEED_UPDATED, feed.getUpdated()),
new BdfEntry(KEY_FEED_LAST_ENTRY, feed.getLastEntryTime()) new BdfEntry(KEY_FEED_LAST_ENTRY, feed.getLastEntryTime())
); );
if (feed.getDescription() != null) RssProperties properties = feed.getProperties();
d.put(KEY_FEED_DESC, feed.getDescription()); if (properties.getUrl() != null)
if (feed.getRssAuthor() != null) d.put(KEY_FEED_URL, properties.getUrl());
d.put(KEY_FEED_RSS_AUTHOR, feed.getRssAuthor()); if (properties.getDescription() != null)
d.put(KEY_FEED_DESC, properties.getDescription());
if (properties.getAuthor() != null)
d.put(KEY_FEED_RSS_AUTHOR, properties.getAuthor());
if (properties.getTitle() != null)
d.put(KEY_FEED_RSS_TITLE, properties.getTitle());
if (properties.getLink() != null)
d.put(KEY_FEED_RSS_LINK, properties.getLink());
if (properties.getUri() != null)
d.put(KEY_FEED_RSS_URI, properties.getUri());
return d; return d;
} }

View File

@@ -297,8 +297,10 @@ class FeedManagerImpl implements FeedManager, EventListener, OpenDatabaseHook,
List<Feed> newFeeds = new ArrayList<>(feeds.size()); List<Feed> newFeeds = new ArrayList<>(feeds.size());
for (Feed feed : feeds) { for (Feed feed : feeds) {
try { try {
String url = feed.getProperties().getUrl();
if (url == null) continue;
// fetch and clean feed // fetch and clean feed
SyndFeed sf = fetchSyndFeed(feed.getUrl()); SyndFeed sf = fetchSyndFeed(url);
// sort and add new entries // sort and add new entries
long lastEntryTime = postFeedEntries(feed, sf.getEntries()); long lastEntryTime = postFeedEntries(feed, sf.getEntries());
newFeeds.add(feedFactory.createFeed(feed, sf, lastEntryTime)); newFeeds.add(feedFactory.createFeed(feed, sf, lastEntryTime));

View File

@@ -25,6 +25,7 @@ import org.briarproject.briar.api.blog.BlogManager;
import org.briarproject.briar.api.blog.BlogPost; import org.briarproject.briar.api.blog.BlogPost;
import org.briarproject.briar.api.blog.BlogPostFactory; import org.briarproject.briar.api.blog.BlogPostFactory;
import org.briarproject.briar.api.feed.Feed; import org.briarproject.briar.api.feed.Feed;
import org.briarproject.briar.api.feed.RssProperties;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.junit.Test; import org.junit.Test;
@@ -83,8 +84,9 @@ public class FeedManagerImplTest extends BrambleMockTestCase {
private final GroupId blogGroupId = blogGroup.getId(); private final GroupId blogGroupId = blogGroup.getId();
private final LocalAuthor localAuthor = getLocalAuthor(); private final LocalAuthor localAuthor = getLocalAuthor();
private final Blog blog = new Blog(blogGroup, localAuthor, true); private final Blog blog = new Blog(blogGroup, localAuthor, true);
private final Feed feed = private final RssProperties properties = new RssProperties(
new Feed("http://example.org", blog, localAuthor, 0); "http://example.org", null, null, null, null, null);
private final Feed feed = new Feed(blog, localAuthor, properties, 0, 0, 0);
private final BdfDictionary feedDict = new BdfDictionary(); private final BdfDictionary feedDict = new BdfDictionary();
private final FeedManagerImpl feedManager = private final FeedManagerImpl feedManager =

View File

@@ -80,7 +80,7 @@ public class FeedManagerIntegrationTest extends BrambleTestCase {
assertTrue(feed.getLastEntryTime() > 0); assertTrue(feed.getLastEntryTime() > 0);
assertTrue(feed.getAdded() > 0); assertTrue(feed.getAdded() > 0);
assertTrue(feed.getUpdated() > 0); assertTrue(feed.getUpdated() > 0);
assertEquals(url, feed.getUrl()); assertEquals(url, feed.getProperties().getUrl());
assertEquals(feedBlog, feed.getBlog()); assertEquals(feedBlog, feed.getBlog());
assertEquals("Schneier on Security", feed.getTitle()); assertEquals("Schneier on Security", feed.getTitle());
assertEquals(feed.getTitle(), feed.getBlog().getName()); assertEquals(feed.getTitle(), feed.getBlog().getName());