Skip to content

Commit 04f0d70

Browse files
committed
RSS: Add support for $content/$summary_detail/$title_detail
1 parent edb13f6 commit 04f0d70

File tree

2 files changed

+121
-1
lines changed

2 files changed

+121
-1
lines changed

plugins/RSS/plugin.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,35 @@ def format_entry(self, network, channel, feed, entry, is_announce):
497497
isinstance(v, str)}
498498
kwargs["feed_name"] = feed.name
499499
kwargs.update(entry)
500+
for (key, value) in list(kwargs.items()):
501+
# First look for plain text
502+
if isinstance(value, list):
503+
for item in value:
504+
if isinstance(item, dict) and 'value' in item and \
505+
item.get('type') == 'text/plain':
506+
value = item['value']
507+
break
508+
# Then look for HTML text or URL
509+
if isinstance(value, list):
510+
for item in value:
511+
if isinstance(item, dict) and item.get('type') in \
512+
('text/html', 'application/xhtml+xml'):
513+
if 'value' in item:
514+
value = utils.web.htmlToText(item['value'])
515+
elif 'href' in item:
516+
value = item['href']
517+
# Then fall back to any URL
518+
if isinstance(value, list):
519+
for item in value:
520+
if isinstance(item, dict) and 'href' in item:
521+
value = item['href']
522+
break
523+
# Finally, as a last resort, use the value as-is
524+
if isinstance(value, list):
525+
for item in value:
526+
if isinstance(item, dict) and 'value' in item:
527+
value = item['value']
528+
kwargs[key] = value
500529
s = string.Template(template).safe_substitute(entry, **kwargs, date=date)
501530
return self._normalize_entry(s)
502531

plugins/RSS/test.py

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
</rss>
6060
"""
6161

62-
6362
class MockResponse:
6463
headers = {}
6564
url = ''
@@ -359,6 +358,98 @@ def testDescription(self, mock):
359358
self.assertRegexp('rss http://xkcd.com/rss.xml',
360359
'On the other hand, the refractor\'s')
361360

361+
@mock_urllib
362+
def testContentHtmlOnly(self, mock):
363+
timeFastForward(1.1)
364+
with conf.supybot.plugins.RSS.format.context('$content'):
365+
mock._data = """
366+
<?xml version="1.0" encoding="UTF-8"?>
367+
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-US">
368+
<title>Recent Commits to anope:2.0</title>
369+
<updated>2023-10-04T16:14:39Z</updated>
370+
<entry>
371+
<title>title with &lt;pre&gt;HTML&lt;pre&gt;</title>
372+
<updated>2023-10-04T16:14:39Z</updated>
373+
<content type="html">
374+
content with &lt;pre&gt;HTML&lt;pre&gt;
375+
</content>
376+
</entry>
377+
</feed>"""
378+
self.assertRegexp('rss https://example.org',
379+
'content with HTML')
380+
381+
@mock_urllib
382+
def testContentXhtmlOnly(self, mock):
383+
timeFastForward(1.1)
384+
with conf.supybot.plugins.RSS.format.context('$content'):
385+
mock._data = """
386+
<?xml version="1.0" encoding="UTF-8"?>
387+
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-US">
388+
<title>Recent Commits to anope:2.0</title>
389+
<updated>2023-10-04T16:14:39Z</updated>
390+
<entry>
391+
<title>title with &lt;pre&gt;HTML&lt;pre&gt;</title>
392+
<updated>2023-10-04T16:14:39Z</updated>
393+
<content type="xhtml">
394+
<div xmlns="http://www.w3.org/1999/xhtml">
395+
content with <pre>XHTML<pre>
396+
</div>
397+
</content>
398+
</entry>
399+
</feed>"""
400+
self.assertRegexp('rss https://example.org',
401+
'content with XHTML')
402+
403+
@mock_urllib
404+
def testContentHtmlAndPlaintext(self, mock):
405+
timeFastForward(1.1)
406+
with conf.supybot.plugins.RSS.format.context('$content'):
407+
mock._data = """
408+
<?xml version="1.0" encoding="UTF-8"?>
409+
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-US">
410+
<title>Recent Commits to anope:2.0</title>
411+
<updated>2023-10-04T16:14:39Z</updated>
412+
<entry>
413+
<title>title with &lt;pre&gt;HTML&lt;pre&gt;</title>
414+
<updated>2023-10-04T16:14:39Z</updated>
415+
<!-- Atom spec says multiple contents is invalid, feedparser says it's not.
416+
I like having the option, so let's make sure we support it. -->
417+
<content type="html">
418+
content with &lt;pre&gt;HTML&lt;pre&gt;
419+
</content>
420+
<content type="text">
421+
content with plaintext
422+
</content>
423+
</entry>
424+
</feed>"""
425+
self.assertRegexp('rss https://example.org',
426+
'content with plaintext')
427+
428+
@mock_urllib
429+
def testContentPlaintextAndHtml(self, mock):
430+
timeFastForward(1.1)
431+
with conf.supybot.plugins.RSS.format.context('$content'):
432+
mock._data = """
433+
<?xml version="1.0" encoding="UTF-8"?>
434+
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-US">
435+
<title>Recent Commits to anope:2.0</title>
436+
<updated>2023-10-04T16:14:39Z</updated>
437+
<entry>
438+
<title>title with &lt;pre&gt;HTML&lt;pre&gt;</title>
439+
<updated>2023-10-04T16:14:39Z</updated>
440+
<!-- Atom spec says multiple contents is invalid, feedparser says it's not.
441+
I like having the option, so let's make sure we support it. -->
442+
<content type="text">
443+
content with plaintext
444+
</content>
445+
<content type="html">
446+
content with &lt;pre&gt;HTML&lt;pre&gt;
447+
</content>
448+
</entry>
449+
</feed>"""
450+
self.assertRegexp('rss https://example.org',
451+
'content with plaintext')
452+
362453
@mock_urllib
363454
def testFeedAttribute(self, mock):
364455
timeFastForward(1.1)

0 commit comments

Comments
 (0)