diff options
Diffstat (limited to 'src/feeds.c')
-rw-r--r-- | src/feeds.c | 78 |
1 files changed, 50 insertions, 28 deletions
diff --git a/src/feeds.c b/src/feeds.c index cbfc36d0..5034c616 100644 --- a/src/feeds.c +++ b/src/feeds.c | |||
@@ -35,6 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
35 | #include <the_Foundation/stringset.h> | 35 | #include <the_Foundation/stringset.h> |
36 | #include <the_Foundation/thread.h> | 36 | #include <the_Foundation/thread.h> |
37 | #include <SDL_timer.h> | 37 | #include <SDL_timer.h> |
38 | #include <ctype.h> | ||
38 | 39 | ||
39 | iDeclareType(Feeds) | 40 | iDeclareType(Feeds) |
40 | iDeclareType(FeedJob) | 41 | iDeclareType(FeedJob) |
@@ -109,12 +110,24 @@ static void submit_FeedJob_(iFeedJob *d) { | |||
109 | } | 110 | } |
110 | 111 | ||
111 | static iFeedJob *startNextJob_Feeds_(iFeeds *d) { | 112 | static iFeedJob *startNextJob_Feeds_(iFeeds *d) { |
113 | if (isEmpty_PtrArray(&d->jobs)) { | ||
114 | return NULL; | ||
115 | } | ||
112 | iFeedJob *job; | 116 | iFeedJob *job; |
113 | if (take_PtrArray(&d->jobs, 0, (void **) &job)) { | 117 | take_PtrArray(&d->jobs, 0, (void **) &job); |
114 | submit_FeedJob_(job); | 118 | submit_FeedJob_(job); |
115 | return job; | 119 | return job; |
120 | } | ||
121 | |||
122 | static void trimTitle_(iString *title) { | ||
123 | const char *start = constBegin_String(title); | ||
124 | iConstForEach(String, i, title) { | ||
125 | start = i.pos; | ||
126 | if (!isSpace_Char(i.value) && !(i.value < 128 && ispunct(i.value))) { | ||
127 | break; | ||
128 | } | ||
116 | } | 129 | } |
117 | return NULL; | 130 | remove_Block(&title->chars, 0, start - constBegin_String(title)); |
118 | } | 131 | } |
119 | 132 | ||
120 | static void parseResult_FeedJob_(iFeedJob *d) { | 133 | static void parseResult_FeedJob_(iFeedJob *d) { |
@@ -123,7 +136,7 @@ static void parseResult_FeedJob_(iFeedJob *d) { | |||
123 | iBeginCollect(); | 136 | iBeginCollect(); |
124 | iRegExp *linkPattern = | 137 | iRegExp *linkPattern = |
125 | new_RegExp("^=>\\s*([^\\s]+)\\s+" | 138 | new_RegExp("^=>\\s*([^\\s]+)\\s+" |
126 | "([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])" | 139 | "([0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9])" |
127 | "([^0-9].*)", | 140 | "([^0-9].*)", |
128 | 0); | 141 | 0); |
129 | iString src; | 142 | iString src; |
@@ -141,8 +154,11 @@ static void parseResult_FeedJob_(iFeedJob *d) { | |||
141 | iFeedEntry *entry = new_FeedEntry(); | 154 | iFeedEntry *entry = new_FeedEntry(); |
142 | entry->bookmarkId = d->bookmarkId; | 155 | entry->bookmarkId = d->bookmarkId; |
143 | setRange_String(&entry->url, url); | 156 | setRange_String(&entry->url, url); |
144 | set_String(&entry->url, collect_String(lower_String(&entry->url))); | 157 | set_String(&entry->url, |
158 | absoluteUrl_String(url_GmRequest(d->request), | ||
159 | collect_String(lower_String(&entry->url)))); | ||
145 | setRange_String(&entry->title, title); | 160 | setRange_String(&entry->title, title); |
161 | trimTitle_(&entry->title); | ||
146 | int year, month, day; | 162 | int year, month, day; |
147 | sscanf(date.start, "%04d-%02d-%02d", &year, &month, &day); | 163 | sscanf(date.start, "%04d-%02d-%02d", &year, &month, &day); |
148 | init_Time( | 164 | init_Time( |
@@ -177,7 +193,7 @@ static iBool updateEntries_Feeds_(iFeeds *d, iPtrArray *incoming) { | |||
177 | delete_FeedEntry(entry); | 193 | delete_FeedEntry(entry); |
178 | if (changed) { | 194 | if (changed) { |
179 | /* TODO: better to use a new flag for read feed entries? */ | 195 | /* TODO: better to use a new flag for read feed entries? */ |
180 | removeUrl_Visited(visited_App(), &entry->url); | 196 | removeUrl_Visited(visited_App(), &existing->url); |
181 | gotNew = iTrue; | 197 | gotNew = iTrue; |
182 | } | 198 | } |
183 | } | 199 | } |
@@ -206,6 +222,7 @@ static iThreadResult fetch_Feeds_(iThread *thread) { | |||
206 | } | 222 | } |
207 | } | 223 | } |
208 | sleep_Thread(0.5); /* TODO: wait on a Condition so we can exit quickly */ | 224 | sleep_Thread(0.5); /* TODO: wait on a Condition so we can exit quickly */ |
225 | if (d->stopWorker) break; | ||
209 | size_t ongoing = 0; | 226 | size_t ongoing = 0; |
210 | iForIndices(i, work) { | 227 | iForIndices(i, work) { |
211 | if (work[i]) { | 228 | if (work[i]) { |
@@ -241,16 +258,18 @@ static iBool startWorker_Feeds_(iFeeds *d) { | |||
241 | if (d->worker) { | 258 | if (d->worker) { |
242 | return iFalse; /* Oops? */ | 259 | return iFalse; /* Oops? */ |
243 | } | 260 | } |
244 | d->worker = new_Thread(fetch_Feeds_); | ||
245 | /* Queue up all the subscriptions for the worker. */ | 261 | /* Queue up all the subscriptions for the worker. */ |
246 | iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), NULL, isSubscribed_, NULL)) { | 262 | iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), NULL, isSubscribed_, NULL)) { |
247 | iFeedJob job; | 263 | iFeedJob* job = new_FeedJob(i.ptr); |
248 | init_FeedJob(&job, i.ptr); | 264 | pushBack_PtrArray(&d->jobs, job); |
249 | pushBack_Array(&d->jobs, &job); | 265 | } |
266 | if (!isEmpty_Array(&d->jobs)) { | ||
267 | d->worker = new_Thread(fetch_Feeds_); | ||
268 | d->stopWorker = iFalse; | ||
269 | start_Thread(d->worker); | ||
270 | return iTrue; | ||
250 | } | 271 | } |
251 | d->stopWorker = iFalse; | 272 | return iFalse; |
252 | start_Thread(d->worker); | ||
253 | return iTrue; | ||
254 | } | 273 | } |
255 | 274 | ||
256 | static uint32_t refresh_Feeds_(uint32_t interval, void *data) { | 275 | static uint32_t refresh_Feeds_(uint32_t interval, void *data) { |
@@ -265,7 +284,11 @@ static void stopWorker_Feeds_(iFeeds *d) { | |||
265 | join_Thread(d->worker); | 284 | join_Thread(d->worker); |
266 | iReleasePtr(&d->worker); | 285 | iReleasePtr(&d->worker); |
267 | } | 286 | } |
268 | /* TODO: Clear jobs */ | 287 | /* Clear remaining jobs. */ |
288 | iForEach(PtrArray, i, &d->jobs) { | ||
289 | delete_FeedJob(i.ptr); | ||
290 | } | ||
291 | clear_PtrArray(&d->jobs); | ||
269 | } | 292 | } |
270 | 293 | ||
271 | static int cmp_FeedEntryPtr_(const void *a, const void *b) { | 294 | static int cmp_FeedEntryPtr_(const void *a, const void *b) { |
@@ -308,7 +331,7 @@ iDeclareType(FeedHashNode) | |||
308 | 331 | ||
309 | struct Impl_FeedHashNode { | 332 | struct Impl_FeedHashNode { |
310 | iHashNode node; | 333 | iHashNode node; |
311 | uint32_t bookmarkId; | 334 | uint32_t bookmarkId; |
312 | }; | 335 | }; |
313 | 336 | ||
314 | static void load_Feeds_(iFeeds *d) { | 337 | static void load_Feeds_(iFeeds *d) { |
@@ -353,27 +376,26 @@ static void load_Feeds_(iFeeds *d) { | |||
353 | } | 376 | } |
354 | case 2: { | 377 | case 2: { |
355 | const uint32_t feedId = strtoul(line.start, NULL, 16); | 378 | const uint32_t feedId = strtoul(line.start, NULL, 16); |
356 | nextSplit_Rangecc(range_Block(src), "\n", &line); | 379 | if (!nextSplit_Rangecc(range_Block(src), "\n", &line)) break; |
357 | const unsigned long long ts = strtoull(line.start, NULL, 10); | 380 | const unsigned long long ts = strtoull(line.start, NULL, 10); |
358 | nextSplit_Rangecc(range_Block(src), "\n", &line); | 381 | if (!nextSplit_Rangecc(range_Block(src), "\n", &line)) break; |
359 | iString url; | 382 | const iRangecc urlRange = line; |
360 | initRange_String(&url, line); | 383 | if (!nextSplit_Rangecc(range_Block(src), "\n", &line)) break; |
361 | nextSplit_Rangecc(range_Block(src), "\n", &line); | 384 | const iRangecc titleRange = line; |
362 | iString title; | 385 | iString *url = newRange_String(urlRange); |
363 | initRange_String(&title, line); | 386 | iString *title = newRange_String(titleRange); |
364 | nextSplit_Rangecc(range_Block(src), "\n", &line); | ||
365 | /* Look it up in the hash. */ | 387 | /* Look it up in the hash. */ |
366 | const iFeedHashNode *node = (iFeedHashNode *) value_Hash(feeds, feedId); | 388 | const iFeedHashNode *node = (iFeedHashNode *) value_Hash(feeds, feedId); |
367 | if (node) { | 389 | if (node) { |
368 | iFeedEntry *entry = new_FeedEntry(); | 390 | iFeedEntry *entry = new_FeedEntry(); |
369 | entry->bookmarkId = node->bookmarkId; | 391 | entry->bookmarkId = node->bookmarkId; |
370 | entry->timestamp.ts.tv_sec = ts; | 392 | entry->timestamp.ts.tv_sec = ts; |
371 | set_String(&entry->url, &url); | 393 | set_String(&entry->url, url); |
372 | set_String(&entry->title, &title); | 394 | set_String(&entry->title, title); |
373 | insert_SortedArray(&d->entries, &entry); | 395 | insert_SortedArray(&d->entries, &entry); |
374 | } | 396 | } |
375 | deinit_String(&title); | 397 | delete_String(title); |
376 | deinit_String(&url); | 398 | delete_String(url); |
377 | break; | 399 | break; |
378 | } | 400 | } |
379 | } | 401 | } |