html_generator.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. '''
  2. This is a library for formatting text outputs as nice HTML.
  3. '''
  4. import os
  5. import re
  6. import time
  7. from pathlib import Path
  8. import markdown
  9. from PIL import Image
  10. # This is to store the paths to the thumbnails of the profile pictures
  11. image_cache = {}
  12. with open(Path(__file__).resolve().parent / '../css/html_readable_style.css', 'r') as f:
  13. readable_css = f.read()
  14. with open(Path(__file__).resolve().parent / '../css/html_4chan_style.css', 'r') as css_f:
  15. _4chan_css = css_f.read()
  16. with open(Path(__file__).resolve().parent / '../css/html_cai_style.css', 'r') as f:
  17. cai_css = f.read()
  18. def fix_newlines(string):
  19. string = string.replace('\n', '\n\n')
  20. string = re.sub(r"\n{3,}", "\n\n", string)
  21. string = string.strip()
  22. return string
  23. # This could probably be generalized and improved
  24. def convert_to_markdown(string):
  25. string = string.replace('\\begin{code}', '```')
  26. string = string.replace('\\end{code}', '```')
  27. string = string.replace('\\begin{blockquote}', '> ')
  28. string = string.replace('\\end{blockquote}', '')
  29. string = re.sub(r"(.)```", r"\1\n```", string)
  30. string = fix_newlines(string)
  31. return markdown.markdown(string, extensions=['fenced_code'])
  32. def generate_basic_html(string):
  33. string = convert_to_markdown(string)
  34. string = f'<style>{readable_css}</style><div class="container">{string}</div>'
  35. return string
  36. def process_post(post, c):
  37. t = post.split('\n')
  38. number = t[0].split(' ')[1]
  39. if len(t) > 1:
  40. src = '\n'.join(t[1:])
  41. else:
  42. src = ''
  43. src = re.sub('>', '&gt;', src)
  44. src = re.sub('(&gt;&gt;[0-9]*)', '<span class="quote">\\1</span>', src)
  45. src = re.sub('\n', '<br>\n', src)
  46. src = f'<blockquote class="message">{src}\n'
  47. src = f'<span class="name">Anonymous </span> <span class="number">No.{number}</span>\n{src}'
  48. return src
  49. def generate_4chan_html(f):
  50. posts = []
  51. post = ''
  52. c = -2
  53. for line in f.splitlines():
  54. line += "\n"
  55. if line == '-----\n':
  56. continue
  57. elif line.startswith('--- '):
  58. c += 1
  59. if post != '':
  60. src = process_post(post, c)
  61. posts.append(src)
  62. post = line
  63. else:
  64. post += line
  65. if post != '':
  66. src = process_post(post, c)
  67. posts.append(src)
  68. for i in range(len(posts)):
  69. if i == 0:
  70. posts[i] = f'<div class="op">{posts[i]}</div>\n'
  71. else:
  72. posts[i] = f'<div class="reply">{posts[i]}</div>\n'
  73. output = ''
  74. output += f'<style>{_4chan_css}</style><div id="parent"><div id="container">'
  75. for post in posts:
  76. output += post
  77. output += '</div></div>'
  78. output = output.split('\n')
  79. for i in range(len(output)):
  80. output[i] = re.sub(r'^(&gt;(.*?)(<br>|</div>))', r'<span class="greentext">\1</span>', output[i])
  81. output[i] = re.sub(r'^<blockquote class="message">(&gt;(.*?)(<br>|</div>))', r'<blockquote class="message"><span class="greentext">\1</span>', output[i])
  82. output = '\n'.join(output)
  83. return output
  84. def get_image_cache(path):
  85. cache_folder = Path("cache")
  86. if not cache_folder.exists():
  87. cache_folder.mkdir()
  88. mtime = os.stat(path).st_mtime
  89. if (path in image_cache and mtime != image_cache[path][0]) or (path not in image_cache):
  90. img = Image.open(path)
  91. img.thumbnail((200, 200))
  92. output_file = Path(f'cache/{path.name}_cache.png')
  93. img.convert('RGB').save(output_file, format='PNG')
  94. image_cache[path] = [mtime, output_file.as_posix()]
  95. return image_cache[path][1]
  96. def generate_chat_html(history, name1, name2):
  97. output = f'<style>{cai_css}</style><div class="chat" id="chat">'
  98. # The time.time() is to prevent the brower from caching the image
  99. img_bot = f'<img src="file/cache/pfp_character.png?{time.time()}">' if Path("cache/pfp_character.png").exists() else ''
  100. img_me = f'<img src="file/cache/pfp_me.png?{time.time()}">' if Path("cache/pfp_me.png").exists() else ''
  101. for i,_row in enumerate(history[::-1]):
  102. row = [convert_to_markdown(entry) for entry in _row]
  103. output += f"""
  104. <div class="message">
  105. <div class="circle-bot">
  106. {img_bot}
  107. </div>
  108. <div class="text">
  109. <div class="username">
  110. {name2}
  111. </div>
  112. <div class="message-body">
  113. {row[1]}
  114. </div>
  115. </div>
  116. </div>
  117. """
  118. if len(row[0]) == 0: # don't display empty user messages
  119. continue
  120. output += f"""
  121. <div class="message">
  122. <div class="circle-you">
  123. {img_me}
  124. </div>
  125. <div class="text">
  126. <div class="username">
  127. {name1}
  128. </div>
  129. <div class="message-body">
  130. {row[0]}
  131. </div>
  132. </div>
  133. </div>
  134. """
  135. output += "</div>"
  136. return output