func_render_namumark.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. from .func_tool import *
  2. class class_do_render_namumark:
  3. def __init__(self, curs, doc_name, doc_data, doc_include, lang_data):
  4. self.curs = curs
  5. self.doc_data = doc_data
  6. self.doc_name = doc_name
  7. self.doc_include = doc_include
  8. self.lang_data = lang_data
  9. self.data_temp_storage = {}
  10. self.data_temp_storage_count = 0
  11. self.data_backlink = []
  12. self.data_toc = ''
  13. self.data_footnote = ''
  14. self.data_category = ''
  15. self.render_data = self.doc_data
  16. self.render_data = html.escape(self.render_data)
  17. self.render_data = '<back_br>\n' + self.render_data + '\n<front_br>'
  18. self.render_data_js = ''
  19. def get_tool_lang(self, name):
  20. if name in self.lang_data:
  21. return self.lang_data[name]
  22. else:
  23. return name + ' (RENDER LANG)'
  24. def get_tool_temp_storage(self, data_A = '', data_B = ''):
  25. self.data_temp_storage_count += 1
  26. data_name = 'render_' + str(self.data_temp_storage_count)
  27. self.data_temp_storage[data_name] = data_A
  28. self.data_temp_storage['/' + data_name] = data_B
  29. return data_name
  30. def get_tool_data_restore(self, data):
  31. storage_count = self.data_temp_storage_count * 3
  32. storage_regex = r'<(\/?render_(?:[0-9]+))>'
  33. while 1:
  34. if not re.search(storage_regex, data):
  35. break
  36. if storage_count < 0:
  37. print('Error : render restore count overflow')
  38. break
  39. else:
  40. data = re.sub(storage_regex, lambda match : self.data_temp_storage[match.group(1)], data, 1)
  41. storage_count -= 1
  42. return data
  43. def do_render_text(self):
  44. # <b> function
  45. def do_render_text_bold(match):
  46. data = match.group(1)
  47. data_name = self.get_tool_temp_storage('<b>', '</b>')
  48. return '<' + data_name + '>' + data + '</' + data_name + '>'
  49. # <b>
  50. self.render_data = re.sub(r"&#x27;&#x27;&#x27;((?:(?!&#x27;&#x27;&#x27;).)+)&#x27;&#x27;&#x27;", do_render_text_bold, self.render_data)
  51. # <i> function
  52. def do_render_text_italic(match):
  53. data = match.group(1)
  54. data_name = self.get_tool_temp_storage('<i>', '</i>')
  55. return '<' + data_name + '>' + data + '</' + data_name + '>'
  56. # <i>
  57. self.render_data = re.sub(r"&#x27;&#x27;((?:(?!&#x27;&#x27;).)+)&#x27;&#x27;", do_render_text_italic, self.render_data)
  58. # <u> function
  59. def do_render_text_under(match):
  60. data = match.group(1)
  61. data_name = self.get_tool_temp_storage('<u>', '</u>')
  62. return '<' + data_name + '>' + data + '</' + data_name + '>'
  63. # <u>
  64. self.render_data = re.sub(r"__((?:(?!__).)+)__", do_render_text_under, self.render_data)
  65. # <sup> function
  66. def do_render_text_sup(match):
  67. data = match.group(1)
  68. data_name = self.get_tool_temp_storage('<sup>', '</sup>')
  69. return '<' + data_name + '>' + data + '</' + data_name + '>'
  70. # <sup>
  71. self.render_data = re.sub(r"\^\^\^((?:(?!\^\^\^).)+)\^\^\^", do_render_text_sup, self.render_data)
  72. # <sup> 2
  73. self.render_data = re.sub(r"\^\^((?:(?!\^\^).)+)\^\^", do_render_text_sup, self.render_data)
  74. # <sub> function
  75. def do_render_text_sub(match):
  76. data = match.group(1)
  77. data_name = self.get_tool_temp_storage('<sub>', '</sub>')
  78. return '<' + data_name + '>' + data + '</' + data_name + '>'
  79. # <sub>
  80. self.render_data = re.sub(r",,,((?:(?!,,,).)+),,,", do_render_text_sub, self.render_data)
  81. # <sub> 2
  82. self.render_data = re.sub(r",,((?:(?!,,).)+),,", do_render_text_sub, self.render_data)
  83. # <sub> function
  84. def do_render_text_strike(match):
  85. data = match.group(1)
  86. data_name = self.get_tool_temp_storage('<s>', '</s>')
  87. return '<' + data_name + '>' + data + '</' + data_name + '>'
  88. # <s>
  89. self.render_data = re.sub(r"--((?:(?!--).)+)--", do_render_text_strike, self.render_data)
  90. # <s> 2
  91. self.render_data = re.sub(r"~~((?:(?!~~).)+)~~", do_render_text_strike, self.render_data)
  92. def do_render_heading(self):
  93. toc_list = []
  94. # make heading base
  95. heading_regex = r'\n((={1,6})(#?) ?([^\n]+))\n'
  96. heading_count_all = len(re.findall(heading_regex, self.render_data)) * 3
  97. heading_stack = [0, 0, 0, 0, 0, 0]
  98. while 1:
  99. if not re.search(heading_regex, self.render_data):
  100. break
  101. elif heading_count_all < 0:
  102. print('Error : render heading count overflow')
  103. break
  104. else:
  105. heading_data = re.search(heading_regex, self.render_data)
  106. heading_data = heading_data.groups()
  107. heading_data_last_regex = r' ?(#?={1,6})$'
  108. heading_data_last = re.search(heading_data_last_regex, heading_data[3])
  109. heading_data_last = heading_data_last.group(1)
  110. heading_data_text = re.sub(heading_data_last_regex, '', heading_data[3])
  111. heading_data_diff = heading_data[2] + heading_data[1]
  112. if heading_data_diff != heading_data_last:
  113. # front != back -> restore
  114. heading_data_all = heading_data[0]
  115. for for_a in reversed(range(1, 7)):
  116. for_a_str = str(for_a)
  117. heading_restore_regex = re.compile('^={' + for_a_str + '}|={' + for_a_str + '}$')
  118. heading_data_all = re.sub(heading_restore_regex, '<heading_' + for_a_str + '>', heading_data_all)
  119. self.render_data = re.sub(heading_regex, '\n' + heading_data_all + '\n', self.render_data, 1)
  120. else:
  121. heading_level = len(heading_data[1])
  122. heading_level_str = str(heading_level)
  123. heading_stack[heading_level - 1] += 1
  124. for for_a in range(heading_level, 6):
  125. heading_stack[for_a] = 0
  126. heading_stack_str = '.'.join([str(for_a) for for_a in heading_stack])
  127. heading_stack_str = re.sub(r'(\.0)+$', '', heading_stack_str)
  128. toc_list += [['', heading_data_text]]
  129. heading_html_name = self.get_tool_temp_storage(
  130. '<h' + heading_level_str + '>',
  131. '</h' + heading_level_str + '>'
  132. )
  133. heading_data_complete = '' + \
  134. '\n<front_br>' + \
  135. '<' + heading_html_name + '>' + \
  136. '<heading_stack>' + \
  137. heading_stack_str + \
  138. '</heading_stack>' + \
  139. ' ' + heading_data_text + \
  140. '</' + heading_html_name + '>' + \
  141. '<back_br>\n' + \
  142. ''
  143. self.render_data = re.sub(heading_regex, heading_data_complete, self.render_data, 1)
  144. heading_count_all -= 1
  145. # heading id adjust
  146. heading_end_count = len(re.findall(r'<heading_stack>', self.render_data))
  147. for for_a in reversed(range(0, 6)):
  148. heading_end_stack_regex = re.compile('<heading_stack>' + ('0\\.' * for_a))
  149. heading_end_match_count = len(re.findall(heading_end_stack_regex, self.render_data))
  150. if heading_end_match_count == heading_end_count:
  151. self.render_data = re.sub(heading_end_stack_regex, '<heading_stack>', self.render_data)
  152. break
  153. # heading id -> inline id
  154. heading_id_regex = r'<heading_stack>([^<>]+)<\/heading_stack>'
  155. heading_id_data = re.findall(heading_id_regex, self.render_data)
  156. for for_a in range(len(heading_id_data)):
  157. self.render_data = re.sub(heading_id_regex, '<a href="#toc" id="s-' + heading_id_data[for_a] + '">' + heading_id_data[for_a] + '.</a>', self.render_data, 1)
  158. toc_list[for_a][0] = heading_id_data[for_a]
  159. # not heading restore
  160. for for_a in range(1, 7):
  161. for_a_str = str(for_a)
  162. heading_restore_regex = re.compile('<heading_' + for_a_str + '>')
  163. self.render_data = re.sub(heading_restore_regex, ('=' * for_a), self.render_data)
  164. # make toc
  165. if len(toc_list) == 0:
  166. toc_data = ''
  167. else:
  168. toc_data = '' + \
  169. '<div class="opennamu_TOC" id="toc">' + \
  170. '<span class="opennamu_TOC_title">' + self.get_tool_lang('toc') + '</span>' + \
  171. '<br>' + \
  172. ''
  173. for for_a in toc_list:
  174. toc_data += '' + \
  175. '<br>' + \
  176. ('<span style="margin-left: 10px;">' * for_a[0].count('.')) + \
  177. '<span>' + \
  178. '<a href="#s-' + for_a[0] + '">' + \
  179. for_a[0] + '. ' + \
  180. '</a>' + \
  181. for_a[1] + \
  182. '</span>' + \
  183. ''
  184. if toc_data != '':
  185. toc_data += '</div>'
  186. # toc replace
  187. self.render_data = re.sub(r'\[(목차|toc|tableofcontents)\]', toc_data, self.render_data)
  188. def do_render_macro(self):
  189. # double macro function
  190. def do_render_macro_double(match):
  191. match = match.groups()
  192. name_data = match[0]
  193. macro_split_regex = r'(?:^|,) *([^,]+)'
  194. macro_split_sub_regex = r'(^[^=]+) *= *([^=]+)'
  195. if name_data in ('youtube', 'nicovideo', 'navertv', 'kakaotv', 'vimeo'):
  196. data = re.findall(macro_split_regex, match[1])
  197. # get option
  198. video_code = ''
  199. video_start = ''
  200. video_end = ''
  201. video_width = '640px'
  202. video_height = '360px'
  203. for for_a in data:
  204. data_sub = re.search(macro_split_sub_regex, for_a)
  205. if data_sub:
  206. data_sub = data_sub.groups()
  207. if data_sub[0] == 'width':
  208. if re.search(r'^[0-9]+$', data_sub[1]):
  209. video_width = data_sub[1] + 'px'
  210. else:
  211. video_width = data_sub[1]
  212. elif data_sub[0] == 'height':
  213. if re.search(r'^[0-9]+$', data_sub[1]):
  214. video_height = data_sub[1] + 'px'
  215. else:
  216. video_height = data_sub[1]
  217. elif data_sub[0] == 'start':
  218. video_start = data_sub[1]
  219. elif data_sub[0] == 'end':
  220. video_end = data_sub[1]
  221. elif data_sub[0] == 'https://www.youtube.com/watch?v' and name_data == 'youtube':
  222. video_code = data_sub[1]
  223. else:
  224. video_code = for_a
  225. # code to url
  226. if name_data == 'youtube':
  227. video_code = re.sub(r'^https:\/\/youtu\.be\/', '', video_code)
  228. video_code = 'https://www.youtube.com/embed/' + video_code
  229. if video_start != '':
  230. if video_end != '':
  231. video_code += '?start=' + video_start + '&end=' + video_end
  232. else:
  233. video_code += '?start=' + video_start
  234. else:
  235. if video_end != '':
  236. video_code += '?end=' + video_end
  237. elif name_data == 'kakaotv':
  238. video_code = re.sub(r'^https:\/\/tv\.kakao\.com\/v\/', '', video_code)
  239. video_code = 'https://tv.kakao.com/embed/player/cliplink/' + video_code +'?service=kakao_tv'
  240. elif name_data == 'navertv':
  241. video_code = re.sub(r'^https:\/\/tv\.naver\.com\/v\/', '', video_code)
  242. video_code = 'https://tv.naver.com/embed/' + video_code
  243. elif name_data == 'nicoviedo':
  244. video_code = 'https://embed.nicovideo.jp/watch/' + video_code
  245. else:
  246. video_code = 'https://player.vimeo.com/video/' + video_code
  247. return '<iframe style="width: ' + video_width + '; height: ' + video_height + ';" src="' + video_code + '" frameborder="0" allowfullscreen></iframe>'
  248. elif name_data == 'ruby':
  249. data = re.findall(macro_split_regex, match[1])
  250. # get option
  251. main_text = ''
  252. sub_text = ''
  253. color = ''
  254. for for_a in data:
  255. data_sub = re.search(macro_split_sub_regex, for_a)
  256. if data_sub:
  257. data_sub = data_sub.groups()
  258. if data_sub[0] == 'ruby':
  259. sub_text = data_sub[1]
  260. elif data_sub[0] == 'color':
  261. color = data_sub[1]
  262. else:
  263. main_text = for_a
  264. # add color
  265. if color != '':
  266. sub_text = '<span style="color:' + color + ';">' + sub_text + '</span>'
  267. return '' + \
  268. '<ruby>' + \
  269. main_text + \
  270. '<rp>(</rp>' + \
  271. '<rt>' + \
  272. sub_text + \
  273. '</rt>' + \
  274. '<rp>)</rp>' + \
  275. '</ruby>' + \
  276. ''
  277. elif name_data == 'age':
  278. if re.search(r'^[0-9]{4}-[0-9]{2}-[0-9]{2}$', match[1]):
  279. try:
  280. date = datetime.datetime.strptime(match[1], '%Y-%m-%d')
  281. except:
  282. return 'invalid date'
  283. date_now = datetime.datetime.today()
  284. if date > date_now:
  285. return 'invalid date'
  286. else:
  287. return str((date_now - date).days // 365)
  288. else:
  289. return 'invalid date'
  290. elif name_data == 'dday':
  291. if re.search(r'^[0-9]{4}-[0-9]{2}-[0-9]{2}$', match[1]):
  292. try:
  293. date = datetime.datetime.strptime(match[1], '%Y-%m-%d')
  294. except:
  295. return 'invalid date'
  296. date_now = datetime.datetime.today()
  297. date_end = (date_now - date).days
  298. if date_end > 0:
  299. return '+' + str(date_end)
  300. else:
  301. if date_end == 0:
  302. return '-' + str(date_end)
  303. else:
  304. return str(date_end)
  305. else:
  306. return 'invalid date'
  307. else:
  308. return '<macro>' + match[0] + '(' + match[1] + ')' + '</macro>'
  309. # double macro replace
  310. self.render_data = re.sub(r'\[([^[(]+)\(([^()]+)\)\]', do_render_macro_double, self.render_data)
  311. # single macro function
  312. def do_render_macro_single(match):
  313. match = match.group(1)
  314. if match in ('date', 'datetime'):
  315. return get_time()
  316. elif match == 'br':
  317. return '<br>'
  318. elif match == 'clearfix':
  319. return '<div style="clear: both;"></div>'
  320. else:
  321. return '<macro>' + match + '</macro>'
  322. # single macro replace
  323. self.render_data = re.sub(r'\[([^[\]]+)\]', do_render_macro_single, self.render_data)
  324. # macro safe restore
  325. self.render_data = re.sub(r'<macro>', '[', self.render_data)
  326. self.render_data = re.sub(r'<\/macro>', ']', self.render_data)
  327. def do_render_last(self):
  328. # remove front_br and back_br
  329. self.render_data = re.sub(r'\n?<front_br>', '', self.render_data)
  330. self.render_data = re.sub(r'<back_br>\n?', '', self.render_data)
  331. # \n to <br>
  332. self.render_data = re.sub(r'\n', '<br>', self.render_data)
  333. # <render_n> restore
  334. self.render_data = self.get_tool_data_restore(self.render_data)
  335. def __call__(self):
  336. self.do_render_text()
  337. self.do_render_macro()
  338. self.do_render_heading()
  339. self.do_render_last()
  340. # print(self.data_temp_storage)
  341. # print(self.render_data)
  342. return [
  343. self.render_data, # HTML
  344. self.render_data_js, # JS
  345. [] # Other
  346. ]