mirror of
https://github.com/tgbot-collection/YYeTsBot.git
synced 2025-11-25 19:37:34 +08:00
add redis, new response
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
FROM python:alpine
|
||||
FROM python:3.8-alpine
|
||||
|
||||
RUN apk update && apk add --no-cache tzdata alpine-sdk libxml2 libxslt-dev
|
||||
COPY requirements.txt /requirements.txt
|
||||
|
||||
45
README.md
45
README.md
@@ -1,16 +1,21 @@
|
||||
# YYeTsBot
|
||||
|
||||
人人影视bot,[戳我使用](https://t.me/yyets_bot) 此机器人长期维护,如果遇到问题可以发送报告给我。
|
||||
|
||||
# 使用说明
|
||||
直接发送想要看的剧集名称就可以了,可选分享网页或者链接(ed2k和磁力链接)
|
||||
直接发送想要看的剧集名称就可以了,可选分享网页或者链接(ed2k和磁力链接)。
|
||||
|
||||
**由于译名的不同,建议输入部分译名,然后从列表中进行选择。**
|
||||
|
||||
# commands
|
||||
|
||||
```
|
||||
start - 开始使用
|
||||
help - 帮助
|
||||
credits - 致谢
|
||||
ping - 运行状态
|
||||
```
|
||||
|
||||
# 截图
|
||||
|
||||

|
||||
@@ -18,40 +23,54 @@ ping - 运行状态
|
||||

|
||||
|
||||
# 部署方法
|
||||
## 使用docker
|
||||
```bash
|
||||
docker run -d --restart=always -e TOKEN="TOKEN" bennythink/yyetsbot
|
||||
```
|
||||
根据情况,还可以 `-e USERNAME="1234"`,USERNAME和PASSWORD是在人人影视的有效的用户名和密码
|
||||
|
||||
也可以自己构建docker image:
|
||||
```bash
|
||||
docker build -t yyetsbot .
|
||||
```
|
||||
## 使用docker
|
||||
|
||||
参见 [这里](https://github.com/tgbot-collection/BotsRunner)
|
||||
|
||||
## 常规方式
|
||||
|
||||
### 1. 环境
|
||||
推荐使用Python 3.6+
|
||||
|
||||
推荐使用Python 3.6+,需要安装redis `apt install redis`,根据个人情况可以使用virtualenv
|
||||
|
||||
```bash
|
||||
pip install -r requirements.py
|
||||
```
|
||||
|
||||
### 2. 配置TOKEN
|
||||
修改`config.py`,把TOKEN修改为你的bot token, USERNAME和PASSWORD是在人人影视的有效的用户名和密码
|
||||
|
||||
修改`config.py`,根据需求修改如下配置项
|
||||
|
||||
* TOKEN:bot token
|
||||
* USERNAME:USERNAME和PASSWORD是在人人影视的有效的用户名和密码
|
||||
* PASSWORD :USERNAME和PASSWORD是在人人影视的有效的用户名和密码
|
||||
* PROXY :是否需要使用代理 格式 `socks5://userproxy:password@proxy_address:port`
|
||||
* MAINTAINER:维护者的Telegram UserID
|
||||
* REDIS:redis的地址,一般为localhost,
|
||||
|
||||
也可以使用环境变量,如 `export TOKEN="1234"`
|
||||
|
||||
### 3. 运行
|
||||
|
||||
```bash
|
||||
python /path/to/YYeTsBot/bot.py
|
||||
```
|
||||
|
||||
### 4. systemd 单元文件
|
||||
|
||||
参考 `yyets.service`
|
||||
|
||||
# Help
|
||||
|
||||
- [ ] test case...
|
||||
|
||||
# Credits
|
||||
|
||||
* [人人影视](http://www.zmz2019.com/)
|
||||
* [追新番](http://www.zhuixinfan.com/main.php)
|
||||
* [FIX字幕侠](http://www.zimuxia.cn/)
|
||||
* [磁力下载站](http://oabt005.com/home.html)
|
||||
|
||||
# License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
74
bot.py
74
bot.py
@@ -9,6 +9,8 @@ import time
|
||||
import re
|
||||
import os
|
||||
import logging
|
||||
import json
|
||||
import tempfile
|
||||
|
||||
from urllib.parse import quote_plus
|
||||
|
||||
@@ -17,7 +19,7 @@ from telebot import types, apihelper
|
||||
from tgbot_ping import get_runtime
|
||||
|
||||
from html_request import get_search_html, analyse_search_html, get_detail_page
|
||||
from utils import save_dump, upsert, get
|
||||
from utils import save_dump, save_to_cache, get_from_cache
|
||||
from config import PROXY, TOKEN, SEARCH_URL, MAINTAINER
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(filename)s [%(levelname)s]: %(message)s')
|
||||
@@ -111,14 +113,13 @@ def send_search(message):
|
||||
bot.send_sticker(message.chat.id, sti)
|
||||
return
|
||||
|
||||
logging.info('Receiving message about %s from user %s(%s)', name, message.chat.username,
|
||||
message.chat.id)
|
||||
logging.info('Receiving message about %s from user %s(%s)', name, message.chat.username, message.chat.id)
|
||||
html = get_search_html(name)
|
||||
result = analyse_search_html(html)
|
||||
|
||||
markup = types.InlineKeyboardMarkup()
|
||||
for url, detail in result.items():
|
||||
btn = types.InlineKeyboardButton(detail['name'], callback_data=url)
|
||||
btn = types.InlineKeyboardButton(detail['name'], callback_data="choose%s" % url)
|
||||
markup.add(btn)
|
||||
|
||||
if result:
|
||||
@@ -145,59 +146,46 @@ def send_search(message):
|
||||
save_dump(content)
|
||||
|
||||
|
||||
@bot.callback_query_handler(func=lambda call: 'resource' in call.data)
|
||||
@bot.callback_query_handler(func=lambda call: re.findall(r"choose(\S*)", call.data))
|
||||
def choose_link(call):
|
||||
bot.send_chat_action(call.message.chat.id, 'typing')
|
||||
resource_url = call.data
|
||||
link = get_detail_page(resource_url)
|
||||
upsert(call.id, link)
|
||||
# call.data is url, http://www.rrys2020.com/resource/36588
|
||||
resource_url = re.findall(r"choose(\S*)", call.data)[0]
|
||||
|
||||
link = get_from_cache(resource_url)
|
||||
if not link:
|
||||
link = get_detail_page(resource_url)
|
||||
save_to_cache(resource_url, link)
|
||||
|
||||
markup = types.InlineKeyboardMarkup()
|
||||
btn1 = types.InlineKeyboardButton("分享页面", callback_data="share%s" % call.id)
|
||||
btn2 = types.InlineKeyboardButton("继续点按钮", callback_data="select%s" % call.id)
|
||||
btn1 = types.InlineKeyboardButton("分享页面", callback_data="share%s" % resource_url)
|
||||
btn2 = types.InlineKeyboardButton("我全都要", callback_data="all%s" % resource_url)
|
||||
markup.add(btn1, btn2)
|
||||
bot.send_message(call.message.chat.id, "想要分享页面,还是继续点击按钮", reply_markup=markup)
|
||||
bot.send_message(call.message.chat.id, "想要分享页面,还是我全都要?", reply_markup=markup)
|
||||
|
||||
|
||||
@bot.callback_query_handler(func=lambda call: re.findall(r"share(\d*)", call.data))
|
||||
@bot.callback_query_handler(func=lambda call: re.findall(r"share(\S*)", call.data))
|
||||
def share_page(call):
|
||||
bot.send_chat_action(call.message.chat.id, 'typing')
|
||||
cid = re.findall(r"share(\d*)", call.data)[0]
|
||||
result = get(cid)
|
||||
resource_url = re.findall(r"share(\S*)", call.data)[0]
|
||||
result = get_from_cache(resource_url)
|
||||
bot.send_message(call.message.chat.id, result['share'])
|
||||
|
||||
|
||||
@bot.callback_query_handler(func=lambda call: re.findall(r"select(\d*)", call.data))
|
||||
def select_episode(call):
|
||||
@bot.callback_query_handler(func=lambda call: re.findall(r"all(\S*)", call.data))
|
||||
def all_episode(call):
|
||||
# just send a file
|
||||
bot.send_chat_action(call.message.chat.id, 'typing')
|
||||
cid = re.findall(r"select(\d*)", call.data)[0]
|
||||
result = get(cid)
|
||||
markup = types.InlineKeyboardMarkup()
|
||||
resource_url = re.findall(r"all(\S*)", call.data)[0]
|
||||
result = get_from_cache(resource_url)
|
||||
|
||||
if not result['rss']:
|
||||
btn = types.InlineKeyboardButton("点击打开分享网站", url=result['share'])
|
||||
markup.add(btn)
|
||||
bot.send_message(call.message.chat.id, "哎呀呀,这是个电影,恐怕没得选吧!", reply_markup=markup)
|
||||
else:
|
||||
for guid, detail in result['rss'].items():
|
||||
btn = types.InlineKeyboardButton(detail['title'], callback_data=f"cid{cid}guid{guid}")
|
||||
markup.add(btn)
|
||||
bot.send_message(call.message.chat.id, "选一集吧!", reply_markup=markup)
|
||||
with tempfile.NamedTemporaryFile(mode='wb+', prefix=result["cnname"], suffix=".txt") as tmp:
|
||||
bytes_data = json.dumps(result["all"], ensure_ascii=False, indent=4).encode('u8')
|
||||
tmp.write(bytes_data)
|
||||
|
||||
|
||||
@bot.callback_query_handler(func=lambda call: re.findall(r"cid(\d*)guid(.*)", call.data))
|
||||
def send_link(call):
|
||||
bot.send_chat_action(call.message.chat.id, 'typing')
|
||||
data = re.findall(r"cid(\d*)guid(.*)", call.data)[0]
|
||||
cid, guid = data[0], data[1]
|
||||
links = get(cid)['rss'][guid]
|
||||
ed2k, magnet, pan = "`{}`".format(links['ed2k']), "`{}`".format(links['magnet']), "`{}`".format(links['pan'])
|
||||
bot.send_message(call.message.chat.id, f"{links['title']}的下载资源如下")
|
||||
if ed2k != "``":
|
||||
bot.send_message(call.message.chat.id, ed2k, parse_mode='markdown')
|
||||
if magnet != "``":
|
||||
bot.send_message(call.message.chat.id, magnet, parse_mode='markdown')
|
||||
if pan != "``":
|
||||
bot.send_message(call.message.chat.id, pan, parse_mode='markdown')
|
||||
bot.send_chat_action(call.message.chat.id, 'upload_document')
|
||||
with open(tmp.name, "rb") as f:
|
||||
bot.send_document(call.message.chat.id, f)
|
||||
|
||||
|
||||
@bot.callback_query_handler(func=lambda call: call.data == 'fix')
|
||||
|
||||
@@ -9,14 +9,19 @@ import os
|
||||
BASE_URL = "http://www.rrys2020.com"
|
||||
LOGIN_URL = "http://www.rrys2020.com/user/login"
|
||||
GET_USER = "http://www.rrys2020.com/user/login/getCurUserTopInfo"
|
||||
# rss is unavailable as of 2021.01.10
|
||||
RSS_URL = "http://rss.rrys.tv/rss/feed/{id}"
|
||||
RESOURCE_SCORE = "http://www.rrys2020.com/resource/getScore" # post rid=38000
|
||||
SEARCH_URL = "http://www.rrys2020.com/search?keyword={kw}&type=resource"
|
||||
AJAX_LOGIN = "http://www.rrys2020.com/User/Login/ajaxLogin"
|
||||
SHARE_URL = "http://www.rrys2020.com/resource/ushare"
|
||||
SHARE_WEB = "http://got002.com/resource.html?code={code}"
|
||||
# http://got002.com/api/v1/static/resource/detail?code=9YxN91
|
||||
SHARE_API = "http://got002.com/api/v1/static/resource/detail?code={code}"
|
||||
|
||||
TOKEN = os.environ.get("TOKEN") or "TOKEN"
|
||||
USERNAME = os.environ.get("USERNAME") or "USERNAME"
|
||||
PASSWORD = os.environ.get("PASSWORD") or "password"
|
||||
PROXY = os.environ.get("PROXY")
|
||||
MAINTAINER = os.environ.get("MAINTAINER")
|
||||
REDIS = os.environ.get("REDIS") or "redis"
|
||||
|
||||
@@ -10,7 +10,7 @@ import requests
|
||||
import feedparser
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from config import SEARCH_URL, GET_USER, RSS_URL, BASE_URL, SHARE_WEB, SHARE_URL, RESOURCE_SCORE
|
||||
from config import SEARCH_URL, GET_USER, RSS_URL, BASE_URL, SHARE_WEB, SHARE_URL, RESOURCE_SCORE, SHARE_API
|
||||
from utils import load_cookies, cookie_file, login
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(filename)s [%(levelname)s]: %(message)s')
|
||||
@@ -32,15 +32,22 @@ def get_search_html(kw: str) -> str:
|
||||
return r.text
|
||||
|
||||
|
||||
def get_detail_page(url: str):
|
||||
def get_detail_page(url: str) -> dict:
|
||||
logging.info("loading detail page %s", url)
|
||||
share_link, api_res = analysis_share_page(url)
|
||||
cnname = api_res["data"]["info"]["cnname"]
|
||||
logging.info("Share page complete for %s", cnname)
|
||||
|
||||
logging.info("Getting rss...")
|
||||
rss_url = RSS_URL.format(id=url.split("/")[-1])
|
||||
rss_result = analyse_rss(rss_url)
|
||||
logging.info("RSS complete...")
|
||||
|
||||
logging.info("loading detail page %s", url)
|
||||
share_link = analysis_share_page(url)
|
||||
# get name from here...
|
||||
if not rss_result:
|
||||
rss_result = api_res
|
||||
|
||||
return {"rss": rss_result, "share": share_link}
|
||||
return {"all": rss_result, "share": share_link, "cnname": cnname}
|
||||
|
||||
|
||||
def analyse_search_html(html: str) -> dict:
|
||||
@@ -70,7 +77,7 @@ def analyse_rss(feed_url: str) -> dict:
|
||||
return result
|
||||
|
||||
|
||||
def analysis_share_page(detail_url: str) -> str:
|
||||
def analysis_share_page(detail_url: str) -> (str, dict):
|
||||
rid = detail_url.split('/')[-1]
|
||||
logging.info("rid is %s", rid)
|
||||
|
||||
@@ -79,7 +86,10 @@ def analysis_share_page(detail_url: str) -> str:
|
||||
logging.info("Share code is %s", share_code)
|
||||
share_url = SHARE_WEB.format(code=share_code)
|
||||
logging.info("Share url %s", share_url)
|
||||
return share_url
|
||||
|
||||
# get api response
|
||||
api_response = s.get(SHARE_API.format(code=share_code)).json()
|
||||
return share_url, api_response
|
||||
|
||||
|
||||
def get_score(rid: str) -> float:
|
||||
|
||||
@@ -4,4 +4,5 @@ beautifulsoup4
|
||||
lxml
|
||||
feedparser
|
||||
pysocks
|
||||
tgbot-ping
|
||||
tgbot-ping
|
||||
redis
|
||||
34
utils.py
34
utils.py
@@ -4,36 +4,38 @@
|
||||
|
||||
__author__ = 'Benny <benny.think@gmail.com>'
|
||||
|
||||
import dbm
|
||||
import os
|
||||
import sys
|
||||
import pickle
|
||||
import json
|
||||
import logging
|
||||
import requests
|
||||
import redis
|
||||
|
||||
from config import AJAX_LOGIN, USERNAME, PASSWORD
|
||||
from config import AJAX_LOGIN, USERNAME, PASSWORD, REDIS
|
||||
|
||||
r = redis.StrictRedis(host=REDIS, decode_responses=True)
|
||||
|
||||
db_path = os.path.join(os.path.dirname(__file__), 'data', 'yyets.dbm')
|
||||
db = dbm.open(db_path, 'c')
|
||||
cookie_file = os.path.join(os.path.dirname(__file__), 'data', 'cookies.dump')
|
||||
|
||||
|
||||
def batch_upsert(data: dict) -> None:
|
||||
for k in data:
|
||||
upsert(k, data[k])
|
||||
def save_to_cache(url: str, value: dict) -> None:
|
||||
data = json.dumps(value, ensure_ascii=False)
|
||||
r.set(url, data, ex=3600 * 12)
|
||||
|
||||
|
||||
def upsert(key: str, value: dict) -> None:
|
||||
db[key] = json.dumps(value, ensure_ascii=False)
|
||||
def get_from_cache(url: str) -> dict:
|
||||
logging.info("Reading data from cache %s", url)
|
||||
from html_request import get_detail_page
|
||||
|
||||
|
||||
def get(key: str) -> dict:
|
||||
return json.loads(db.get(key, '{}'))
|
||||
|
||||
|
||||
def delete(key: str) -> None:
|
||||
del db[key]
|
||||
data = r.get(url)
|
||||
if data:
|
||||
logging.info("cache hit")
|
||||
return json.loads(data)
|
||||
else:
|
||||
logging.info("cache miss")
|
||||
save_to_cache(url, get_detail_page(url))
|
||||
return get_from_cache(url)
|
||||
|
||||
|
||||
def save_dump(err):
|
||||
|
||||
Reference in New Issue
Block a user