✨ Support sub
This commit is contained in:
parent
fe641bbe42
commit
4a39d35f15
8
ci.py
8
ci.py
@ -1,3 +1,4 @@
|
|||||||
|
import json
|
||||||
from configparser import RawConfigParser
|
from configparser import RawConfigParser
|
||||||
from os import sep, mkdir
|
from os import sep, mkdir
|
||||||
from os.path import exists
|
from os.path import exists
|
||||||
@ -10,13 +11,14 @@ from sqlitedict import SqliteDict
|
|||||||
|
|
||||||
if not exists("data"):
|
if not exists("data"):
|
||||||
mkdir("data")
|
mkdir("data")
|
||||||
sqlite = SqliteDict(f"data{sep}data.sqlite", autocommit=True)
|
sqlite = SqliteDict(f"data{sep}data.sqlite", encode=json.dumps, decode=json.loads, autocommit=True)
|
||||||
# data.sqlite 结构如下:
|
# data.sqlite 结构如下:
|
||||||
# {
|
# {
|
||||||
# "module 名称": {
|
# "module 名称": {
|
||||||
# "subscribes": [订阅id],
|
# "msg_link": str,
|
||||||
|
# "subscribes": List[订阅id: int],
|
||||||
# },
|
# },
|
||||||
# "update_time": "",
|
# "update_time": str,
|
||||||
# }
|
# }
|
||||||
# 读取配置文件
|
# 读取配置文件
|
||||||
config = RawConfigParser()
|
config = RawConfigParser()
|
||||||
|
0
defs/decorators.py
Normal file
0
defs/decorators.py
Normal file
35
defs/msg.py
35
defs/msg.py
@ -23,30 +23,45 @@ def gen_button(data: Module) -> InlineKeyboardMarkup:
|
|||||||
if data.releases:
|
if data.releases:
|
||||||
if data.releases[0].releaseAssets:
|
if data.releases[0].releaseAssets:
|
||||||
data_ = [[InlineKeyboardButton("⬇️ 下载", url=data.releases[0].releaseAssets[0].url)]]
|
data_ = [[InlineKeyboardButton("⬇️ 下载", url=data.releases[0].releaseAssets[0].url)]]
|
||||||
data_.extend([[InlineKeyboardButton("Release", url=data.releases[0].url),
|
data_.extend([[InlineKeyboardButton("Release", url=data.releases[0].url),
|
||||||
InlineKeyboardButton("主页", url=data.homepageUrl),
|
InlineKeyboardButton("主页", url=data.homepageUrl),
|
||||||
InlineKeyboardButton(
|
InlineKeyboardButton(
|
||||||
"订阅",
|
"订阅",
|
||||||
url=f"https://t.me/{me.username}?start={data.name.replace('.', '_')}"),]])
|
url=f"https://t.me/{me.username}?start={data.name.replace('.', '_')}"), ]])
|
||||||
|
else:
|
||||||
|
data_.extend([[InlineKeyboardButton("主页", url=data.homepageUrl),
|
||||||
|
InlineKeyboardButton(
|
||||||
|
"订阅",
|
||||||
|
url=f"https://t.me/{me.username}?start={data.name.replace('.', '_')}"), ]])
|
||||||
return InlineKeyboardMarkup(data_)
|
return InlineKeyboardMarkup(data_)
|
||||||
|
|
||||||
|
|
||||||
|
def format_text(text: str) -> str:
|
||||||
|
text = text.strip()
|
||||||
|
for i in ["/", " ", "-", "@", ]:
|
||||||
|
text = text.replace(i, "_")
|
||||||
|
for i in ["【", "】", "[", "]"]:
|
||||||
|
text = text.replace(i, "")
|
||||||
|
return text.strip()
|
||||||
|
|
||||||
|
|
||||||
def gen_tags(data: Module) -> str:
|
def gen_tags(data: Module) -> str:
|
||||||
text = f"#{data.description.split()[0]} "
|
text = f"#{format_text(data.description.split()[0])} "
|
||||||
text += f"#{data.collaborators[0]} "
|
if data.collaborators:
|
||||||
|
text += f"#{format_text(data.collaborators[0])} "
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
def gen_update_msg(data: Module) -> TrackMessage:
|
def gen_update_msg(data: Module) -> TrackMessage:
|
||||||
text = template.format(gen_tags(data), data.name, data.description, data.latestRelease,
|
text = template.format(gen_tags(data), data.name, data.description, data.latestRelease,
|
||||||
data.updatedAt,
|
data.updatedAt,
|
||||||
data.releases[0].description.replace(r"\r\n", "\n"))
|
data.releases[0].description.replace(r"\r\n", "\n")[:1000].strip())
|
||||||
url = None
|
url = None
|
||||||
name = data.name.replace('.', '_') + "-" + data.latestRelease
|
name = None
|
||||||
if data.releases:
|
if data.releases:
|
||||||
if data.releases[0].releaseAssets:
|
if data.releases[0].releaseAssets:
|
||||||
url = data.releases[0].releaseAssets[0].url
|
url = data.releases[0].releaseAssets[0].url
|
||||||
mime = data.releases[0].releaseAssets[0].name.split(".")[-1:][0]
|
mime = data.releases[0].releaseAssets[0].name.split(".")[-1:][0]
|
||||||
name += "." + mime
|
name = data.name.replace('.', '_') + "-" + data.latestRelease + "." + mime
|
||||||
button = gen_button(data)
|
button = gen_button(data)
|
||||||
return TrackMessage(text, url, name, button)
|
return TrackMessage(text, url, name, button)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from os import sep
|
from os import sep
|
||||||
from os.path import exists
|
from os.path import exists
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
from typing import List
|
from typing import List, Optional
|
||||||
|
|
||||||
from ci import client, sqlite
|
from ci import client, sqlite
|
||||||
from json import load
|
from json import load
|
||||||
@ -9,17 +9,25 @@ from defs.format_time import now_time
|
|||||||
from defs.utils import Module
|
from defs.utils import Module
|
||||||
|
|
||||||
new_modules: List[Module] = []
|
new_modules: List[Module] = []
|
||||||
|
new_modules_index: dict = {}
|
||||||
old_modules: List[Module] = []
|
old_modules: List[Module] = []
|
||||||
|
old_modules_index: dict = {}
|
||||||
if exists(f"data{sep}modules.json"):
|
if exists(f"data{sep}modules.json"):
|
||||||
with open(f"data{sep}modules.json", "r", encoding="utf-8") as file:
|
with open(f"data{sep}modules.json", "r", encoding="utf-8") as file:
|
||||||
new_modules = load(file)
|
temp_data = load(file)
|
||||||
|
for temp in temp_data:
|
||||||
|
new_modules.append(Module(temp))
|
||||||
if exists(f"data{sep}old_modules.json"):
|
if exists(f"data{sep}old_modules.json"):
|
||||||
with open(f"data{sep}old_modules.json", "r", encoding="utf-8") as file:
|
with open(f"data{sep}old_modules.json", "r", encoding="utf-8") as file:
|
||||||
old_modules = load(file)
|
temp_data = load(file)
|
||||||
|
for temp in temp_data:
|
||||||
|
old_modules.append(Module(temp))
|
||||||
|
new_modules_index = {i.name: i for i in new_modules}
|
||||||
|
old_modules_index = {i.name: i.latestRelease for i in old_modules}
|
||||||
|
|
||||||
|
|
||||||
async def update_data() -> None:
|
async def update_data() -> None:
|
||||||
global new_modules, old_modules
|
global new_modules, old_modules, new_modules_index
|
||||||
if exists(f"data{sep}modules.json"):
|
if exists(f"data{sep}modules.json"):
|
||||||
copyfile(f"data{sep}modules.json", f"data{sep}old_modules.json")
|
copyfile(f"data{sep}modules.json", f"data{sep}old_modules.json")
|
||||||
data = await client.get("https://modules.lsposed.org/modules.json")
|
data = await client.get("https://modules.lsposed.org/modules.json")
|
||||||
@ -30,14 +38,16 @@ async def update_data() -> None:
|
|||||||
new_modules = []
|
new_modules = []
|
||||||
for i in data:
|
for i in data:
|
||||||
new_modules.append(Module(i))
|
new_modules.append(Module(i))
|
||||||
|
new_modules_index = {i.name: i for i in new_modules}
|
||||||
sqlite["update_time"] = now_time()
|
sqlite["update_time"] = now_time()
|
||||||
|
|
||||||
|
|
||||||
def compare() -> List[Module]:
|
def compare() -> List[Module]:
|
||||||
|
global old_modules_index
|
||||||
data = []
|
data = []
|
||||||
old_data = {i.name: i.latestRelease for i in old_modules}
|
old_modules_index = {i.name: i.latestRelease for i in old_modules}
|
||||||
for i in new_modules:
|
for i in new_modules:
|
||||||
if i.latestRelease != old_data.get(i.name, ""):
|
if i.latestRelease != old_modules_index.get(i.name, ""):
|
||||||
data.append(i)
|
data.append(i)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@ -48,3 +58,28 @@ async def download(url: str, name: str) -> str:
|
|||||||
with open(f"data{sep}{name}", 'wb') as f:
|
with open(f"data{sep}{name}", 'wb') as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
return f"data{sep}{name}"
|
return f"data{sep}{name}"
|
||||||
|
|
||||||
|
|
||||||
|
def from_name_to_module(name: str) -> Optional[Module]:
|
||||||
|
return new_modules_index.get(name, None)
|
||||||
|
|
||||||
|
|
||||||
|
def from_list_to_name(data: List) -> str:
|
||||||
|
data_ = ""
|
||||||
|
for i in data:
|
||||||
|
name = new_modules_index.get(i, None)
|
||||||
|
if isinstance(name, Module):
|
||||||
|
data_ += f"\n{name.name}({name.description})"
|
||||||
|
return data_
|
||||||
|
|
||||||
|
|
||||||
|
def from_keyword_to_module(keyword: str) -> Optional[Module]:
|
||||||
|
for value in new_modules:
|
||||||
|
data = value.name + value.description + value.url + value.homepageUrl + value.summary + \
|
||||||
|
value.sourceUrl
|
||||||
|
if value.scope:
|
||||||
|
for i in value.scope:
|
||||||
|
data += i
|
||||||
|
if keyword in data:
|
||||||
|
return value
|
||||||
|
return None
|
||||||
|
97
defs/subs.py
Normal file
97
defs/subs.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import traceback
|
||||||
|
from asyncio import sleep
|
||||||
|
from random import uniform
|
||||||
|
|
||||||
|
from pyrogram.errors import FloodWait, ButtonUrlInvalid, BadRequest
|
||||||
|
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
|
|
||||||
|
from ci import app, sqlite, me
|
||||||
|
from defs.source import from_list_to_name
|
||||||
|
from defs.utils import Module
|
||||||
|
|
||||||
|
subs_msg = """
|
||||||
|
<code>{}</code> 有新的更新!
|
||||||
|
|
||||||
|
<b>版本:</b><code>{}</code>
|
||||||
|
<b>更新时间:</b><code>{}</code>
|
||||||
|
"""
|
||||||
|
subs_list_msg = """
|
||||||
|
<b>您订阅了:</b>{}
|
||||||
|
"""
|
||||||
|
subs_list_no_msg = """
|
||||||
|
<b>您订阅了个寂寞!</b>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def gen_subs_button(data: Module, link: str) -> InlineKeyboardMarkup:
|
||||||
|
data_ = [[InlineKeyboardButton("详情", url=link),
|
||||||
|
InlineKeyboardButton("退订",
|
||||||
|
url=f"https://t.me/{me.username}?start=un-{data.name.replace('.', '_')}"), ]]
|
||||||
|
return InlineKeyboardMarkup(data_)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_back_button() -> InlineKeyboardMarkup:
|
||||||
|
return InlineKeyboardMarkup([[InlineKeyboardButton("返回", callback_data="help"), ]])
|
||||||
|
|
||||||
|
|
||||||
|
def gen_subs_msg(cid: int) -> str:
|
||||||
|
data_ = []
|
||||||
|
for key, value in sqlite.items():
|
||||||
|
if key == "update_time":
|
||||||
|
continue
|
||||||
|
data = value.get("subscribes", [])
|
||||||
|
if cid in data:
|
||||||
|
data_.append(key)
|
||||||
|
if data_:
|
||||||
|
text = subs_list_msg.format(from_list_to_name(data_))
|
||||||
|
else:
|
||||||
|
text = subs_list_no_msg
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
async def send_subs_msg(cid: int, data: Module, link: str):
|
||||||
|
return await app.send_message(cid,
|
||||||
|
subs_msg.format(data.name, data.latestRelease, data.updatedAt),
|
||||||
|
reply_markup=gen_subs_button(data, link))
|
||||||
|
|
||||||
|
|
||||||
|
async def send_to_subscribes(data: Module):
|
||||||
|
users = sqlite.get(data.name, {}).get("subscribes", [])
|
||||||
|
link = sqlite.get(data.name, {}).get("msg_link", "https://t.me/lsposed_Modules_Updates_Tracker")
|
||||||
|
for i in users:
|
||||||
|
try:
|
||||||
|
await send_subs_msg(i, data, link)
|
||||||
|
except FloodWait as e:
|
||||||
|
print(f"Send subscribes msg flood - Sleep for {e.x} second(s)")
|
||||||
|
await sleep(uniform(0.5, 1.0))
|
||||||
|
await send_subs_msg(i, data, link)
|
||||||
|
except ButtonUrlInvalid:
|
||||||
|
print(f"Send button error")
|
||||||
|
await app.send_message(i, subs_msg.format(data.name, data.latestRelease, data.updatedAt), )
|
||||||
|
except BadRequest:
|
||||||
|
users.remove(i)
|
||||||
|
except Exception as e:
|
||||||
|
traceback.print_exc()
|
||||||
|
sqlite[data.name]["subscribes"] = users
|
||||||
|
|
||||||
|
|
||||||
|
def add_to_subs(cid: int, data: Module) -> bool:
|
||||||
|
users = sqlite.get(data.name, {}).get("subscribes", [])
|
||||||
|
if cid not in users:
|
||||||
|
users.append(cid)
|
||||||
|
data_ = sqlite.get(data.name, {"subscribes": []})
|
||||||
|
data_["subscribes"] = users
|
||||||
|
sqlite[data.name] = data_
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def remove_from_subs(cid: int, data: Module) -> bool:
|
||||||
|
users = sqlite.get(data.name, {}).get("subscribes", [])
|
||||||
|
if cid in users:
|
||||||
|
users.remove(cid)
|
||||||
|
data_ = sqlite.get(data.name, {"subscribes": []})
|
||||||
|
data_["subscribes"] = users
|
||||||
|
sqlite[data.name] = data_
|
||||||
|
return True
|
||||||
|
return False
|
@ -27,10 +27,10 @@ class Release:
|
|||||||
class Module:
|
class Module:
|
||||||
def __init__(self, data: dict):
|
def __init__(self, data: dict):
|
||||||
self.name: str = data["name"]
|
self.name: str = data["name"]
|
||||||
self.description: str = data["description"]
|
self.description: str = data["description"] if data["description"] else ""
|
||||||
self.url: str = data["url"]
|
self.url: str = data["url"] if data["url"] else ""
|
||||||
self.homepageUrl: str = data["homepageUrl"] if data["homepageUrl"] else data["url"]
|
self.homepageUrl: str = data["homepageUrl"] if data["homepageUrl"] else data["url"]
|
||||||
self.sourceUrl: str = data["sourceUrl"]
|
self.sourceUrl: str = data["sourceUrl"] if data["sourceUrl"] else ""
|
||||||
self.hide: bool = data["hide"]
|
self.hide: bool = data["hide"]
|
||||||
self.createdAt: str = strf_time(data["createdAt"])
|
self.createdAt: str = strf_time(data["createdAt"])
|
||||||
self.updatedAt: str = strf_time(data["updatedAt"])
|
self.updatedAt: str = strf_time(data["updatedAt"])
|
||||||
@ -47,7 +47,8 @@ class Module:
|
|||||||
for i in data["releases"]:
|
for i in data["releases"]:
|
||||||
releases.append(Release(i))
|
releases.append(Release(i))
|
||||||
self.releases: List[Release] = releases
|
self.releases: List[Release] = releases
|
||||||
self.summary = data["summary"]
|
self.summary: str = data["summary"] if data["summary"] else ""
|
||||||
|
self.scope: List[str] = data["scope"] if data["scope"] else []
|
||||||
|
|
||||||
|
|
||||||
class TrackMessage:
|
class TrackMessage:
|
||||||
|
26
plugins/callback.py
Normal file
26
plugins/callback.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
from pyrogram import Client, filters
|
||||||
|
from pyrogram.types import CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
|
|
||||||
|
from defs.subs import gen_subs_msg, gen_back_button
|
||||||
|
from plugins.help import help_msg
|
||||||
|
|
||||||
|
|
||||||
|
@Client.on_callback_query(filters.regex("help"))
|
||||||
|
async def help_set(_, query: CallbackQuery):
|
||||||
|
await query.edit_message_text(
|
||||||
|
help_msg,
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[[InlineKeyboardButton("订阅", callback_data="subs")]]
|
||||||
|
),
|
||||||
|
disable_web_page_preview=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@Client.on_callback_query(filters.regex("subs"))
|
||||||
|
async def subs_set(_, query: CallbackQuery):
|
||||||
|
text = gen_subs_msg(query.from_user.id)
|
||||||
|
await query.edit_message_text(
|
||||||
|
text,
|
||||||
|
reply_markup=gen_back_button(),
|
||||||
|
disable_web_page_preview=True,
|
||||||
|
)
|
32
plugins/help.py
Normal file
32
plugins/help.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
from pyrogram import Client, filters
|
||||||
|
from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
|
|
||||||
|
help_msg = """
|
||||||
|
下面是我学会了的指令列表:
|
||||||
|
|
||||||
|
👩🏻💼 » /subscribe <code>包名|关键词|作用域|开源地址|模块地址</code> - 订阅更新
|
||||||
|
<code>/subscribe nil.nadph.qnotified</code>
|
||||||
|
<code>/subscribe QNotified</code>
|
||||||
|
<code>/subscribe com.tencent.mobileqq</code>
|
||||||
|
<code>/subscribe https://github.com/ferredoxin/QNotified</code>
|
||||||
|
<code>/subscribe https://modules.lsposed.org/module/nil.nadph.qnotified</code>
|
||||||
|
|
||||||
|
👩🏻💼 » /unsubscribe <code>包名|关键词|作用域|开源地址|模块地址</code> - 取消订阅更新
|
||||||
|
|
||||||
|
👩🏻💼 » /subscription - 列出您当前的订阅
|
||||||
|
|
||||||
|
👩🏻💼 » /info <code>包名|关键词|作用域|开源地址|模块地址</code> - 查询模块信息
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@Client.on_message(filters.incoming & filters.private &
|
||||||
|
filters.command(["help"]))
|
||||||
|
async def help_command(_: Client, message: Message):
|
||||||
|
await message.reply(
|
||||||
|
help_msg,
|
||||||
|
reply_markup=InlineKeyboardMarkup(
|
||||||
|
[[InlineKeyboardButton("订阅", callback_data="subs")]]
|
||||||
|
),
|
||||||
|
disable_web_page_preview=True,
|
||||||
|
quote=True,
|
||||||
|
)
|
64
plugins/info.py
Normal file
64
plugins/info.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
from pyrogram import Client, filters
|
||||||
|
from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
|
|
||||||
|
from ci import sqlite, me
|
||||||
|
from defs.source import from_keyword_to_module
|
||||||
|
from defs.utils import Module
|
||||||
|
from plugins.start import not_found_msg
|
||||||
|
|
||||||
|
info_help_msg = """
|
||||||
|
👩🏻💼 » /info <code>包名|关键词|作用域|开源地址|模块地址</code> - 查询模块信息
|
||||||
|
<code>/info nil.nadph.qnotified</code>
|
||||||
|
<code>/info QNotified</code>
|
||||||
|
<code>/info com.tencent.mobileqq</code>
|
||||||
|
<code>/info https://github.com/ferredoxin/QNotified</code>
|
||||||
|
<code>/info https://modules.lsposed.org/module/nil.nadph.qnotified</code>
|
||||||
|
"""
|
||||||
|
module_msg = """
|
||||||
|
<b>{}</b>
|
||||||
|
|
||||||
|
<b>简介:</b><code>{}</code>
|
||||||
|
<b>概要:</b><code>{}</code>
|
||||||
|
<b>版本:</b><code>{}</code>
|
||||||
|
<b>创建时间:</b><code>{}</code>
|
||||||
|
<b>更新时间:</b><code>{}</code>
|
||||||
|
<b>作用域:</b>
|
||||||
|
<code>
|
||||||
|
{}
|
||||||
|
</code>
|
||||||
|
@lsposed_Modules_Updates_Tracker | @lsposed_Geeks_Bot
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def gen_info_button(data: Module) -> InlineKeyboardMarkup:
|
||||||
|
msg_link = sqlite.get(data.name, {}).get("msg_link", "https://t.me/lsposed_Modules_Updates_Tracker")
|
||||||
|
data_ = [[InlineKeyboardButton("详情", url=msg_link),
|
||||||
|
InlineKeyboardButton("订阅",
|
||||||
|
url=f"https://t.me/{me.username}?start={data.name.replace('.', '_')}"), ]]
|
||||||
|
return InlineKeyboardMarkup(data_)
|
||||||
|
|
||||||
|
|
||||||
|
@Client.on_message(filters.incoming & filters.private &
|
||||||
|
filters.command(["info"]))
|
||||||
|
async def info_command(_: Client, message: Message):
|
||||||
|
if len(message.command) == 1:
|
||||||
|
await message.reply(info_help_msg, quote=True)
|
||||||
|
else:
|
||||||
|
data = " ".join(message.command[1:])
|
||||||
|
module = from_keyword_to_module(data)
|
||||||
|
if module:
|
||||||
|
await message.reply(
|
||||||
|
module_msg.format(
|
||||||
|
module.name,
|
||||||
|
module.description,
|
||||||
|
module.summary,
|
||||||
|
module.latestRelease,
|
||||||
|
module.createdAt,
|
||||||
|
module.updatedAt,
|
||||||
|
"\n ".join(module.scope),
|
||||||
|
),
|
||||||
|
reply_markup=gen_info_button(module),
|
||||||
|
quote=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await message.reply(not_found_msg.format(data), quote=True)
|
67
plugins/inline.py
Normal file
67
plugins/inline.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
from pyrogram import Client, emoji
|
||||||
|
from pyrogram.types import InlineQuery, InputTextMessageContent, InlineQueryResultArticle
|
||||||
|
|
||||||
|
from defs.source import new_modules, new_modules_index
|
||||||
|
from plugins.info import module_msg, gen_info_button
|
||||||
|
|
||||||
|
|
||||||
|
@Client.on_inline_query()
|
||||||
|
async def inline_process(_: Client, query: InlineQuery):
|
||||||
|
data = []
|
||||||
|
text = query.query.split()
|
||||||
|
nums = 0
|
||||||
|
if not new_modules_index:
|
||||||
|
return
|
||||||
|
data_ = new_modules_index
|
||||||
|
for key, module in data_.items():
|
||||||
|
if len(text) == 0:
|
||||||
|
data.append(InlineQueryResultArticle(
|
||||||
|
(module.summary if module.summary else module.description) + " - " + module.name,
|
||||||
|
InputTextMessageContent(module_msg.format(
|
||||||
|
module.name,
|
||||||
|
module.description,
|
||||||
|
module.summary,
|
||||||
|
module.latestRelease,
|
||||||
|
module.createdAt,
|
||||||
|
module.updatedAt,
|
||||||
|
"\n ".join(module.scope),
|
||||||
|
)),
|
||||||
|
reply_markup=gen_info_button(module),
|
||||||
|
))
|
||||||
|
nums += 1
|
||||||
|
else:
|
||||||
|
name = module.name + module.description + module.url + module.homepageUrl + module.summary + \
|
||||||
|
module.sourceUrl
|
||||||
|
if module.scope:
|
||||||
|
for i in module.scope:
|
||||||
|
name += i
|
||||||
|
skip = False
|
||||||
|
for i in text:
|
||||||
|
if i not in name:
|
||||||
|
skip = True
|
||||||
|
if not skip:
|
||||||
|
data.append(InlineQueryResultArticle(
|
||||||
|
(module.summary if module.summary else module.description) + " - " + module.name,
|
||||||
|
InputTextMessageContent(module_msg.format(
|
||||||
|
module.name,
|
||||||
|
module.description,
|
||||||
|
module.summary,
|
||||||
|
module.latestRelease,
|
||||||
|
module.createdAt,
|
||||||
|
module.updatedAt,
|
||||||
|
"\n ".join(module.scope),
|
||||||
|
)),
|
||||||
|
reply_markup=gen_info_button(module),
|
||||||
|
))
|
||||||
|
nums += 1
|
||||||
|
if nums >= 50:
|
||||||
|
break
|
||||||
|
if nums == 0:
|
||||||
|
return await query.answer(
|
||||||
|
results=[],
|
||||||
|
switch_pm_text=f'{emoji.CROSS_MARK} 字符串 "{" ".join(text)}" 没有搜索到任何结果',
|
||||||
|
switch_pm_parameter="help",
|
||||||
|
)
|
||||||
|
await query.answer(data,
|
||||||
|
switch_pm_text=f'{emoji.KEY} 搜索了 {len(new_modules)} 个模块',
|
||||||
|
switch_pm_parameter="help", )
|
@ -1,6 +1,8 @@
|
|||||||
from pyrogram import Client, filters
|
from pyrogram import Client, filters
|
||||||
from pyrogram.types import Message
|
from pyrogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
from ci import me
|
from ci import me
|
||||||
|
from defs.source import from_name_to_module
|
||||||
|
from defs.subs import add_to_subs, remove_from_subs
|
||||||
|
|
||||||
des = """
|
des = """
|
||||||
你好!{} 我是 [{}]({}),一个为 lsposed 用户打造的一体化机器人!
|
你好!{} 我是 [{}]({}),一个为 lsposed 用户打造的一体化机器人!
|
||||||
@ -9,6 +11,29 @@ des = """
|
|||||||
点击下面的帮助按钮来查看使用方法。
|
点击下面的帮助按钮来查看使用方法。
|
||||||
加入 [我的频道](https://t.me/lsposed_Modules_Updates_Tracker) 获取关于 lsposed 模块的所有更新和公告!
|
加入 [我的频道](https://t.me/lsposed_Modules_Updates_Tracker) 获取关于 lsposed 模块的所有更新和公告!
|
||||||
"""
|
"""
|
||||||
|
unsub_msg = """
|
||||||
|
<b>成功退订了</b> <code>{}</code> <b>的更新!</b>
|
||||||
|
"""
|
||||||
|
not_sub_msg = """
|
||||||
|
<b>你好像没有订阅</b> <code>{}</code> <b>的更新!</b>
|
||||||
|
"""
|
||||||
|
sub_msg = """
|
||||||
|
<b>成功订阅了</b> <code>{}</code> <b>的更新!</b>
|
||||||
|
"""
|
||||||
|
already_sub_msg = """
|
||||||
|
<b>已经订阅过</b> <code>{}</code> <b>的更新!</b>
|
||||||
|
"""
|
||||||
|
not_found_msg = """
|
||||||
|
<b>没有找到名为</b> <code>{}</code> <b>的模块!</b>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def gen_help_button() -> InlineKeyboardMarkup:
|
||||||
|
data_ = [[InlineKeyboardButton("📢 官方频道", url="https://t.me/lsposed_Modules_Updates_Tracker"),
|
||||||
|
InlineKeyboardButton("💬 官方群组", url="https://t.me/Invite_Challenge_Bot?start=1"), ],
|
||||||
|
[InlineKeyboardButton("❓ 阅读帮助", callback_data="help")],
|
||||||
|
]
|
||||||
|
return InlineKeyboardMarkup(data_)
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.incoming & filters.private &
|
@Client.on_message(filters.incoming & filters.private &
|
||||||
@ -17,6 +42,35 @@ async def start_command(client: Client, message: Message):
|
|||||||
"""
|
"""
|
||||||
回应消息
|
回应消息
|
||||||
"""
|
"""
|
||||||
await message.reply(des.format(message.from_user.mention(),
|
if len(message.command) == 1:
|
||||||
me.name,
|
await message.reply(des.format(message.from_user.mention(),
|
||||||
f"https://t.me/{me.username}"), quote=True,)
|
me.name,
|
||||||
|
f"https://t.me/{me.username}"),
|
||||||
|
reply_markup=gen_help_button(),
|
||||||
|
quote=True, )
|
||||||
|
else:
|
||||||
|
data = message.command[1].replace("_", ".")
|
||||||
|
if data.startswith("un-"):
|
||||||
|
# 退订
|
||||||
|
name = data[3:]
|
||||||
|
data = from_name_to_module(name)
|
||||||
|
if data:
|
||||||
|
success = remove_from_subs(message.from_user.id, data)
|
||||||
|
if success:
|
||||||
|
await message.reply(unsub_msg.format(data.name), quote=True)
|
||||||
|
else:
|
||||||
|
await message.reply(not_sub_msg.format(data.name), quote=True)
|
||||||
|
else:
|
||||||
|
await message.reply(not_found_msg.format(name), quote=True)
|
||||||
|
else:
|
||||||
|
# 订阅
|
||||||
|
name = data
|
||||||
|
data = from_name_to_module(data)
|
||||||
|
if data:
|
||||||
|
success = add_to_subs(message.from_user.id, data)
|
||||||
|
if success:
|
||||||
|
await message.reply(sub_msg.format(data.name), quote=True)
|
||||||
|
else:
|
||||||
|
await message.reply(already_sub_msg.format(data.name), quote=True)
|
||||||
|
else:
|
||||||
|
await message.reply(not_found_msg.format(name), quote=True)
|
||||||
|
66
plugins/subs.py
Normal file
66
plugins/subs.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
from pyrogram import Client, filters
|
||||||
|
from pyrogram.types import Message
|
||||||
|
|
||||||
|
from defs.source import from_keyword_to_module
|
||||||
|
from defs.subs import gen_subs_msg, gen_back_button, add_to_subs, remove_from_subs
|
||||||
|
from plugins.start import sub_msg, not_found_msg, already_sub_msg, unsub_msg, not_sub_msg
|
||||||
|
|
||||||
|
sub_help_msg = """
|
||||||
|
👩🏻💼 » /subscribe <code>包名|关键词|作用域|开源地址|模块地址</code> - 订阅更新
|
||||||
|
<code>/subscribe nil.nadph.qnotified</code>
|
||||||
|
<code>/subscribe QNotified</code>
|
||||||
|
<code>/subscribe com.tencent.mobileqq</code>
|
||||||
|
<code>/subscribe https://github.com/ferredoxin/QNotified</code>
|
||||||
|
<code>/subscribe https://modules.lsposed.org/module/nil.nadph.qnotified</code>
|
||||||
|
"""
|
||||||
|
unsub_help_msg = """
|
||||||
|
👩🏻💼 » /unsubscribe <code>包名|关键词|作用域|开源地址|模块地址</code> - 取消订阅更新
|
||||||
|
<code>/unsubscribe nil.nadph.qnotified</code>
|
||||||
|
<code>/unsubscribe QNotified</code>
|
||||||
|
<code>/unsubscribe com.tencent.mobileqq</code>
|
||||||
|
<code>/unsubscribe https://github.com/ferredoxin/QNotified</code>
|
||||||
|
<code>/unsubscribe https://modules.lsposed.org/module/nil.nadph.qnotified</code>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@Client.on_message(filters.incoming & filters.private &
|
||||||
|
filters.command(["subscription"]))
|
||||||
|
async def subscription_command(_: Client, message: Message):
|
||||||
|
text = gen_subs_msg(message.from_user.id)
|
||||||
|
await message.reply(text, reply_markup=gen_back_button(), quote=True, )
|
||||||
|
|
||||||
|
|
||||||
|
@Client.on_message(filters.incoming & filters.private &
|
||||||
|
filters.command(["subscribe"]))
|
||||||
|
async def sub_command(_: Client, message: Message):
|
||||||
|
if len(message.command) == 1:
|
||||||
|
await message.reply(sub_help_msg, reply_markup=gen_back_button(), quote=True)
|
||||||
|
else:
|
||||||
|
data = " ".join(message.command[1:])
|
||||||
|
module = from_keyword_to_module(data)
|
||||||
|
if module:
|
||||||
|
success = add_to_subs(message.from_user.id, module)
|
||||||
|
if success:
|
||||||
|
await message.reply(sub_msg.format(module.name), quote=True)
|
||||||
|
else:
|
||||||
|
await message.reply(already_sub_msg.format(module.name), quote=True)
|
||||||
|
else:
|
||||||
|
await message.reply(not_found_msg.format(data), quote=True)
|
||||||
|
|
||||||
|
|
||||||
|
@Client.on_message(filters.incoming & filters.private &
|
||||||
|
filters.command(["unsubscribe"]))
|
||||||
|
async def un_sub_command(_: Client, message: Message):
|
||||||
|
if len(message.command) == 1:
|
||||||
|
await message.reply(unsub_help_msg, reply_markup=gen_back_button(), quote=True)
|
||||||
|
else:
|
||||||
|
data = " ".join(message.command[1:])
|
||||||
|
module = from_keyword_to_module(data)
|
||||||
|
if module:
|
||||||
|
success = remove_from_subs(message.from_user.id, module)
|
||||||
|
if success:
|
||||||
|
await message.reply(unsub_msg.format(module.name), quote=True)
|
||||||
|
else:
|
||||||
|
await message.reply(not_sub_msg.format(module.name), quote=True)
|
||||||
|
else:
|
||||||
|
await message.reply(not_found_msg.format(data), quote=True)
|
@ -6,23 +6,24 @@ from random import uniform
|
|||||||
from pyrogram.errors import FloodWait, ButtonUrlInvalid
|
from pyrogram.errors import FloodWait, ButtonUrlInvalid
|
||||||
from pyrogram.types import Message
|
from pyrogram.types import Message
|
||||||
|
|
||||||
from ci import app, scheduler, channel_id, admin_id
|
from ci import app, scheduler, channel_id, admin_id, sqlite
|
||||||
from pyrogram import Client, filters
|
from pyrogram import Client, filters
|
||||||
from defs.msg import gen_update_msg
|
from defs.msg import gen_update_msg
|
||||||
from defs.source import update_data, compare, download
|
from defs.source import update_data, compare, download
|
||||||
|
from defs.subs import send_to_subscribes
|
||||||
|
|
||||||
|
|
||||||
async def send_track_msg(file, track_msg):
|
async def send_track_msg(file, track_msg) -> Message:
|
||||||
if file:
|
if file:
|
||||||
await app.send_document(channel_id, file,
|
return await app.send_document(channel_id, file,
|
||||||
caption=track_msg.text[:1000],
|
caption=track_msg.text,
|
||||||
force_document=True,
|
force_document=True,
|
||||||
parse_mode="html",
|
parse_mode="html",
|
||||||
reply_markup=track_msg.button)
|
reply_markup=track_msg.button)
|
||||||
else:
|
else:
|
||||||
await app.send_message(channel_id, track_msg.text[:1000],
|
return await app.send_message(channel_id, track_msg.text,
|
||||||
parse_mode="html",
|
parse_mode="html",
|
||||||
reply_markup=track_msg.button)
|
reply_markup=track_msg.button)
|
||||||
|
|
||||||
|
|
||||||
@scheduler.scheduled_job("cron", minute="*/30", id="0")
|
@scheduler.scheduled_job("cron", minute="*/30", id="0")
|
||||||
@ -31,20 +32,21 @@ async def run_every_30_minute():
|
|||||||
need_update = compare()
|
need_update = compare()
|
||||||
for i in need_update:
|
for i in need_update:
|
||||||
track_msg = gen_update_msg(i)
|
track_msg = gen_update_msg(i)
|
||||||
|
msg = None
|
||||||
if track_msg.url:
|
if track_msg.url:
|
||||||
file = await download(track_msg.url, track_msg.name)
|
file = await download(track_msg.url, track_msg.name)
|
||||||
try:
|
try:
|
||||||
await send_track_msg(file, track_msg)
|
msg = await send_track_msg(file, track_msg)
|
||||||
except FloodWait as e:
|
except FloodWait as e:
|
||||||
print(f"Send document flood - Sleep for {e.x} second(s)")
|
print(f"Send document flood - Sleep for {e.x} second(s)")
|
||||||
await sleep(uniform(0.5, 1.0))
|
await sleep(uniform(0.5, 1.0))
|
||||||
await send_track_msg(file, track_msg)
|
msg = await send_track_msg(file, track_msg)
|
||||||
except ButtonUrlInvalid:
|
except ButtonUrlInvalid:
|
||||||
print(f"Send button error")
|
print(f"Send button error")
|
||||||
await app.send_document(channel_id, file,
|
msg = await app.send_document(channel_id, file,
|
||||||
caption=track_msg.text,
|
caption=track_msg.text,
|
||||||
force_document=True,
|
force_document=True,
|
||||||
parse_mode="html",)
|
parse_mode="html", )
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
try:
|
try:
|
||||||
@ -53,17 +55,22 @@ async def run_every_30_minute():
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
await send_track_msg(None, track_msg)
|
msg = await send_track_msg(None, track_msg)
|
||||||
except FloodWait as e:
|
except FloodWait as e:
|
||||||
print(f"Send document flood - Sleep for {e.x} second(s)")
|
print(f"Send document flood - Sleep for {e.x} second(s)")
|
||||||
await sleep(e.x + uniform(0.5, 1.0))
|
await sleep(e.x + uniform(0.5, 1.0))
|
||||||
await send_track_msg(None, track_msg)
|
msg = await send_track_msg(None, track_msg)
|
||||||
except ButtonUrlInvalid:
|
except ButtonUrlInvalid:
|
||||||
print(f"Send button error")
|
print(f"Send button error")
|
||||||
await app.send_message(channel_id, track_msg.text, parse_mode="html",)
|
msg = await app.send_message(channel_id, track_msg.text, parse_mode="html", )
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
await sleep(uniform(0.5, 2.0))
|
await sleep(uniform(0.5, 2.0))
|
||||||
|
data_ = sqlite.get(i.name, {"msg_link": ""})
|
||||||
|
data_["msg_link"] = msg.link
|
||||||
|
sqlite[i.name] = data_
|
||||||
|
await send_to_subscribes(i)
|
||||||
|
await sleep(uniform(0.5, 2.0))
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.incoming & filters.private & filters.chat(admin_id) &
|
@Client.on_message(filters.incoming & filters.private & filters.chat(admin_id) &
|
||||||
|
Loading…
Reference in New Issue
Block a user