-
Notifications
You must be signed in to change notification settings - Fork 8
/
txtBloglib.py
421 lines (347 loc) · 13.1 KB
/
txtBloglib.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
import json,re,time,os
from flask import url_for
# version 0.0.7-8
# version 0.0.7-9 部分支持行内Math
import configparser
# read configure file
# v0.1 没有该值怎么办?
def getConf(section, item):
base_dir = str(os.path.dirname(__file__))
base_dir = base_dir.replace('\\', '/')
file_path = base_dir + "/data/_config/conf.ini"
#return base_dir;
#print("file_path=", file_path);
cf = configparser.ConfigParser() # configparser类来读取config文件
cf.read(file_path)
return cf.get(section, item);
# 在控制台打印彩色文字
import colorama
from colorama import Fore
from colorama import Style
colorama.init()
def print_yellow(str):
print(Fore.YELLOW + Style.BRIGHT + str + Style.RESET_ALL)
def print_red(str):
print(Fore.RED + Style.BRIGHT + str + Style.RESET_ALL)
#################
# mistune 版本号很关键
# 不过放弃适配 LaTex 公式就简单多了
#################
import mistune
version = mistune.__version__
version_1=int( re.split("\.", version)[0] ) #主版本号
isLaTexOn = getConf("function","LaTex")=="on" and (version_1 in [0, 3])
print("####################")
print("# Global settings")
print("# Markdown parser: mistune "+ version)
print( "# LaTex: ", isLaTexOn)
print("####################")
# mistune v0.8.4
if version_1 < 1:
from mistune import Renderer, InlineLexer
# todo 单引号括起来的还没有处理好? //------> todo
# define new sub class
#让mistune不后台处理$$和$$之间的LaTex代码,交给前台的js处理成数学公式
class LaTexRenderer(Renderer):
#def LaTex(self, alt, link):
def LaTex(self, text):
return '$$%s$$' % (text)
def LaTex_inline(self, text):
return '$%s$' % (text)
class LaTexInlineLexer(InlineLexer):
def enable_LaTex(self):
# add LaTex rules
self.rules.LaTex = re.compile(
r'\$$' # $$ 头
r'([\s\S]+?)' # *** 中间
r'\$$(?!\])' # $$ 尾
)
# Add LaTex parser to default rules
# you can insert it some place you like
# but place matters, maybe 3 is not good
self.default_rules.insert(3, 'LaTex')
#
self.rules.LaTex_inline = re.compile(
r'\$' # $$ 头
r'([\s\S]+?)' # *** 中间
r'\$(?!\])' # $$ 尾
)
self.default_rules.insert(0, 'LaTex_inline')
def output_LaTex(self, m):
text = m.group(1)
#alt, link = text.split('|')
# you can create an custom render
# you can also return the html if you like
#return self.renderer.LaTex(alt, link)
return self.renderer.LaTex(text)
def output_LaTex_inline(self, m):
text = m.group(1)
#alt, link = text.split('|')
# you can create an custom render
# you can also return the html if you like
#return self.renderer.LaTex(alt, link)
return self.renderer.LaTex_inline(text)
# the end of sub class
# 对 mistune 0.xx: 跳过LaTex片段的markdown to html parser mistune子类
# 对于 >= 1.xx 的,只能是普通渲染
def md2html(md):
if version_1 < 1:
renderer = LaTexRenderer()
inline = LaTexInlineLexer(renderer)
# enable the feature
inline.enable_LaTex()
markdown = mistune.Markdown(renderer, inline=inline)
return markdown(md)
elif version_1==3:
from mistune.plugins.math import math
renderer = mistune.HTMLRenderer()
markdown = mistune.Markdown(renderer, plugins=[math])
return markdown(md)
else: # version_1==2
return mistune.html(md);
#
#文本文件阅读器,input filepath, return string from the file.
#v0.3 <h4>下添加换行,防止遮挡;
#v0.4 对尖括号转码
#v0.5 添加纸质背景
#v0.6 分离txt.css,支持在config/conf.ini配置文件中切换皮肤
#v0.7 fix left corner
def txtReader(fpath,txtStyle="ubuntu1"):
fr=open(fpath, 'r', encoding="utf8")
tmp=''
for lineR in fr.readlines():
#line=lineR.strip("\n")#去除两端的换行
line= re.sub(r'\n$',"", lineR) #只去除末尾的换行
#if line.match("")
line=re.sub("<","<",line);
line=re.sub(">",">",line);
#add text
if re.match("\={40,}",line):
tmp+="<hr class=top><h4>\n"
elif re.match("\-{40,}",line):
tmp+="</h4><hr class=under>\n"
else:
tmp+=line+"\n";
#关闭文件
fr.close()
css='<link rel="stylesheet" type="text/css" href="/static/css/txt.css" media="all">\n'
js='<script type="text/javascript" src="/static/js/txt.js"></script>\n\n'
#获取配置风格
txtStyle=getConf('style','txt');
# left bottom corner contents
cornerContents="""
<div id="common_box">
<div id="cli_title" class=title> Contents <b id="cli_on">+</b></div>
<div id="f_content" class=container>
<div class=content></div>
<div class="title">==This is the bottom==</div>
</div>
</div>
<script type="text/javascript" src="/static/js/startMove.js"></script>\n
"""
return css+"<div class='content'><pre class="+txtStyle+">" + tmp + "</pre></div>"+cornerContents+js+"\n";
#html读取器
#v0.1
def htmlReader(fpath):
fr=open(fpath, 'r', encoding="utf8")
tmp=fr.read();
fr.close();
# LaTex
# js3='<script src="/static/js/mathjax-2.7.6/MathJax.js"></script>\n';
#js3='<script src="/static/js/mathjax-2.7.6/MathJax.js?config=TeX-MML-AM_CHTML"></script>\n';
js3='<script src="/static/js/mathjax-2.7.6/MathJax.js?config=TeX-MML-AM_CHTML"></script>\n';
#js3='<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"></script>';
#js3+='<script src="/static/js/showLaTex.js"></script>\n\n';
#if getConf("function","LaTex")=="on":
if isLaTexOn:
tmp=tmp+js3;
return tmp;
#
#markdown读取器
#v0.1
#v0.2 增加top目录
#v0.3 代码高亮
#v0.4 左下角添加目录
#v0.5 增加LaTex支持,依赖MathJax.js,不好用。因为mistune解析markdown时转义_为<i>,导致带有_的公式转换失败
#v0.6 LaTex根据配置文件,决定是否加载
#v0.7 恢复使用 online 版的 MathJax.js
def markdownReader(fpath):
# read markdown
fr=open(fpath, 'r', encoding="utf8")
text=fr.read()
fr.close()
#遇到 MathJax 和markdown 冲突怎么办?https://www.v2ex.com/t/240363
# mathjax中的'_'(下划线字符 下标)与markdown中的斜体冲突
# markdown to html
#tmp=mistune.markdown(text, escape=False, hard_wrap=True) #'I am using **mistune markdown parser**'
tmp=md2html(text) #'I am using **mistune markdown parser**' , escape=False, hard_wrap=True
tmp="<div class=markdown>\n"+tmp+"</div>\n"
#tmp="<div class=content>\n"+tmp+"</div>\n"
# left bottom corner contents
cornerContents="""
<div id="common_box">
<div id="cli_title" class=title> Contents <b id="cli_on">+</b></div>
<div id="f_content" class=container>
<div class=content></div>
<div class="title">==This is the bottom==</div>
</div>
</div>
<script type="text/javascript" src="/static/js/startMove.js"></script>\n
"""
tmp+=cornerContents;#这个框架的内容由js在markdown.js中填充
# add markdown style sheet and top contents js, left bottom corner contents.
mdStyle=getConf("style","markdown") #get markdown style file name from config file.
css='<link rel="stylesheet" type="text/css" href="/static/css/'+mdStyle+'.css" media="all">\n'
js='<script type="text/javascript" src="/static/js/markdown.js"></script>\n\n'
tmp=css+js+tmp;
codeNumberJS='''
addEvent(window, 'load', function(){
//1. get pre code
var aPre=document.getElementsByTagName('pre');
var aCode=[]
for(var i=0;i<aPre.length;i++){
var oPre=aPre[i]
var aCode1=oPre.getElementsByTagName('code');
if(1== aCode1.length){
var oCode=aCode1[0]
aCode.push(oCode)
//2. get text inside
var lines=oCode.innerHTML.split("\\n")
var n=lines.length;
//console.log('i=',i, lines, '; n=',n)
//3.make a dom of numbering
var oUl=document.createElement('ul');
oUl.setAttribute('class', 'pre-numbering');
for(var j=0;j<n-1;j++){
var oLi=document.createElement('li');
oLi.innerHTML=j+1;
oUl.append(oLi)
}
//4. add to code
oPre.append(oUl)
oCode.setAttribute('class', oCode.getAttribute('class')+ ' has-numbering')
oPre.setAttribute('class', 'prettyprint')
}
}
})
'''
# high light code
css2='<link rel="stylesheet" href="/static/css/highlight-routeros.css">\n'
js2='<script src="/static/js/highlight.pack.js"></script>\n\n'
tmp=tmp + css2+js2 + '<script>hljs.initHighlightingOnLoad();'+codeNumberJS+'</script>';
# LaTex
#js3='<script type="text/javascript" async src="/static/js/MathJax-2.7.5.js?config=TeX-MML-AM_CHTML"></script>\n';
#js3='<script type="text/javascript" async src="/static/js/MathJax-tex-mml-chtml-3-es5.js"></script>\n';
js3='<script src="/static/js/mathjax-2.7.6/MathJax.js?config=TeX-MML-AM_CHTML"></script>\n';
#js3='<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"></script>';
js3+='<script src="/static/js/showLaTex.js"></script>\n\n';
#print_red(js3);
#if getConf("function","LaTex")=="on":
if isLaTexOn:
tmp=tmp+js3;
return tmp;
#input k and id, return url_left and content, filepath
#v0.3
def getData(k,id):
#1.解析id为2个数字
arr=re.split("_", id)
n0=int(arr[0])
n1=int(arr[1])
#2.解析json文件获取左侧目录,和文件名字
#读取json
fname="data/"+k+".json";
if not os.path.isfile(fname):
return (0, fname + " not found!"); # 响应找不到目录.json错误
#
load_f=open(fname,'r',encoding="utf8")
menus = json.load(load_f);
#关闭文件
load_f.close();
#凑出来文件路径,如果找不到则定位到错误页面
print_red("====> menu: "+k+ "/ " + str(len(menus) ) + " section(s), port: " + getConf("system", "port") );
#print(menus); #顶部菜单数据
if len( menus )<=n0: #如果 R/ 下分块下标不含url的请求,则报错
return (0, "Error: Index out of bounds! Top menu length: "+ str(len(menus)) + ", doesn't have "+str(n0)+"th element(0-based index)" );
if len( menus[n0]["data"] )<=n1: #
return (0, "Error: Index out of bounds! "+k+"/ left section "+ str(n0) +" only have "+ str(len(menus[n0]["data"])) +" files, doesn't have index "+ str(n1) +"(0-based)" );
menuCur = menus[n0]["data"][n1]
filepath="data/"+k+"/"+menuCur[1]+"."+menuCur[2] #路径
suffix=menuCur[2].lower() #后缀
#拼凑出超链接
url_left=""
for i in range(len(menus)):
#print("="*10,menus[i]["title"]);
url_left+="<li><h5 class=title>"+str(i)+" "+menus[i]["title"]+"</h5>\n<ul class=submenu>\n";
arr2=menus[i]["data"];
for j in range(len(arr2)):
#print("title=",arr2[j][0], str(i)+"_"+str(j) )
cur=""
if i==n0 and j==n1:
cur=" class=cur"
#
id=str(i)+"_"+str(j)
item_url=url_for('hello', k=k, id=id) #第一个参数是函数名,不是路由
url_left+="<li"+cur+"><a href=" + item_url +">"+id+" "+arr2[j][0]+"</a></li>\n"
url_left+="</ul>\n</li>\n"
#上次修改时间
lastModified = "2017-10-19 7:0:0"
#根据文件类型,读取文件
content='<div class="alert">该文章暂时未公开,请稍后再来...</div>';
if os.path.exists(filepath):
# modified date and time;
#modified=time.localtime(os.path.getctime(filepath))
modified = os.path.getmtime(filepath)
year,month,day,hour,minute,second=time.localtime(modified)[:-3]
lastModified=str(year)+"-"+str(month)+"-"+str(day) +" "+str(hour)+":"+str(minute)+":"+str(second)
# content
if suffix=="html":
content=htmlReader(filepath)
elif suffix=="markdown" or suffix=='md':
content=markdownReader(filepath)
else: #txt
content=txtReader(filepath)
#如果是英语频道,则新增底部英语随机句子。
if k=="English" or getConf('function','motto')=="on":
content+='\n<script src="/static/js/startMove_OOP.js"></script>\n<script src="/static/js/motto.js"></script>\n';
return (url_left, content,filepath.replace("data/",""), lastModified,suffix)
# 0 1 2 3 4
#顶部菜单生成
#v0.2
def getTopMenu(k):
#读取json
load_f=open("data/topMenu.json",'r',encoding="utf8")
menus = json.load(load_f);
load_f.close();
tmp=""
for i in range(len(menus)):
item_url=url_for('hello', k=menus[i][0], id="0_0")
cur=""
if menus[i][0]==k:
cur=" current"
tmp+=" <a class='topmenu"+cur+"' href=" + item_url +" title="+menus[i][1]+">"+menus[i][0]+"</a> "
return tmp;
#
#底部菜单生成
#v0.1
# 根据友情链接数组,输出拼接好的字符串。【对外】
# 1.输入一级数组: ['http://jsbin.com/','jsbin','练习前端的好工具!']
# 2.或二级数组:
# [
# ['http://jsbin.com/','jsbin','练习前端的好工具!'],
# ['http://jquery.cuishifeng.cn/','jQuery手册']
# ];
# 3.返回链接字符串。
def get_links(arr):
def get_link(ar):
title=""
if len(ar)>2:
title="title="+ar[2]
return "<a target=_blank href="+ar[0]+" "+title+">"+ar[1]+"</a> | \n"
#
if isinstance(arr[0],str):
return get_link(arr);
html=""
for i in range(len(arr)):
html+=get_link(arr[i])
return html;
#