diff --git a/application/lib/calibre/ebooks/conversion/plugins/recipe_input.py b/application/lib/calibre/ebooks/conversion/plugins/recipe_input.py
index 42925372..19159a82 100644
--- a/application/lib/calibre/ebooks/conversion/plugins/recipe_input.py
+++ b/application/lib/calibre/ebooks/conversion/plugins/recipe_input.py
@@ -91,12 +91,13 @@ def convert(self, recipes, opts, file_ext, log, output_dir, fs):
log.warning(msg)
continue
- feed_index_start += len(ro.feed_objects)
- self.feeds.extend(ro.feed_objects)
- self.aborted_articles.extend(ro.aborted_articles)
- self.failed_downloads.extend(ro.failed_downloads)
- self.index_htmls.append((ro.title, ro.get_root_index_html_name()))
- self.recipe_objects.append(ro)
+ if ro.feed_objects:
+ feed_index_start += len(ro.feed_objects)
+ self.feeds.extend(ro.feed_objects)
+ self.aborted_articles.extend(ro.aborted_articles)
+ self.failed_downloads.extend(ro.failed_downloads)
+ self.index_htmls.append((ro.title, ro.get_root_index_html_name()))
+ self.recipe_objects.append(ro)
#可能会有些副作用,前面的conversion_options会影响后面的recipe
for key, val in ro.conversion_options.items():
diff --git a/application/routes.py b/application/routes.py
index c7d638c3..0987880b 100644
--- a/application/routes.py
+++ b/application/routes.py
@@ -13,13 +13,6 @@
def Home():
return render_template('home.html')
-@bpHome.route('/env')
-def Test():
- strEnv = []
- for d in os.environ:
- strEnv.append("
" + str(d).rjust(28) + " | " + str(os.environ[d]) + "
")
- return ''.join(strEnv)
-
@bpHome.route('/images/')
def ImageFileRoute(image_file):
imgDir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'images'))
diff --git a/application/static/base.js b/application/static/base.js
index 877deeb2..a4d43229 100644
--- a/application/static/base.js
+++ b/application/static/base.js
@@ -23,7 +23,7 @@ function BrowserLanguage() {
if (lang.indexOf('-') != -1) {
return lang.substring(0, lang.indexOf('-'));
} else {
- return lang.substring(0, 2);
+ return lang; //.substring(0, 2);
}
}
@@ -592,8 +592,17 @@ function ShowSimpleModalDialog(content) {
//显示一个分享自定义RSS的对话框
function ShowShareDialog(id, title){
- var all_languages = ['aa','ab','af','ak','sq','am','ar','an','hy','as','av','ae','ay','az','ba','bm','eu','be','bn','bh','bi','bo','bs','br','bg','my','ca','cs','ch','ce','zh','cu','cv','kw','co','cr','cy','cs','da','de','dv','nl','dz','el','en','eo','et','eu','ee','fo','fa','fj','fi','fr','fy','ff','ga','de','gd','ga','gl','gv','el','gn','gu','ht','ha','he','hz','hi','ho','hr','hu','hy','ig','is','io','ii','iu','ie','ia','id','ik','is','it','jv','ja','kl','kn','ks','ka','kr','kk','km','ki','rw','ky','kv','kg','ko','kj','ku','lo','la','lv','li','ln','lt','lb','lu','lg','mk','mh','ml','mi','mr','ms','mi','mk','mg','mt','mn','mi','ms','my','na','nv','nr','nd','ng','ne','nl','nn','nb','no','oc','oj','or','om','os','pa','fa','pi','pl','pt','ps','qu','rm','ro','ro','rn','ru','sg','sa','si','sk','sk','sl','se','sm','sn','sd','so','st','es','sq','sc','sr','ss','su','sw','sv','ty','ta','tt','te','tg','tl','th','bo','ti','to','tn','ts','tk','tr','tw','ug','uk','ur','uz','ve','vi','vo','cy','wa','wo','xh','yi','yo','za','zh','zu'];
- var languages = ['en','fr','zh','es','pt','de','it','ja','ru','tr','ko','ar','cs','nl','el','hi','ms','bn','fa','ur','sw','vi','pa','jv','tl','ha'];
+ var all_languages = ['aa','ab','af','ak','sq','am','ar','an','hy','as','av','ae','ay','az','ba','bm','eu','be','bn',
+ 'bh','bi','bo','bs','br','bg','my','ca','cs','ch','ce','zh','cu','cv','kw','co','cr','cy','cs','da','de','dv','nl',
+ 'dz','el','en','eo','et','eu','ee','fo','fa','fj','fi','fr','fy','ff','ga','de','gd','ga','gl','gv','el','gn','gu',
+ 'ht','ha','he','hz','hi','ho','hr','hu','hy','ig','is','io','ii','iu','ie','ia','id','ik','is','it','jv','ja','kl',
+ 'kn','ks','ka','kr','kk','km','ki','rw','ky','kv','kg','ko','kj','ku','lo','la','lv','li','ln','lt','lb','lu','lg',
+ 'mk','mh','ml','mi','mr','ms','mi','mk','mg','mt','mn','mi','ms','my','na','nv','nr','nd','ng','ne','nl','nn','nb',
+ 'no','oc','oj','or','om','os','pa','fa','pi','pl','pt','ps','qu','rm','ro','ro','rn','ru','sg','sa','si','sk','sk',
+ 'sl','se','sm','sn','sd','so','st','es','sq','sc','sr','ss','su','sw','sv','ty','ta','tt','te','tg','tl','th','bo',
+ 'ti','to','tn','ts','tk','tr','tw','ug','uk','ur','uz','ve','vi','vo','cy','wa','wo','xh','yi','yo','za','zh','zu'];
+ var languages = ['en','fr','zh','es','pt','de','it','ja','ru','tr','ko','ar','cs','nl','el','hi','ms','bn','fa','ur',
+ 'sw','vi','pa','jv','tl','ha','da','in','no','pl','ro','sv','th'];
var userLang = BrowserLanguage();
var modal = new tingle.modal({footer: true});
var ostr = ['' + i18n.shareLinksHappiness + '
'];
diff --git a/application/templates/setting.html b/application/templates/setting.html
index 09a72c6f..a8add5e0 100644
--- a/application/templates/setting.html
+++ b/application/templates/setting.html
@@ -195,7 +195,9 @@
{% if 'smtp' in sm_services -%}
{% endif -%}
+ {% if 'local' in sm_services -%}
+ {% endif -%}
diff --git a/application/view/setting.py b/application/view/setting.py
index 05ab623c..5bba7e6b 100644
--- a/application/view/setting.py
+++ b/application/view/setting.py
@@ -135,6 +135,15 @@ def SendTestEmailPost():
return {'status': status, 'emails': emails}
+#显示环境变量的值
+@bpSetting.route('/env')
+@login_required()
+def DisplayEnv():
+ strEnv = []
+ for d in os.environ:
+ strEnv.append("
" + str(d).rjust(28) + " | " + str(os.environ[d]) + "
")
+ return ''.join(strEnv)
+
#设置国际化语种
@bpSetting.route("/setlocale/
")
def SetLang(langCode):
diff --git a/application/work/worker.py b/application/work/worker.py
index c7e7afa1..d1738086 100644
--- a/application/work/worker.py
+++ b/application/work/worker.py
@@ -108,10 +108,13 @@ def WorkerImpl(userName: str, recipeId: list=None, log=None):
else:
save_delivery_log(user, title, 0, status='nonews')
- elaspTime = time.time() - startTime
+ elaspTime = (time.time() - startTime) / 60.0
if ret:
ret = '\n'.join(ret)
- ret += f'\nTime: {elaspTime} seconds.'
+ if '\n' in ret:
+ ret += f'\nConsumed time: {elaspTime:.1f} minutes.'
+ else:
+ ret += f' [Consumed time: {elaspTime:.1f} minutes].'
else:
ret = "There are no new feeds available."
log.warning(ret)
diff --git a/docs/Chinese/deployment.md b/docs/Chinese/deployment.md
index 1c97d1e0..6f79ce3f 100644
--- a/docs/Chinese/deployment.md
+++ b/docs/Chinese/deployment.md
@@ -53,12 +53,10 @@ gcloud beta app deploy --version=1 app.yaml
### 其他说明
1. 初始账号和密码为 admin/admin。
2. 部署时出现下面的几个提示时记得按 y,因为光标自动下移到了下一行,往往会忘记按 y,否则会一直卡在这里。
-
```
Updating config [cron]...API [cloudscheduler.googleapis.com] not enabled on project [xxx]. Would you like to enable and retry (this will take a few minutes)
Updating config [queue]...API [cloudtasks.googleapis.com] not enabled on project [xxx]. Would you like to enable and retry (this will take a few minutes)
-```
-
+```
3. 如果出现部署失败并且多次尝试后仍然无法解决,比如"Timed out fetching pod."之类的错误,可以关停此id,然后重建一个,部署时选择其他区域。
diff --git a/tests/readme.developer.md b/tests/readme.developer.md
index d4f69ce0..7c3efcc5 100644
--- a/tests/readme.developer.md
+++ b/tests/readme.developer.md
@@ -31,6 +31,7 @@
gcloud app deploy cron.yaml
gcloud app deploy queue.yaml
+gcloud services list | grep datastore.googleapis.com
# Windows 安装celery
* 安装并启动redis服务,(Windows只能安装redis3 )
@@ -60,9 +61,17 @@ gcloud app deploy queue.yaml
# KindleEar额外自带的Python库,这些库不用pip安装,不在requirements.txt里面
* readability-lxml: 修改了其htmls.py|shorten_title()
-# 关于翻译的注意事项
+# 关于i18n翻译
* javascript的翻译没有采用其他复杂或引入其他依赖的方案,而是简单粗暴的在base.html里面将要翻译的字段预先翻译,
然后保存到一个全局字典
+* 文本字符串有修改后,逐个执行三个脚本。
+第一个脚本提取文本到messages.pot,第二个将文本更新到messages.po,翻译后使用第三个脚本编译为messages.mo
+```bat
+tools\pybabel_extract.bat
+tools\pybabel_update.bat
+tools\pybabel_compile.bat
+```
+* 在po后查找fuzzy,更新翻译后,将fuzzy标识行删除
# Docker
@@ -72,6 +81,7 @@ cp ./docker/Dockerfile .
sudo docker build -t kindleear/kindleear .
#or
sudo docker build --no-cache -t kindleear/kindleear .
+sudo docker tag id kindleear/kindleear:version
```
## 常用Docker命令
@@ -84,9 +94,17 @@ sudo docker ps -a
sudo docker compose up -d
sudo docker run -d
sudo docker run -it id /bin/bash
-
+sudo docker login
+sudo docker push kindleear/kindleear:tag
+sudo docker push kindleear/kindleear
```
+
+# 申请Let’s Encrypt ssl证书
+* sudo apt update && sudo apt install certbot
+* sudo certbot certonly --manual --preferred-challenges=dns --email xx@xx.com -d www.yourdomain.com
+* 添加txt记录
+
# Python托管平台的一些了解
* [appengine](https://cloud.google.com):必须绑定信用卡,但有免费额度,有收发邮件服务,任务队列,后台进程
* [Heroku](https://www.heroku.com): 没有免费额度,入门套餐也需要付费
diff --git a/tools/run_flask.bat b/tools/run_flask.bat
index 236e19db..edcf8b97 100644
--- a/tools/run_flask.bat
+++ b/tools/run_flask.bat
@@ -7,5 +7,6 @@ set TASK_QUEUE_SERVICE=apscheduler
set TASK_QUEUE_BROKER_URL=redis://127.0.0.1:6379/
set KE_TEMP_DIR=d:/temp
set LOG_LEVEL=debug
+set HIDE_MAIL_TO_LOCAL=no
python -m flask run --host=0.0.0.0 --debug
pause