1 #ifndef NEWSBOAT_RSSFEED_H_
2 #define NEWSBOAT_RSSFEED_H_
3 
4 #include <memory>
5 #include <mutex>
6 #include <string>
7 #include <unordered_map>
8 #include <vector>
9 
10 #include "matchable.h"
11 #include "rssitem.h"
12 #include "utils.h"
13 
14 namespace newsboat {
15 
16 enum class DlStatus { SUCCESS, TO_BE_DOWNLOADED, DURING_DOWNLOAD, DL_ERROR };
17 
18 class Cache;
19 
20 class RssFeed : public Matchable {
21 public:
22 	explicit RssFeed(Cache* c);
23 	RssFeed();
24 	~RssFeed() override;
title_raw()25 	std::string title_raw() const
26 	{
27 		return title_;
28 	}
29 	std::string title() const;
set_title(const std::string & t)30 	void set_title(const std::string& t)
31 	{
32 		title_ = t;
33 		utils::trim(title_);
34 	}
35 
description()36 	std::string description() const
37 	{
38 		return description_;
39 	}
set_description(const std::string & d)40 	void set_description(const std::string& d)
41 	{
42 		description_ = d;
43 	}
44 
link()45 	const std::string& link() const
46 	{
47 		return link_;
48 	}
set_link(const std::string & l)49 	void set_link(const std::string& l)
50 	{
51 		link_ = l;
52 	}
53 
pubDate()54 	std::string pubDate() const
55 	{
56 		return utils::mt_strf_localtime(_("%a, %d %b %Y %T %z"), pubDate_);
57 	}
set_pubDate(time_t t)58 	void set_pubDate(time_t t)
59 	{
60 		pubDate_ = t;
61 	}
62 
63 	bool hidden() const;
64 
items()65 	std::vector<std::shared_ptr<RssItem>>& items()
66 	{
67 		return items_;
68 	}
add_item(std::shared_ptr<RssItem> item)69 	void add_item(std::shared_ptr<RssItem> item)
70 	{
71 		items_.push_back(item);
72 		items_guid_map[item->guid()] = item;
73 	}
add_items(const std::vector<std::shared_ptr<RssItem>> & items)74 	void add_items(const std::vector<std::shared_ptr<RssItem>>& items)
75 	{
76 		for (const auto& item : items) {
77 			items_.push_back(item);
78 			items_guid_map[item->guid()] = item;
79 		}
80 	}
set_items(std::vector<std::shared_ptr<RssItem>> & items)81 	void set_items(std::vector<std::shared_ptr<RssItem>>& items)
82 	{
83 		erase_items(items_.begin(), items_.end());
84 		add_items(items);
85 	}
86 
erase_items(std::vector<std::shared_ptr<RssItem>>::iterator begin,std::vector<std::shared_ptr<RssItem>>::iterator end)87 	void erase_items(std::vector<std::shared_ptr<RssItem>>::iterator begin,
88 		std::vector<std::shared_ptr<RssItem>>::iterator end)
89 	{
90 		for (auto it = begin; it != end; ++it) {
91 			items_guid_map.erase((*it)->guid());
92 		}
93 		items_.erase(begin, end);
94 	}
erase_item(std::vector<std::shared_ptr<RssItem>>::iterator pos)95 	void erase_item(std::vector<std::shared_ptr<RssItem>>::iterator pos)
96 	{
97 		items_guid_map.erase((*pos)->guid());
98 		items_.erase(pos);
99 	}
100 
101 	std::shared_ptr<RssItem> get_item_by_guid(const std::string& guid);
102 	std::shared_ptr<RssItem> get_item_by_guid_unlocked(
103 		const std::string& guid);
104 
105 	/// \brief User-specified feed URL. Can't be empty, otherwise we wouldn't
106 	/// be able to fetch the feed.
rssurl()107 	const std::string& rssurl() const
108 	{
109 		return rssurl_;
110 	}
111 	void set_rssurl(const std::string& u);
112 
113 	unsigned int unread_item_count() const;
total_item_count()114 	unsigned int total_item_count() const
115 	{
116 		return items_.size();
117 	}
118 
119 	void set_tags(const std::vector<std::string>& tags);
120 	bool matches_tag(const std::string& tag);
121 	std::string get_tags() const;
122 	std::string get_firsttag();
123 
124 	nonstd::optional<std::string> attribute_value(const std::string& attr) const
125 	override;
126 
127 	void update_items(std::vector<std::shared_ptr<RssFeed>> feeds);
128 
set_query(const std::string & s)129 	void set_query(const std::string& s)
130 	{
131 		query = s;
132 	}
133 
is_query_feed()134 	bool is_query_feed() const
135 	{
136 		return rssurl_.substr(0, 6) == "query:";
137 	}
138 
is_search_feed()139 	bool is_search_feed() const
140 	{
141 		return search_feed;
142 	}
143 
set_search_feed(bool b)144 	void set_search_feed(bool b)
145 	{
146 		search_feed = b;
147 	}
148 
149 	void sort(const ArticleSortStrategy& sort_strategy);
150 	void sort_unlocked(const ArticleSortStrategy& sort_strategy);
151 
152 	void purge_deleted_items();
153 
set_rtl(bool b)154 	void set_rtl(bool b)
155 	{
156 		is_rtl_ = b;
157 	}
is_rtl()158 	bool is_rtl()
159 	{
160 		return is_rtl_;
161 	}
162 
set_index(unsigned int i)163 	void set_index(unsigned int i)
164 	{
165 		idx = i;
166 	}
get_index()167 	unsigned int get_index()
168 	{
169 		return idx;
170 	}
171 
set_order(unsigned int x)172 	void set_order(unsigned int x)
173 	{
174 		order = x;
175 	}
get_order()176 	unsigned int get_order()
177 	{
178 		return order;
179 	}
180 
181 	void set_feedptrs(std::shared_ptr<RssFeed> self);
182 
183 	std::string get_status();
184 
reset_status()185 	void reset_status()
186 	{
187 		std::lock_guard<std::mutex> guard(status_mutex_);
188 		status_ = DlStatus::TO_BE_DOWNLOADED;
189 	}
set_status(DlStatus st)190 	void set_status(DlStatus st)
191 	{
192 		std::lock_guard<std::mutex> guard(status_mutex_);
193 		status_ = st;
194 	}
195 
196 	void unload();
197 	void load();
198 
199 	void mark_all_items_read();
200 
201 	// this is ugly, but makes it possible to lock items use e.g. from the Cache class
202 	mutable std::mutex item_mutex;
203 
204 private:
205 	std::string title_;
206 	std::string description_;
207 	std::string link_;
208 	time_t pubDate_;
209 	std::string rssurl_;
210 	std::vector<std::shared_ptr<RssItem>> items_;
211 	std::unordered_map<std::string, std::shared_ptr<RssItem>>
212 		items_guid_map;
213 	std::vector<std::string> tags_;
214 	std::string query;
215 
216 	Cache* ch;
217 
218 	bool search_feed;
219 	bool is_rtl_;
220 	unsigned int idx;
221 	unsigned int order;
222 	std::mutex items_guid_map_mutex;
223 
224 	DlStatus status_;
225 	std::mutex status_mutex_;
226 };
227 
228 } // namespace newsboat
229 
230 #endif /* NEWSBOAT_RSSFEED_H_ */
231