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