16516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruimport markdown 26516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Querufrom markdown import etree 36516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 46516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruDEFAULT_URL = "http://www.freewisdom.org/projects/python-markdown/" 56516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruDEFAULT_CREATOR = "Yuri Takhteyev" 66516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruDEFAULT_TITLE = "Markdown in Python" 76516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruGENERATOR = "http://www.freewisdom.org/projects/python-markdown/markdown2rss" 86516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 96516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Querumonth_map = { "Jan" : "01", 106516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru "Feb" : "02", 116516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru "March" : "03", 126516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru "April" : "04", 136516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru "May" : "05", 146516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru "June" : "06", 156516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru "July" : "07", 166516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru "August" : "08", 176516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru "September" : "09", 186516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru "October" : "10", 196516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru "November" : "11", 206516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru "December" : "12" } 216516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 226516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Querudef get_time(heading): 236516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 246516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru heading = heading.split("-")[0] 256516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru heading = heading.strip().replace(",", " ").replace(".", " ") 266516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 276516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru month, date, year = heading.split() 286516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru month = month_map[month] 296516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 306516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return rdftime(" ".join((month, date, year, "12:00:00 AM"))) 316516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 326516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Querudef rdftime(time): 336516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 346516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru time = time.replace(":", " ") 356516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru time = time.replace("/", " ") 366516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru time = time.split() 376516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return "%s-%s-%sT%s:%s:%s-08:00" % (time[0], time[1], time[2], 386516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru time[3], time[4], time[5]) 396516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 406516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 416516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Querudef get_date(text): 426516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return "date" 436516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 446516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass RssExtension (markdown.Extension): 456516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 466516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def extendMarkdown(self, md, md_globals): 476516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 486516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.config = { 'URL' : [DEFAULT_URL, "Main URL"], 496516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 'CREATOR' : [DEFAULT_CREATOR, "Feed creator's name"], 506516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 'TITLE' : [DEFAULT_TITLE, "Feed title"] } 516516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 526516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru md.xml_mode = True 536516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 546516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru # Insert a tree-processor that would actually add the title tag 556516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru treeprocessor = RssTreeProcessor(md) 566516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru treeprocessor.ext = self 576516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru md.treeprocessors['rss'] = treeprocessor 586516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru md.stripTopLevelTags = 0 596516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru md.docType = '<?xml version="1.0" encoding="utf-8"?>\n' 606516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 616516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass RssTreeProcessor(markdown.treeprocessors.Treeprocessor): 626516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 636516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def run (self, root): 646516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 656516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru rss = etree.Element("rss") 666516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru rss.set("version", "2.0") 676516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 686516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru channel = etree.SubElement(rss, "channel") 696516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 706516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru for tag, text in (("title", self.ext.getConfig("TITLE")), 716516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ("link", self.ext.getConfig("URL")), 726516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ("description", None)): 736516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 746516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru element = etree.SubElement(channel, tag) 756516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru element.text = text 766516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 776516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru for child in root: 786516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 796516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if child.tag in ["h1", "h2", "h3", "h4", "h5"]: 806516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 816516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru heading = child.text.strip() 826516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru item = etree.SubElement(channel, "item") 836516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru link = etree.SubElement(item, "link") 846516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru link.text = self.ext.getConfig("URL") 856516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru title = etree.SubElement(item, "title") 866516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru title.text = heading 876516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 886516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru guid = ''.join([x for x in heading if x.isalnum()]) 896516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru guidElem = etree.SubElement(item, "guid") 906516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru guidElem.text = guid 916516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru guidElem.set("isPermaLink", "false") 926516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 936516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru elif child.tag in ["p"]: 946516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru try: 956516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru description = etree.SubElement(item, "description") 966516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru except UnboundLocalError: 976516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru # Item not defined - moving on 986516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru pass 996516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: 1006516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if len(child): 1016516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru content = "\n".join([etree.tostring(node) 1026516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru for node in child]) 1036516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: 1046516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru content = child.text 1056516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru pholder = self.markdown.htmlStash.store( 1066516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru "<![CDATA[ %s]]>" % content) 1076516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru description.text = pholder 1086516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1096516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return rss 1106516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1116516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1126516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Querudef makeExtension(configs): 1136516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1146516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return RssExtension(configs) 115