From 6821384f4bf4a20c4ac9bad92bba6a5289fb46ed Mon Sep 17 00:00:00 2001 From: John Xina Date: Mon, 24 Jul 2023 14:45:05 +0800 Subject: [PATCH] Add terminal web browser support from Hatsuharu --- app.py | 55 +++++++++++++++++++++++++++++++------- templates/bar.html.text | 54 +++++++++++++++++++++++++++++++++++++ templates/error.html.text | 41 ++++++++++++++++++++++++++++ templates/index.html.text | 49 +++++++++++++++++++++++++++++++++ templates/thread.html.text | 49 +++++++++++++++++++++++++++++++++ templates/user.html.text | 37 +++++++++++++++++++++++++ 6 files changed, 275 insertions(+), 10 deletions(-) create mode 100644 templates/bar.html.text create mode 100644 templates/error.html.text create mode 100644 templates/index.html.text create mode 100644 templates/thread.html.text create mode 100644 templates/user.html.text diff --git a/app.py b/app.py index 840cfc4..7e8f32b 100644 --- a/app.py +++ b/app.py @@ -2,6 +2,9 @@ import asyncio import aiotieba import uvicorn +import re +import textwrap + from aioflask import render_template, request, escape from urllib.parse import quote_plus from datetime import datetime @@ -33,6 +36,25 @@ async def cache_name_from_id(c, i): def normalize_utf8(s): return s.encode('unicode_escape').decode('ascii').replace('\\', '') +# Render the template with compatibility detection. +def render_template_c(tmpl, **kwargs): + text_browsers = ['w3m', 'Lynx', 'ELinks', 'Links', 'URL/Emacs', 'Emacs'] + ua = request.headers.get('User-Agent') + + for text_ua in text_browsers: + if ua.startswith(text_ua): + return render_template(f'{tmpl}.text', **kwargs) + return render_template(tmpl, **kwargs) + +# Wrap the text to the given width. +def wrap_text(i, width=70, join='\n', rws=False): + i = str(i) + def add_whitespace_to_chinese(match): + return '\uFFFD' + match.group(0) + pattern = r'[\u4e00-\u9fff\uFF00-\uFFEF]' + aft = re.sub(pattern, add_whitespace_to_chinese, i) + return join.join(textwrap.wrap(aft, width=width, replace_whitespace=rws)).replace('\uFFFD', '') + ###################################################################### # Convert a timestamp to its simpliest readable date format. @@ -63,6 +85,15 @@ def _jinja2_filter_intsep(i): def _jinja2_filter_trim(text): return text[:78] + '……' if len(text) > 78 else text +# Format comments to its equiviant text HTML. +@app.template_filter('tcomments') +async def _jinja2_filter_tcomments(coms): + buf = ' | ' + for com in coms: + buf += wrap_text(f'{ com.user.show_name }:{ com.text }', width=60, join="\n | ") + buf += '\n \---\n | ' + return buf[:-4] + # Format fragments to its equiviant HTML. @app.template_filter('translate') async def _jinja2_filter_translate(frags, reply_id=0): @@ -105,6 +136,10 @@ async def _jinja2_filter_translate(frags, reply_id=0): return htmlfmt +@app.template_filter('twrap') +async def _jinja2_filter_translate(text, width=70, join='\n', rws=False): + return wrap_text(text, width, join, rws) + ###################################################################### @app.route('/p/') @@ -134,7 +169,7 @@ async def thread_view(tid): await asyncio.gather(*(cache_name_from_id(tieba, i) for i in all_users)) - return await render_template('thread.html', info=thread_info, ao=ao) + return await render_template_c('thread.html', info=thread_info, ao=ao) @app.route('/f') async def forum_view(): @@ -156,10 +191,10 @@ async def forum_view(): 'member': forum_info.member_num, 'desc': '贴吧描述暂不可用', 'name': forum_info.fname } if threads.page.current_page > threads.page.total_page or pn < 1: - return await render_template('error.html', msg = \ + return await render_template_c('error.html', msg = \ f'请求越界,本贴吧共有 { threads.page.total_page } 页' f'而您查询了第 { threads.page.current_page} 页') - return await render_template('bar.html', info=forum_info, threads=threads, sort=sort, + return await render_template_c('bar.html', info=forum_info, threads=threads, sort=sort, tp = ((115 if threads.page.total_page > 115 else threads.page.total_page) if sort == 0 else threads.page.total_page)) @app.route('/home/main') @@ -175,28 +210,28 @@ async def user_view(): try: hp = await tieba.get_homepage(i, pn) except ValueError: - return await render_template('error.html', msg='您已超过最后页') + return await render_template_c('error.html', msg='您已超过最后页') if len(hp[1]) == 0 and pn > 1: - return await render_template('error.html', msg='您已超过最后页') + return await render_template_c('error.html', msg='您已超过最后页') - return await render_template('user.html', hp=hp, pn=pn) + return await render_template_c('user.html', hp=hp, pn=pn) @app.route('/') async def main_view(): - return await render_template('index.html') + return await render_template_c('index.html') ###################################################################### @app.errorhandler(RuntimeError) async def runtime_error_view(e): if hasattr(e, 'msg'): - return await render_template('error.html', msg=e.msg) - return await render_template('error.html', msg='错误信息不可用') + return await render_template_c('error.html', msg=e.msg) + return await render_template_c('error.html', msg='错误信息不可用') @app.errorhandler(Exception) async def general_error_view(e): - return await render_template('error.html', msg=e) + return await render_template_c('error.html', msg=e) ###################################################################### diff --git a/templates/bar.html.text b/templates/bar.html.text new file mode 100644 index 0000000..960b1ee --- /dev/null +++ b/templates/bar.html.text @@ -0,0 +1,54 @@ + + + + + + + {{ info['name'] }}吧 - RAT + + +
+------------------------------------------------------------------------
+    欢迎来到{{info['name']}}吧! {{info['desc']}}
+        关注 {{ info['member']|intsep }} 主题 {{ info['topic']|intsep }} 帖子 {{ info['thread']|intsep }}
+------------------------------------------------------------------------
+
+         [时下热门]         [最新回复]         [最新发布]
+ {% for t in threads %} +
----- {{ '%4s'|format(t.reply_num) }} {{ '/置顶/ ' if t.is_top or t.is_livepost else '' }}{{ '/精/ ' if t.is_good else '' }}
++ 发帖人:{{ t.user.show_name }}
++ 最近回复时间: {{ t.last_time|date }}
+
+{{ t.title if t.title else t.text|twrap }}
+{% if t.title %}
+{{ t.text[(t.title|length)+1:]|twrap(rws=True) }}{% endif %}
+ {% endfor %} +
+------------------------------------------------------------------------
+	
+ 首页 | + + {% for i in range(5) %} + {% set np = threads.page.current_page - 5 + i %} + {% if np > 0 %} + {{ np }} | + {% endif %} + {% endfor %} + + {{ threads.page.current_page }} | + + {% for i in range(5) %} + {% set np = threads.page.current_page + 1 + i %} + {% if np <= tp %} + {{ np }} | + {% endif %} + {% endfor %} + + 尾页 +
+------------------------------------------------------------------------
+      RAT Ain't Tieba       自豪地以 AGPLv3 释出       源代码
+------------------------------------------------------------------------
+	
+ + diff --git a/templates/error.html.text b/templates/error.html.text new file mode 100644 index 0000000..db04d3c --- /dev/null +++ b/templates/error.html.text @@ -0,0 +1,41 @@ + + + + + + + 错误 - RAT + + +
+------------------------------------------------------------------------
+      Guru Meditation                 c'est la vie
+------------------------------------------------------------------------
+
+   ██░▀██████████████▀░██
+  █▌▒▒░████████████░▒▒▐█
+  █░▒▒▒░██████████░▒▒▒░█
+  ▌░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░▐
+  ░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░
+  ███▀▀▀██▄▒▒▒▒▒▒▒▄██▀▀▀██
+  ██░░░▐█░▀█▒▒▒▒▒█▀░█▌░░░█
+  ▐▌░░░▐▄▌░▐▌▒▒▒▐▌░▐▄▌░░▐▌
+  █░░░▐█▌░░▌▒▒▒▐░░▐█▌░░█
+  ▒▀▄▄▄█▄▄▄▌░▄░▐▄▄▄█▄▄▀▒
+  ░░░░░░░░░░└┴┘░░░░░░░░░
+  ██▄▄░░░░░░░░░░░░░░▄▄██
+  ████████▒▒▒▒▒▒████████
+  █▀░░███▒▒░░▒░░▒▀██████
+  █▒░███▒▒╖░░╥░░╓▒▐█████
+  █▒░▀▀▀░░║░░║░░║░░█████
+  ██▄▄▄▄▀▀┴┴╚╧╧╝╧╧╝┴┴███
+  ██████████████████████`
+
+Cat says, * {{ msg|twrap }} *.
+
+------------------------------------------------------------------------
+      RAT Ain't Tieba       自豪地以 AGPLv3 释出       源代码
+------------------------------------------------------------------------
+	
+ + diff --git a/templates/index.html.text b/templates/index.html.text new file mode 100644 index 0000000..6f07234 --- /dev/null +++ b/templates/index.html.text @@ -0,0 +1,49 @@ + + + + + + + 首页 - RAT + + +
+------------------------------------------------------------------------
+      欢迎来到 RAT! RAT Ain't Tieba 是一款自由的百度贴吧前端。
+------------------------------------------------------------------------
+
+______  ___ _____    ___  _       _ _     _____ _      _           
+| ___ \/ _ |_   _|  / _ \(_)     ( | |   |_   _(_)    | |          
+| |_/ / /_\ \| |   / /_\ \_ _ __ |/| |_    | |  _  ___| |__   __ _ 
+|    /|  _  || |   |  _  | | '_ \  | __|   | | | |/ _ | '_ \ / _` |
+| |\ \| | | || |   | | | | | | | | | |_    | | | |  __| |_) | (_| |
+\_| \_\_| |_/\_/   \_| |_|_|_| |_|  \__|   \_/ |_|\___|_.__/ \__,_|
+                                                                   
+
+您正在查看的是为终端浏览器优化过的前端页面。如果您认为您的浏览器不应该
+使用此页面,请于下方报告缺陷。如果您的终端浏览器不能很好地处理页面,您
+也可以报告缺陷。此前端页面由 *初春トワ* 打造,祝您有个愉快网上冲浪体验。
+
+RAT Ain't Tieba 是以 AGPLv3 分发的自由软件,它尊重您的自由。更多关于
+自由软件运动的内容,请见 writefreesoftwareGNU。
+
+  源代码  :0xacab(对文本浏览器不友好)
+源代码仓库:https://0xacab.org/johnxina/rat.git
+缺陷追踪器:0xacab(对文本浏览器不友好)
+
+当然,您也可以使用电子邮件报告缺陷:bingchilling@riseup.net。
+	
+ +
+ + +
+ +
+
+------------------------------------------------------------------------
+      RAT Ain't Tieba       自豪地以 AGPLv3 释出       源代码
+------------------------------------------------------------------------
+	
+ + diff --git a/templates/thread.html.text b/templates/thread.html.text new file mode 100644 index 0000000..5a78c4c --- /dev/null +++ b/templates/thread.html.text @@ -0,0 +1,49 @@ + + + + + + + {{ info.thread.title }} - {{ info.thread.fname }}吧 - RAT + + +
+------------------------------------------------------------------------
+[{{ info.forum.fname }}吧] {{ info.thread.title|twrap(width=60) }}
+------------------------------------------------------------------------
+
+               [全部回复]         [仅看楼主]
+ {% for p in info %} +
+#{{ p.floor }} | {{ p.user.show_name }}:
+
+{{ p.text|twrap(rws=True) }}
+{% if p.comments %}{{ '\n' + p.comments|tcomments }}{% endif %}
+ {% endfor %} +
------------------------------------------------------------------------
+ 首页 | + + {% for i in range(5) %} + {% set np = info.page.current_page - 5 + i %} + {% if np > 0 %} + {{ np }} | + {% endif %} + {% endfor %} + + {{ info.page.current_page }} | + + {% for i in range(5) %} + {% set np = info.page.current_page + 1 + i %} + {% if np <= info.page.total_page %} + {{ np }} | + {% endif %} + {% endfor %} + + 尾页 +
+------------------------------------------------------------------------
+      RAT Ain't Tieba       自豪地以 AGPLv3 释出       源代码
+------------------------------------------------------------------------
+	
+ + diff --git a/templates/user.html.text b/templates/user.html.text new file mode 100644 index 0000000..8548a01 --- /dev/null +++ b/templates/user.html.text @@ -0,0 +1,37 @@ + + + + + + + {{ hp[0].show_name }}的个人资料 - RAT + + +
+------------------------------------------------------------------------
+    {{ hp[0].show_name }} ({{ hp[0].user_name }})
+        关注 {{ hp[0].follow_num|intsep}} 粉丝 {{ hp[0].fan_num|intsep }} 发帖 {{ hp[0].post_num|intsep }} 关注贴吧 {{ hp[0].forum_num|intsep }}
+------------------------------------------------------------------------
+ {% for t in hp[1] %} +
{{ t.text|twrap(rws=True) }}
+ {% endfor %} +
------------------------------------------------------------------------
+ 首页 | + + {% for i in range(5) %} + {% set np = pn - 5 + i %} + {% if np > 0 %} + {{ np }} | + {% endif %} + {% endfor %} + + {{ pn }} | + + 下一页 +
+------------------------------------------------------------------------
+      RAT Ain't Tieba       自豪地以 AGPLv3 释出       源代码
+------------------------------------------------------------------------
+	
+ +