diff --git a/application/static/library.js b/application/static/library.js
index 3c6cefe5..45e4dc2d 100644
--- a/application/static/library.js
+++ b/application/static/library.js
@@ -334,9 +334,11 @@ function SelectCategory(obj, category) {
function DoSearchInShared() {
var input = $('#search_text');
var txt = input.val();
- if (txt == "#download") { //下载所有的共享RSS
- DownAllRssToFile();
+ if ((txt == "#download") || (txt == "#downxml") || (txt == "#downjson")) { //下载所有的共享RSS
+ var fileType = (txt == "#downjson") ? "json" : "xml";
+ DownAllRssToFile(fileType);
input.val("");
+ DoSearchInShared();
return;
}
@@ -401,39 +403,54 @@ function ReportInvalid(title, feedurl, dbId) {
//将内容全部下载到本地一个xml文件内
-function DownAllRssToFile() {
+//fileType: 保存的文件格式,xml/json
+function DownAllRssToFile(fileType) {
if (!g_SharedRss) {
return;
}
- var title, url, ftext, cat, rssd, fmtdate, nowdate, lang;
- var elementA = document.createElement('a');
- var aTxt = new Array();
- aTxt.push("");
- aTxt.push("");
- aTxt.push("");
- aTxt.push(" KindleEar.opml");
- aTxt.push(" " + new Date() + "");
- aTxt.push(" " + new Date() + "");
- aTxt.push(" KindleEar");
- aTxt.push("");
- aTxt.push("");
- for (var i = 0; i < g_SharedRss.length; i++) {
- title = escapeXml(g_SharedRss[i].t);
- url = escapeXml(g_SharedRss[i].u);
- cat = escapeXml(g_SharedRss[i].c);
- lang = g_SharedRss[i].l || '';
- ftext = (g_SharedRss[i].f == "false") ? "no" : "yes";
- aTxt.push(' '
- .format(title, url, ftext, cat, lang));
+ fileType = fileType || 'xml';
+ var content, mimeType;
+ var title, url, ftext, cat, lang;
+ const now = new Date();
+ if (fileType == 'xml') {
+ var aTxt = new Array();
+ aTxt.push("");
+ aTxt.push("");
+ aTxt.push("");
+ aTxt.push(" KindleEar.opml");
+ aTxt.push(" " + now + "");
+ aTxt.push(" " + now + "");
+ aTxt.push(" KindleEar");
+ aTxt.push("");
+ aTxt.push("");
+ for (var i = 0; i < g_SharedRss.length; i++) {
+ title = escapeXml(g_SharedRss[i].t);
+ url = escapeXml(g_SharedRss[i].u);
+ cat = escapeXml(g_SharedRss[i].c);
+ lang = g_SharedRss[i].l || '';
+ ftext = (g_SharedRss[i].f == "false") ? "no" : "yes";
+ aTxt.push(' '
+ .format(title, url, ftext, cat, lang));
+ }
+ aTxt.push("");
+ aTxt.push("\n");
+ content = aTxt.join("\n");
+ mimeType = "application/xml";
+ } else {
+ var jsonData = g_SharedRss.map(function(item) {
+ return {t: item.t, u: item.u, c: item.c, l: item.l || '', f: item.f};
+ });
+ content = JSON.stringify(jsonData, null, 2);
+ mimeType = "application/json";
}
- aTxt.push("");
- aTxt.push("\n");
-
- nowdate = new Date();
- fmtdate = "KindleEar_library_" + nowdate.getFullYear() + "_" + ((nowdate.getMonth() + 1)) + "_" + nowdate.getDate() + ".xml";
- elementA.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(aTxt.join("\n")));
- elementA.setAttribute("download", fmtdate);
+ var elementA = document.createElement('a');
+ const year = now.getFullYear();
+ const month = now.getMonth() + 1;
+ const date = now.getDate();
+ const fmtDate = "KindleEar_" + year + "_" + month + "_" + date + "." + fileType;
+ elementA.setAttribute("href", "data:" + mimeType + ";charset=utf-8," + encodeURIComponent(content));
+ elementA.setAttribute("download", fmtDate);
elementA.style.display = 'none';
document.body.appendChild(elementA);
elementA.click();
diff --git a/application/templates/adv_delivernow.html b/application/templates/adv_delivernow.html
index 27754962..f9535475 100644
--- a/application/templates/adv_delivernow.html
+++ b/application/templates/adv_delivernow.html
@@ -11,23 +11,30 @@
{% if recipes|length == 0 -%}
@@ -142,7 +142,7 @@
-
+
diff --git a/application/view/adv.py b/application/view/adv.py
index d8d546fa..8f15c334 100644
--- a/application/view/adv.py
+++ b/application/view/adv.py
@@ -32,6 +32,12 @@ def adv_render_template(tpl, advCurr, **kwargs):
@login_required()
def AdvDeliverNow(user: KeUser):
recipes = user.get_booked_recipe()
+ if user.cfg('enable_send') != 'all': #添加自定义RSS
+ rss = [BookedRecipe(recipe_id=r.recipe_id, separated=r.custom.get('separated', False),
+ user=user.name, title=r.title, description=r.description)
+ for r in user.all_custom_rss()]
+ recipes = rss + recipes
+
deliveryKey = app.config['DELIVERY_KEY']
return adv_render_template('adv_delivernow.html', 'deliverNow', user=user, recipes=recipes,
deliveryKey=deliveryKey)
diff --git a/application/view/deliver.py b/application/view/deliver.py
index 33bfc711..69cf96dd 100644
--- a/application/view/deliver.py
+++ b/application/view/deliver.py
@@ -78,20 +78,31 @@ def MultiUserDelivery():
#idList: recipe id列表,id格式:custom:xx,upload:xx,builtin:xx,为空则推送指定账号下所有订阅
def SingleUserDelivery(userName: str, idList: list=None):
user = KeUser.get_or_none(KeUser.name == userName)
- if not user or not user.cfg('kindle_email'):
+ if not user or ('email' in user.cfg('delivery_mode') and not user.cfg('kindle_email')):
return render_template('autoback.html', tips=_('The username does not exist or the email is empty.'))
- sent = []
#这里不判断特定账号是否已经订阅了指定的书籍,只要提供就推送
if idList:
- recipesToPush = list(filter(bool, map(user.get_booked_recipe, idList)))
+ toPush = []
+ for id_ in idList:
+ recipeType, dbId = Recipe.type_and_id(id_)
+ bked = user.get_booked_recipe(id_)
+ #如果没有启用自定义RSS推送
+ r = Recipe.get_by_id_or_none(dbId) if (not bked and (recipeType == 'custom')) else None
+ if r:
+ toPush.append({'id_': r.recipe_id, 'separated': r.custom.get('separated', False),
+ 'title': r.title})
+ elif bked:
+ toPush.append({'id_': bked.recipe_id, 'separated': bked.separated, 'title': bked.title})
else: #推送特定账号所有订阅的书籍
- recipesToPush = user.get_booked_recipe()
+ toPush = [{'id_': r.recipe_id, 'separated': r.separated, 'title': r.title}
+ for r in user.get_booked_recipe()]
+ sent = []
bkQueue = defaultdict(list)
- for bkRecipe in recipesToPush: #BookedRecipe实例
- queueOneBook(bkQueue, user, bkRecipe.recipe_id, bkRecipe.separated, reason='manual')
- sent.append(f'{bkRecipe.title}')
+ for bked in toPush:
+ queueOneBook(bkQueue, user, bked['id_'], bked['separated'], reason='manual')
+ sent.append(f'{bked["title"]}')
flushQueueToPush(bkQueue, reason='manual')
if sent:
diff --git a/application/view/settings.py b/application/view/settings.py
index e2e2d15d..b3b43bac 100644
--- a/application/view/settings.py
+++ b/application/view/settings.py
@@ -37,47 +37,36 @@ def Settings(user: KeUser):
@login_required()
def SettingsPost(user: KeUser):
form = request.form
- keMail = form.get('kindle_email', '').strip(';, ')
- myTitle = form.get('rss_title')
-
- send_mail_service = BuildSmSrvDict(user, form)
- if not keMail:
- tips = _("Kindle E-mail is requied!")
- elif not myTitle:
- tips = _("Title is requied!")
- elif not send_mail_service:
- tips = _("Some parameters are missing or wrong.")
- else:
- base_config = user.base_config
- book_config = user.book_config
-
- enable_send = form.get('enable_send')
- base_config['enable_send'] = enable_send if enable_send in ('all', 'recipes') else ''
- base_config['kindle_email'] = keMail
- base_config['delivery_mode'] = form.get('delivery_mode', 'email') if app.config['EBOOK_SAVE_DIR'] else 'email'
- base_config['webshelf_days'] = str_to_int(form.get('webshelf_days', '7'))
- base_config['timezone'] = float(form.get('timezone', '0'))
- user.send_time = int(form.get('send_time', '0'))
- book_config['type'] = form.get('book_type', 'epub')
- book_config['device'] = form.get('device_type', 'kindle')
- book_config['title_fmt'] = form.get('title_fmt', '')
- allDays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
- user.send_days = [weekday for weekday, day in enumerate(allDays) if str_to_bool(form.get(day, ''))]
- book_config['mode'] = form.get('book_mode', '')
- book_config['rm_links'] = form.get('remove_hyperlinks', '')
- book_config['author_fmt'] = form.get('author_format', '') #修正Kindle 5.9.x固件的bug【将作者显示为日期】
- book_config['title'] = myTitle
- book_config['language'] = form.get("book_language", "en")
- book_config['oldest_article'] = int(form.get('oldest', 7))
- book_config['time_fmt'] = form.get('time_fmt', '')
- user.base_config = base_config
- user.book_config = book_config
- user.send_mail_service = send_mail_service
- user.save()
- tips = _("Settings Saved!")
-
- #根据自定义RSS的使能设置,将自定义RSS添加进订阅列表或从订阅列表移除
- UpdateBookedCustomRss(user)
+ base_config = user.base_config
+ book_config = user.book_config
+
+ enable_send = form.get('enable_send')
+ base_config['enable_send'] = enable_send if enable_send in ('all', 'recipes') else ''
+ base_config['kindle_email'] = form.get('kindle_email', '').strip(';, ')
+ base_config['delivery_mode'] = form.get('delivery_mode', 'email') if app.config['EBOOK_SAVE_DIR'] else 'email'
+ base_config['webshelf_days'] = str_to_int(form.get('webshelf_days', '7'))
+ base_config['timezone'] = float(form.get('timezone', '0'))
+ user.send_time = int(form.get('send_time', '0'))
+ book_config['type'] = form.get('book_type', 'epub')
+ book_config['device'] = form.get('device_type', 'kindle')
+ book_config['title_fmt'] = form.get('title_fmt', '')
+ allDays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
+ user.send_days = [weekday for weekday, day in enumerate(allDays) if str_to_bool(form.get(day, ''))]
+ book_config['mode'] = form.get('book_mode', '')
+ book_config['rm_links'] = form.get('remove_hyperlinks', '')
+ book_config['author_fmt'] = form.get('author_format', '') #修正Kindle 5.9.x固件的bug【将作者显示为日期】
+ book_config['title'] = form.get('rss_title') or 'KindleEar'
+ book_config['language'] = form.get("book_language", "en")
+ book_config['oldest_article'] = int(form.get('oldest', 7))
+ book_config['time_fmt'] = form.get('time_fmt', '')
+ user.base_config = base_config
+ user.book_config = book_config
+ user.send_mail_service = BuildSmSrvDict(user, form)
+ user.save()
+ tips = _("Settings Saved!")
+
+ #根据自定义RSS的使能设置,将自定义RSS添加进订阅列表或从订阅列表移除
+ UpdateBookedCustomRss(user)
sm_services = avaliable_sm_services()
return render_template('settings.html', tab='set', user=user, tips=tips, langMap=LangMap(),
@@ -85,11 +74,11 @@ def SettingsPost(user: KeUser):
#构建发送邮件服务配置字典,返回空字典表示出错
#form: request.form 实例
-def BuildSmSrvDict(user: KeUser, form):
+def BuildSmSrvDict(user: KeUser, form) -> dict:
srv = user.send_mail_service.copy()
- srvType = form.get('sm_service', '')
#service==admin 说明和管理员的设置一致
if user.name == os.getenv('ADMIN_NAME') or srv.get('service') != 'admin':
+ srvType = form.get('sm_service', '')
srv['service'] = srvType
srv['apikey'] = form.get('sm_apikey', '')
srv['secret_key'] = form.get('sm_secret_key', '')
@@ -98,7 +87,7 @@ def BuildSmSrvDict(user: KeUser, form):
srv['username'] = form.get('sm_username', '')
srv['password'] = user.encrypt(form.get('sm_password', ''))
srv['save_path'] = form.get('sm_save_path', '')
- validations = {
+ validations = { #根据选择的发送邮件服务类型进行简单校验
'sendgrid': lambda srv: srv['apikey'],
'mailjet': lambda srv: srv['apikey'] and srv['secret_key'],
'smtp': lambda srv: all((srv['host'], srv['port'], srv['password'])), #部分smtp不需要账号名
diff --git a/application/work/worker.py b/application/work/worker.py
index f28e1457..e8611ab3 100644
--- a/application/work/worker.py
+++ b/application/work/worker.py
@@ -157,25 +157,33 @@ def WorkerImpl(userName: str, recipeId: Union[list,str,None]=None, reason='cron'
#在已订阅的Recipe或自定义RSS列表创建Recipe源码列表
#返回一个字典,键名为title,元素为 [BookedRecipe, Recipe, src]
def GetAllRecipeSrc(user, idList):
+ bkeds = []
+ for id_ in idList:
+ recipeType, dbId = Recipe.type_and_id(id_)
+ bked = BookedRecipe.get_or_none(BookedRecipe.recipe_id == id_)
+ #针对没有启用自定义RSS推送的情况,创建一个临时BookedRecipe对象但不保存到数据库
+ recipe = Recipe.get_by_id_or_none(dbId) if (not bked and (recipeType == 'custom')) else None
+ if recipe:
+ bked = BookedRecipe(recipe_id=id_, separated=recipe.custom.get('separated', False),
+ user=user.name, title=recipe.title, description=recipe.description)
+ bkeds.append({'recipeId': id_, 'recipeType': recipeType, 'dbId': dbId, 'bked': bked,
+ 'recipe': recipe})
+
srcDict = {}
- for bked in filter(bool, [BookedRecipe.get_or_none(BookedRecipe.recipe_id == id_) for id_ in idList]):
- recipeId = bked.recipe_id
- recipeType, dbId = Recipe.type_and_id(recipeId)
- if recipeType == 'builtin':
- bnInfo = GetBuiltinRecipeInfo(recipeId)
- src = GetBuiltinRecipeSource(recipeId)
+ for item in bkeds:
+ recipe = item['recipe']
+ if item['recipeType'] == 'builtin':
+ bnInfo = GetBuiltinRecipeInfo(item['recipeId'])
+ src = GetBuiltinRecipeSource(item['recipeId'])
if bnInfo and src:
- srcDict[bnInfo.get('title', '')] = [bked, bnInfo, src]
- continue
-
- recipe = Recipe.get_by_id_or_none(dbId)
- if recipe:
+ srcDict[bnInfo.get('title', '')] = [item['bked'], bnInfo, src]
+ elif recipe:
title = recipe.title
- if recipeType == 'upload': #上传的Recipe
- srcDict[title] = [bked, recipe, recipe.src]
+ if item['recipeType'] == 'upload': #上传的Recipe
+ srcDict[title] = [item['bked'], recipe, recipe.src]
else: #自定义RSS
src = GenerateRecipeSource(title, [(title, recipe.url)], user, isfulltext=recipe.isfulltext)
- srcDict[title] = [bked, recipe, src]
+ srcDict[title] = [item['bked'], recipe, src]
return srcDict
#返回可用的mp3cat执行文件路径