refresh.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #!/usr/bin/env python3
  2. import os
  3. import re
  4. from markup import *
  5. #WARNING: if you're going to use special characters like emojis, type them as HTML entities!
  6. def build_entry_html_truncated(entry_id,entry_title,entry_date,entry_body):
  7. entry_body = entry_truncate(entry_body,entry_id)
  8. return """<article id="%s">
  9. <a name="entry_%s"></a>
  10. <h1 class="article-header">&#128196;&nbsp;<a href="articles/%s.html">%s</a></h1>
  11. <span class="metadata">%s</span><br>
  12. %s
  13. </article>
  14. """ % (entry_id,entry_id,entry_id,entry_title,entry_date,entry_body)
  15. def build_entry_html(entry_title,entry_date,entry_body):
  16. return """<!-- !!TITLE:%s -->
  17. <h1 class="article-header">%s</h1>
  18. <p class="metadata">%s</p>
  19. <!-- !!ARTICLE BODY -->
  20. %s
  21. <!-- !!END -->
  22. """ % (entry_title,entry_title,entry_date,entry_body)
  23. def build_entry_xml(entry_id,entry_date,neocities_username,entry_html_body):
  24. entry_desc = entry_truncate(entry_html_body,entry_id)
  25. entry_desc = entry_desc.replace('<','&lt;').replace('>','&gt;')
  26. return """<item>
  27. <guid>%s</guid>
  28. <title>New entry on %s.neocities.org</title>
  29. <pubDate>%s</pubDate>
  30. <description>
  31. %s
  32. </description>
  33. <link>https://%s.neocities.org/%s.html#entry_%s</link>
  34. </item>
  35. """ % (entry_id,neocities_username,entry_date,entry_desc,neocities_username,blog_fname,entry_id)
  36. def entry_truncate(str,entry_id):
  37. #truncates article preview to only the first paragraph, if no paragraphs (<p></p>), the whole entry is returned
  38. truncated=""
  39. paragraphs=str.split("</p>")
  40. if paragraphs.__len__ == 1:
  41. truncated=str+"<nav class=\"entrynav\"><a href=\"#entry_"+entry_id+"\">Permalink</a> | <a href=\"#top\">Top</a> | <a href=\"articles/"+entry_id+".html\">Full entry &#187;</a></nav><br>"
  42. else:
  43. truncated=paragraphs[0]+"</p><nav class=\"entrynav\"><a href=\"#entry_"+entry_id+"\">Permalink</a> | <a href=\"#top\">Top</a> | <a href=\"articles/"+entry_id+".html\">Full entry &#187;</a></nav><br>"
  44. return truncated
  45. def insert_article(entry_html_body, entry_xml_body):
  46. #insert an article into html
  47. blog_html = open("public_html/"+blog_fname+".html").read()
  48. #this is the reason why you shouldn't delete <!-- COMMENTS -->, they are used to insert entries
  49. blog_html_split = blog_html.split("<!-- !!BLOG ENTRIES -->\n")
  50. #split blog html and insert new article
  51. blog_html_top = blog_html_split[0]
  52. blog_html_bottom = blog_html_split[1]
  53. blog_html_new = blog_html_top+"<!-- !!BLOG ENTRIES -->\n"+entry_html_body+blog_html_bottom
  54. #temporary delete blog html and re-write it with new contents
  55. os.system("rm -f public_html/"+blog_fname+".html")
  56. os.system("touch public_html/"+blog_fname+".html")
  57. open("public_html/"+blog_fname+".html","w").write(blog_html_new)
  58. #now let's insert the article into rss feed! :3
  59. blog_rss = open("public_html/rss.xml").read()
  60. #split the file
  61. blog_rss_split = blog_rss.split("<!-- !!BLOG ENTRIES -->\n")
  62. blog_rss_top = blog_rss_split[0]
  63. blog_rss_bottom = blog_rss_split[1]
  64. blog_rss_new = blog_rss_top+"<!-- !!BLOG ENTRIES -->\n"+entry_xml_body+blog_rss_bottom
  65. #let's delete and re-write again...
  66. os.system("rm -f public_html/rss.xml")
  67. os.system("touch public_html/rss.xml")
  68. open("public_html/rss.xml","w").write(blog_rss_new)
  69. def create_article_file(entry_id,entry_title,entry_body_html):
  70. #read article template
  71. template_html = open("public_html/articles/article_template.html").read()
  72. template_html_split = template_html.split("<!-- !!ARTICLE -->\n")
  73. template_html_top=template_html_split[0]
  74. template_html_bottom=template_html_split[1]
  75. #insert article
  76. html_pre = template_html_top+"<!-- !!ARTICLE -->\n"+entry_body_html+template_html_bottom
  77. #insert <title>
  78. html_pre_split = html_pre.split("<title>")
  79. html_pre_top = html_pre_split[0]
  80. html_pre_bottom = html_pre_split[1]
  81. article_html = html_pre_top+"<title>"+entry_title+html_pre_bottom
  82. #create the new entry file! :3
  83. os.system("touch public_html/articles/"+entry_id+".html")
  84. open("public_html/articles/"+entry_id+".html","w").write(article_html)
  85. def add_new_entries(blog_fname):
  86. #count added entries
  87. added=0
  88. #read current html contents from blog file
  89. blog_html = open("public_html/"+blog_fname+".html").read()
  90. #count existing entries
  91. html_current_entries = re.findall("<article id=\"" + r"[0-9]+" + "\">",blog_html)
  92. html_entries_count = html_current_entries.__len__()
  93. #count entry files in "entries/" directory
  94. raw_entries_files = sorted(os.listdir("entries/"))
  95. raw_entries_count = raw_entries_files.__len__()-1 #exclude "README" file
  96. if raw_entries_count > html_entries_count:
  97. for fname in raw_entries_files:
  98. if fname=="README":
  99. continue
  100. entry_id=fname.split('_')[1]
  101. entry_raw=open("entries/"+fname).read()
  102. if entry_raw == "[DELETED]\n" or html_current_entries.count("<article id=\""+entry_id+"\">") > 0:
  103. continue
  104. entry_title=entry_raw.split('\n')[0].split("TITLE:")[1].replace('<','&lt;').replace('>','&gt;')
  105. entry_date=entry_raw.split('\n')[1].split("DATE:")[1]
  106. entry_body_raw=entry_raw.split("BODY:\n")[1]
  107. entry_body_html=mdtohtml(entry_body_raw)
  108. #build "final product"
  109. neocities_username=open("nci.conf").read().split('\n')[0]
  110. entry_full_html=build_entry_html(entry_title,entry_date,entry_body_html)
  111. entry_truncated_html=build_entry_html_truncated(entry_id,entry_title,entry_date,entry_body_html)
  112. entry_full_xml=build_entry_xml(entry_id,entry_date,neocities_username,entry_body_html)
  113. #insert data
  114. insert_article(entry_truncated_html,entry_full_xml)
  115. create_article_file(entry_id,entry_title,entry_full_html)
  116. def del_entries(blog_fname):
  117. #count deleted entries
  118. deleted=0
  119. #check if any raw entry is [DELETED]
  120. raw_entries_files=sorted(os.listdir("entries/"))
  121. raw_entries_count=raw_entries_files.__len__()
  122. for fname in raw_entries_files:
  123. if fname == "README":
  124. continue #exclude README file
  125. entry_id=fname.split("_")[1]
  126. entry_raw=open("entries/"+fname).read()
  127. #check if entry is deleted but still exists in public_html
  128. if entry_raw=="[DELETED]\n":
  129. #delete article page, if file not found, nothing will happen so thanks -f
  130. os.system("rm -f public_html/articles/"+entry_id+".html")
  131. #check if entry still exists in html or rss files and remove it from them if so
  132. blog_html=open("public_html/"+blog_fname+".html").read()
  133. html_current_entries=re.findall("<article id=\""+r"[0-9]+"+"\">",blog_html)
  134. #i suck at html DOM manipulation using python
  135. if html_current_entries.count("<article id=\""+entry_id+"\">") > 0:
  136. blog_html_split = blog_html.split("<article id=\""+entry_id+"\">")
  137. blog_html_top = blog_html_split[0]
  138. blog_html_pre_bottom = blog_html_split[1]
  139. blog_html_bottom = blog_html_pre_bottom[blog_html_pre_bottom.find("</article>")+10:]
  140. blog_html_new = blog_html_top+blog_html_bottom
  141. os.system("rm -f public_html/"+blog_fname+".html")
  142. os.system("touch public_html/"+blog_fname+".html")
  143. open("public_html/"+blog_fname+".html","w").write(blog_html_new)
  144. #delete from rss xml
  145. blog_rss_xml = open("public_html/rss.xml").read()
  146. rss_current_entries = re.findall("<guid>"+r"[0-9]+"+"</guid>",blog_rss_xml)
  147. if rss_current_entries.count("<guid>"+entry_id+"</guid>")>0:
  148. blog_rss_split = blog_rss_xml.split("<item>\n<guid>"+entry_id+"</guid>")
  149. blog_rss_top = blog_rss_split[0]
  150. blog_rss_pre_bottom = blog_rss_split[1]
  151. blog_rss_bottom = blog_rss_pre_bottom[blog_rss_pre_bottom.find("</item>")+7:]
  152. blog_rss_new = blog_rss_top+blog_rss_bottom
  153. os.system("rm -f public_html/rss.xml")
  154. os.system("touch public_html/rss.xml")
  155. open("public_html/rss.xml","w").write(blog_rss_new)
  156. def update_entries(blog_fname):
  157. #count updated entries
  158. updated=0
  159. html_articles = sorted(os.listdir("public_html/articles/"))
  160. #read excluded entries
  161. excluded_raw = ""
  162. to_exclude = []
  163. try:
  164. excluded_raw = open("exclude.conf").read()
  165. except FileNotFoundError:
  166. print("[!] Warning: exclude.conf file not found.")
  167. to_exclude = excluded_raw.split('\n')
  168. #compare html content with mdtohtml(raw) for each existing non-deleted entry
  169. for f_article in html_articles:
  170. if f_article == "article_template.html" or f_article == "style.css":
  171. continue
  172. entry_id = f_article.split(".html")[0]
  173. entry_page = open("public_html/articles/"+f_article).read()
  174. if str(entry_id) in to_exclude:
  175. print("[*] Entry No. "+entry_id+" excluded from being updated.")
  176. continue
  177. entry_title = entry_page.split("<!-- !!TITLE:")[1].split(" -->")[0]
  178. html_split = entry_page.split("<!-- !!ARTICLE BODY -->\n")
  179. html_top = html_split[0]
  180. entry_body = html_split[1]
  181. html_split2 = entry_body.split("<!-- !!END -->\n")
  182. entry_body = html_split2[0]
  183. html_bottom = html_split2[1]
  184. entry_new_title = open("entries/entry_"+entry_id).read().split('\n')[0].split("TITLE:")[1].replace('<',"&lt;").replace('>',"&gt;")
  185. entry_new_body = mdtohtml(open("entries/entry_"+entry_id).read().split('BODY:\n')[1])
  186. #DATES CAN'T BE CHANGED (NO SUPPORT FOR THAT)! DO NOT TRY TO "UPDATE" YOUR ENTRIES POST DATE.
  187. entry_date = open("entries/entry_"+entry_id).read().split('\n')[1].split("DATE:")[1]
  188. if entry_body != entry_new_body or entry_title != entry_new_title:
  189. #modify blog html
  190. bhtml = open("public_html/"+blog_fname+".html").read()
  191. bhtml_split = bhtml.split("<article id=\""+entry_id+"\">\n")
  192. bhtml_top = bhtml_split[0]
  193. bhtml_entry_start = bhtml_split[1]
  194. bhtml_bottom = bhtml_entry_start[bhtml_entry_start.find("</article>")+10:]
  195. entry_new_html = build_entry_html_truncated(entry_id, entry_new_title, entry_date, entry_new_body)
  196. bhtml_new = bhtml_top+entry_new_html+bhtml_bottom
  197. os.system("rm -f public_html/"+blog_fname+".html")
  198. os.system("touch public_html/"+blog_fname+".html")
  199. open("public_html/"+blog_fname+".html","w").write(bhtml_new)
  200. #modify rss
  201. blog_rss_xml = open("public_html/rss.xml").read()
  202. blog_rss_split = blog_rss_xml.split("<item>\n<guid>"+entry_id+"</guid>")
  203. blog_rss_top = blog_rss_split[0]
  204. blog_rss_entry_start = blog_rss_split[1]
  205. blog_rss_bottom = blog_rss_entry_start[blog_rss_entry_start.find("</item>")+7:]
  206. username=open("nci.conf").read().split('\n')[0]
  207. entry_new_xml = build_entry_xml(entry_id,entry_date,username,entry_new_body)
  208. blog_rss_new_xml = blog_rss_top+entry_new_xml+blog_rss_bottom
  209. os.system("rm -f public_html/rss.xml")
  210. os.system("touch public_html/rss.xml")
  211. open("public_html/rss.xml","w").write(blog_rss_new_xml)
  212. #modify entry page
  213. article_html_new = html_top.replace(entry_title,entry_new_title)+"<!-- !!ARTICLE BODY -->\n"+entry_new_body+"<!-- !!END -->\n"+html_bottom
  214. os.system("rm -f public_html/articles/"+entry_id+".html")
  215. os.system("touch public_html/articles/"+entry_id+".html")
  216. open("public_html/articles/"+entry_id+".html","w").write(article_html_new)
  217. #...
  218. print("Updating blog public files...")
  219. #read blog filename from configuration file
  220. blog_fname = open("nci.conf").read().split('\n')[1]
  221. #update
  222. add_new_entries(blog_fname)
  223. del_entries(blog_fname)
  224. update_entries(blog_fname)
  225. print("Files successfully updated! IMPORTANT: Remember to run the \"./push\" command to upload your changed files to Neocities.")
  226. print("OK.")