提交 36fbdd20 编写于 作者: H hjdhnx

大版本升级

上级 2674875d
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File : R.py
# Author: DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------
# Date : 2022/9/6
from flask import jsonify
class copy_utils:
@staticmethod
def obj_to_dic(obj):
'''
将传入的data对象转成字典
'''
result = {}
for temp in obj.__dict__:
if temp.startswith('_') or temp == 'metadata':
continue
result[temp] = getattr(obj, temp)
return result
@staticmethod
def obj_to_list(list_obj):
'''
将传入的data对象转成List,list中的元素是字典
'''
result = []
for obj in list_obj:
result.append(copy_utils.obj_to_dic(obj))
return result
class R(object):
@classmethod
def ok(self,msg='操作成功',data=None):
if not data:
data = []
result = {"code": 200, "msg": msg, "data": data}
return jsonify(result)
@classmethod
def error(self,msg="系统异常",code=404):
result = {"code": code, "msg": msg}
return jsonify(result)
@classmethod
def success(self,msg='操作成功', data=None):
return self.ok(msg,data)
@classmethod
def failed(self,msg="系统异常", code=404):
return self.error(msg,code)
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File : __init__.py
# Author: DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------
# Date : 2022/9/6
from . import database
from . import config
from . import R
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File : config.py
# Author: DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------
# Date : 2022/9/6
DIALECT = 'mysql'
DRIVER = 'pymysql'
USERNAME = 'gp'
PASSWORD = '123456'
HOST = '127.0.0.1'
PORT = '3306'
DATABASE = 'pira'
# DB_URI = '{}+{}://{}:{}@{}:{}/{}?charset=utf8'.format(DIALECT, DRIVER, USERNAME, PASSWORD, HOST, PORT, DATABASE)
DB_URI = 'sqlite:///models/rules.db?charset=utf8&check_same_thread=False'
SQLALCHEMY_DATABASE_URI = DB_URI
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = False # 打印sql语句
JSON_AS_ASCII = False # jsonify返回的中文正常显示
PLAY_URL = 'http://cms.nokia.press' # 匹配远程解析服务器链接 远程接口主页地址,后面不能有/
PLAY_URL = PLAY_URL.rstrip('/')
HTTP_HOST = '0.0.0.0'
HTTP_PORT = '5705'
PLAY_DISABLE = False # 全局禁用播放解析
LAZYPARSE_MODE = 1 # 播放解析模式(0 本地 1 局域网 2远程 仅在全局禁用为False的时候生效)
WALL_PAPER_ENABLE = True # 启用自定义壁纸
WALL_PAPER = "https://picsum.photos/1280/720/?blur=10" # 自定义壁纸,可注释
SUP_PORT = 9001 # supervisord 服务端口
RETRY_CNT = 3 # 验证码重试次数
# OCR_API = 'http://192.168.3.224:9000/api/ocr_img' # 验证码识别接口,传参数data
OCR_API = 'http://dm.mudery.com:10000' # 验证码识别接口,传参数data
UNAME = 'admin' # 管理员账号
PWD = 'drpy' # 管理员密码
MAX_CONTENT_LENGTH = 1 * 1024 * 1024/100 # 100 kB
LIVE_MODE = 0 # 0 本地 1外网
LIVE_URL = 'https://gitcode.net/qq_26898231/TVBox/-/raw/main/live/zb.txt' # 初始化外网直播地址(后续在管理界面改)
CATE_EXCLUDE = '首页|留言|APP|下载|资讯|新闻|动态' # 动态分类过滤
# {% if config.WALL_PAPER %}"wallpaper":"{{ config.WALL_PAPER }}",{% endif %}
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File : databse.py
# Author: DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------
# Date : 2022/9/6
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File : __init__.py
# Author: DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------
# Date : 2022/9/6
from . import home
from . import admin
from . import service
from . import vod
from . import cms
from . import cls
from . import classes
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File : admin.py
# Author: DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------
# Date : 2022/9/6
import os
from flask import Blueprint,request,render_template,jsonify,make_response
from controllers.service import storage_service
from base.R import R
from utils.web import verfy_token
from utils.update import getLocalVer,getOnlineVer,download_new_version,download_lives
from utils import parser
from utils.web import getParmas
from js.rules import getRules
from utils.parser import runJScode
from werkzeug.utils import secure_filename
import js2py
from utils.web import md5
admin = Blueprint("admin", __name__)
# @admin.route("/",methods=['get'])
# def index():
# return R.ok(msg='欢迎进入首页',data=None)
# @admin.route("/info",methods=['get'])
# def info_all():
# data = storage_service.query_all()
# return R.ok(data=data)
@admin.route('/')
def admin_index(): # 管理员界面
lsg = storage_service()
live_url = lsg.getItem('LIVE_URL')
print(f'live_url:',live_url)
if not verfy_token():
return render_template('login.html')
live_url = lsg.getItem('LIVE_URL')
return render_template('admin.html', rules=getRules('js'), ver=getLocalVer(), live_url=live_url)
@admin.route("/view/<name>",methods=['GET'])
def admin_view_rule(name):
if not name or not name.split('.')[-1] in ['js','txt','py','json']:
return R.error(f'非法猥亵,未指定文件名。必须包含js|txt|json|py')
try:
return parser.toJs(name,'js')
except Exception as e:
return R.error(f'非法猥亵\n{e}')
@admin.route('/clear/<name>')
def admin_clear_rule(name):
if not name or not name.split('.')[-1] in ['js','txt','py','json']:
return R.error(f'非法猥亵,未指定文件名。必须包含js|txt|json|py')
if not verfy_token():
return render_template('login.html')
file_path = os.path.abspath(f'js/{name}')
print(file_path)
if not os.path.exists(file_path):
return R.error('服务端没有此文件!'+file_path)
os.remove(file_path)
return R.ok('成功删除文件:'+file_path)
@admin.route('/get_ver')
def admin_get_ver():
if not verfy_token():
# return render_template('login.html')
return R.error('请登录后再试')
return jsonify({'local_ver':getLocalVer(),'online_ver':getOnlineVer()})
@admin.route('/update_ver')
def admin_update_ver():
if not verfy_token():
return R.failed('请登录后再试')
msg = download_new_version()
return R.success(msg)
@admin.route('/update_lives')
def admin_update_lives():
url = getParmas('url')
if not url:
return R.failed('未提供被同步的直播源远程地址!')
if not verfy_token():
return R.failed('请登录后再试')
live_url = url
success = download_lives(live_url)
if success:
return R.success(f'直播源{live_url}同步成功')
else:
return R.failed(f'直播源{live_url}同步失败')
@admin.route('/write_live_url')
def admin_write_live_url():
url = getParmas('url')
if not url:
return R.failed('未提供修改后的直播源地址!')
if not verfy_token():
return R.failed('请登录后再试')
lsg = storage_service()
id = lsg.setItem('LIVE_URL',url)
msg = f'已修改的配置记录id为:{id}'
return R.success(msg)
@admin.route('/upload', methods=['GET', 'POST'])
def upload_file():
if not verfy_token():
return render_template('login.html')
if request.method == 'POST':
try:
file = request.files['file']
filename = secure_filename(file.filename)
print(f'推荐安全文件命名:{filename}')
savePath = f'js/{file.filename}'
if os.path.exists(savePath):
return R.failed(f'上传失败,文件已存在,请先查看删除再试')
with open('js/模板.js', encoding='utf-8') as f2:
before = f2.read()
upcode = file.stream.read().decode('utf-8')
check_to_run = before + upcode
# print(check_to_run)
try:
# js2py.eval_js(check_to_run)
loader, _ = runJScode(check_to_run)
rule = loader.eval('rule')
if not rule:
return R.failed('文件上传失败,检测到上传的文件不是drpy框架支持的源代码')
except:
return R.failed('文件上传失败,检测到上传的文件不是drpy框架支持的源代码')
print(savePath)
file.seek(0) # 读取后变成空文件,重新赋能
file.save(savePath)
return R.success('文件上传成功')
except Exception as e:
return R.failed(f'文件上传失败!{e}')
else:
# return render_template('upload.html')
return R.failed('文件上传失败')
@admin.route('/login',methods=['GET','POST'])
def login_api():
username = getParmas('username')
password = getParmas('password')
autologin = getParmas('autologin')
if not all([username,password]):
return R.failed('账号密码字段必填')
token = md5(f'{username};{password}')
check = verfy_token(token=token)
if check:
# response = make_response(redirect('/admin'))
response = make_response(R.success('登录成功'))
response.set_cookie('token', token)
return response
else:
return R.failed('登录失败,用户名或密码错误')
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File : classes.py
# Author: DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------
# Date : 2022/9/6
from base.database import db
from utils.log import logger
from models.ruleclass import RuleClass
def getClasses():
if not db:
msg = '未提供数据库连接'
logger.info(msg)
return []
res = db.session.query(RuleClass).all()
return [rc.name for rc in res]
def getClassInfo(cls):
if not db:
msg = f'未提供数据库连接,获取{cls}详情失败'
logger.info(msg)
return None
logger.info(f'开始查询{cls}的分类详情')
res = db.session.query(RuleClass).filter(RuleClass.name == cls).first()
if res:
logger.info(str(res))
return str(res)
else:
return f'数据库不存在{cls}的分类缓存'
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File : CLS.py
# Author: DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------
# Date : 2022/9/6
from flask import Blueprint
from controllers.classes import getClasses,getClassInfo
from base.R import R
from utils.log import logger
from base.database import db
from models.ruleclass import RuleClass
cls = Blueprint("cls", __name__)
@cls.route('/get/<cls>')
def getClassInfoApi(cls):
info = getClassInfo(cls)
return R.ok(info)
@cls.route('/clear/<cls>')
def clearClassApi(cls):
logger.info(f'开始查询{cls}的分类详情')
res = db.session.query(RuleClass).filter(RuleClass.name == cls)
if res:
res.delete()
db.session.commit()
return R.success(f'已清除{cls}的分类缓存')
else:
return R.failed(f'数据库不存在{cls}的分类缓存')
\ No newline at end of file
此差异已折叠。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File : index.py
# Author: DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------
# Date : 2022/9/6
import json
import os
from flask import Blueprint,abort,render_template,url_for,redirect,make_response
from controllers.service import storage_service
from controllers.classes import getClasses,getClassInfo
from utils.web import getParmas
from utils.files import getPics
from js.rules import getRules
from base.R import R
from utils.system import cfg,getHost,is_linux
from utils import parser
from utils.log import logger
from utils.files import getAlist,get_live_url
from js.rules import getJxs
import random
home = Blueprint("home", __name__,static_folder='/static')
@home.route('/')
def forbidden(): # put application's code here
abort(403)
@home.route('/favicon.ico') # 设置icon
def favicon():
# return home.send_static_file('img/favicon.svg')
return redirect('/static/img/favicon.svg')
# 对于当前文件所在路径,比如这里是static下的favicon.ico
# return send_from_directory(os.path.join(app.root_path, 'static'), 'img/favicon.svg', mimetype='image/vnd.microsoft.icon')
@home.route('/index')
def index():
sup_port = cfg.get('SUP_PORT', False)
manager0 = ':'.join(getHost(0).split(':')[0:2])
manager1 = ':'.join(getHost(1).split(':')[0:2])
manager2 = ':'.join(getHost(2).split(':')[0:2]).replace('https','http')
if sup_port:
manager0 += f':{sup_port}'
manager1 += f':{sup_port}'
manager2 += f':{sup_port}'
return render_template('index.html',getHost=getHost,manager0=manager0,manager1=manager1,manager2=manager2,is_linux=is_linux())
@home.route('/rules/clear')
def rules_to_clear():
return render_template('rules_to_clear.html',rules=getRules(),classes=getClasses())
@home.route('/rules/view')
def rules_to_view():
return render_template('rules_to_view.html',rules=getRules(),classes=getClasses())
@home.route('/pics')
def random_pics():
id = getParmas('id')
# print(f'id:{id}')
pics = getPics()
print(pics)
if len(pics) > 0:
if id and f'images/{id}.jpg' in pics:
pic = f'images/{id}.jpg'
else:
pic = random.choice(pics)
file = open(pic, "rb").read()
response = make_response(file)
response.headers['Content-Type'] = 'image/jpeg'
return response
else:
return redirect(cfg.WALL_PAPER)
@home.route('/clear')
def clear_rule():
rule = getParmas('rule')
if not rule:
return R.failed('规则字段必填')
cache_path = os.path.abspath(f'cache/{rule}.js')
if not os.path.exists(cache_path):
return R.failed('服务端没有此规则的缓存文件!'+cache_path)
os.remove(cache_path)
return R.success('成功删除文件:'+cache_path)
@home.route("/plugin/<name>",methods=['GET'])
def plugin(name):
# name=道长影视模板.js
if not name or not name.split('.')[-1] in ['js','txt','py','json']:
return R.failed(f'非法猥亵,未指定文件名。必须包含js|txt|json|py')
try:
return parser.toJs(name)
except Exception as e:
return R.failed(f'非法猥亵\n{e}')
@home.route('/lives')
def get_lives():
live_path = 'js/直播.txt'
if not os.path.exists(live_path):
with open(live_path,mode='w+',encoding='utf-8') as f:
f.write('')
with open(live_path,encoding='utf-8') as f:
live_text = f.read()
response = make_response(live_text)
response.headers['Content-Type'] = 'text/plain; charset=utf-8'
return response
@home.route('/liveslib')
def get_liveslib():
live_path = 'js/custom_spider.jar'
if not os.path.exists(live_path):
with open(live_path,mode='w+',encoding='utf-8') as f:
f.write('')
with open(live_path,mode='rb') as f:
live_text = f.read()
response = make_response(live_text)
filename = 'custom_spider.jar'
response.headers['Content-Type'] = 'application/octet-stream'
response.headers['Content-Disposition'] = f'attachment;filename="{filename}"'
return response
@home.route('/config/<int:mode>')
def config_render(mode):
# print(dict(app.config))
if mode == 1:
jyw_ip = getHost(mode)
logger.info(jyw_ip)
new_conf = cfg
host = getHost(mode)
jxs = getJxs()
alists = getAlist()
alists_str = json.dumps(alists, ensure_ascii=False)
live_url = get_live_url(new_conf,mode)
# html = render_template('config.txt',rules=getRules('js'),host=host,mode=mode,jxs=jxs,base64Encode=base64Encode,config=new_conf)
html = render_template('config.txt',rules=getRules('js'),host=host,mode=mode,jxs=jxs,alists=alists,alists_str=alists_str,live_url=live_url,config=new_conf)
response = make_response(html)
response.headers['Content-Type'] = 'application/json; charset=utf-8'
return response
@home.route('/configs')
def config_gen():
# 生成文件
os.makedirs('txt',exist_ok=True)
new_conf = cfg
jxs = getJxs()
alists = getAlist()
alists_str = json.dumps(alists,ensure_ascii=False)
set_local = render_template('config.txt',rules=getRules('js'),alists=alists,alists_str=alists_str,live_url=get_live_url(new_conf,0),mode=0,host=getHost(0),jxs=jxs)
print(set_local)
set_area = render_template('config.txt',rules=getRules('js'),alists=alists,alists_str=alists_str,live_url=get_live_url(new_conf,1),mode=1,host=getHost(1),jxs=jxs)
set_online = render_template('config.txt',rules=getRules('js'),alists=alists,alists_str=alists_str,live_url=get_live_url(new_conf,2),mode=1,host=getHost(2),jxs=jxs)
with open('txt/pycms0.json','w+',encoding='utf-8') as f:
set_dict = json.loads(set_local)
f.write(json.dumps(set_dict,ensure_ascii=False,indent=4))
with open('txt/pycms1.json','w+',encoding='utf-8') as f:
set_dict = json.loads(set_area)
f.write(json.dumps(set_dict,ensure_ascii=False,indent=4))
with open('txt/pycms2.json','w+',encoding='utf-8') as f:
set_dict = json.loads(set_online)
f.write(json.dumps(set_dict,ensure_ascii=False,indent=4))
files = [os.path.abspath(rf'txt\pycms{i}.json') for i in range(3)]
# print(files)
return R.success('猫配置生成完毕,文件位置在:\n'+'\n'.join(files))
@home.route("/info",methods=['get'])
def info_all():
data = storage_service.query_all()
return R.ok(data=data)
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File : service.py.py
# Author: DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------
# Date : 2022/9/6
from base.R import copy_utils
from models.storage import Storage
from utils.system import cfg
class storage_service(object):
@staticmethod
def query_all():
# 查询所有
res = Storage.query.all()
return copy_utils.obj_to_list(res)
def __init__(self):
if not self.getItem('LIVE_URL'):
print('开始初始化lsg')
self.setItem('LIVE_URL', cfg.get('LIVE_URL'))
@classmethod
def getItem(self, key, value=''):
return Storage.getItem(key,value)
@classmethod
def setItem(self,key, value):
return Storage.setItem(key, value)
@classmethod
def clearItem(self,key):
return Storage.clearItem(key)
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File : vod.py
# Author: DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------
# Date : 2022/9/6
from flask import Blueprint,request,render_template,jsonify,make_response,redirect
from time import time
from utils.web import getParmas,get_interval,cfg
from js.rules import getRuleLists,getJxs
from base.R import R
from utils.log import logger
from utils import parser
from controllers.cms import CMS
from base.database import db
from models.ruleclass import RuleClass
from models.playparse import PlayParse
vod = Blueprint("vod", __name__)
@vod.route('/vod')
def vod_home():
t0 = time()
rule = getParmas('rule')
ext = getParmas('ext')
if not ext.startswith('http') and not rule:
return R.failed('规则字段必填')
rule_list = getRuleLists()
if not ext.startswith('http') and not rule in rule_list:
msg = f'服务端本地仅支持以下规则:{",".join(rule_list)}'
return R.failed(msg)
# logger.info(f'检验耗时:{get_interval(t0)}毫秒')
t1 = time()
js_path = f'js/{rule}.js' if not ext.startswith('http') else ext
with open('js/模板.js', encoding='utf-8') as f:
before = f.read()
# logger.info(f'js读取耗时:{get_interval(t1)}毫秒')
logger.info(f'参数检验js读取共计耗时:{get_interval(t0)}毫秒')
t2 = time()
ctx, js_code = parser.runJs(js_path,before=before)
if not js_code:
return R.failed('爬虫规则加载失败')
# rule = ctx.eval('rule')
# print(type(ctx.rule.lazy()),ctx.rule.lazy().toString())
ruleDict = ctx.rule.to_dict()
ruleDict['id'] = rule # 把路由请求的id装到字典里,后面播放嗅探才能用
# print(ruleDict)
# print(rule)
# print(type(rule))
# print(ruleDict)
logger.info(f'js装载耗时:{get_interval(t2)}毫秒')
# print(ruleDict)
# print(rule)
cms = CMS(ruleDict,db,RuleClass,PlayParse,cfg)
wd = getParmas('wd')
ac = getParmas('ac')
quick = getParmas('quick')
play = getParmas('play') # 类型为4的时候点击播放会带上来
flag = getParmas('flag') # 类型为4的时候点击播放会带上来
filter = getParmas('filter')
t = getParmas('t')
pg = getParmas('pg','1')
pg = int(pg)
ids = getParmas('ids')
q = getParmas('q')
play_url = getParmas('play_url')
if play:
jxs = getJxs()
play_url = play.split('play_url=')[1]
play_url = cms.playContent(play_url, jxs,flag)
if isinstance(play_url, str):
# return redirect(play_url)
# return jsonify({'parse': 0, 'playUrl': play_url, 'jx': 0, 'url': play_url})
# return jsonify({'parse': 0, 'playUrl': play_url, 'jx': 0, 'url': ''})
return jsonify({'parse': 0, 'playUrl': '', 'jx': 0, 'url': play_url})
elif isinstance(play_url, dict):
return jsonify(play_url)
else:
return play_url
if play_url: # 播放
jxs = getJxs()
play_url = cms.playContent(play_url,jxs)
if isinstance(play_url,str):
return redirect(play_url)
elif isinstance(play_url,dict):
return jsonify(play_url)
else:
return play_url
if ac and t: # 一级
data = cms.categoryContent(t,pg)
# print(data)
return jsonify(data)
if ac and ids: # 二级
id_list = ids.split(',')
# print('app:377',len(id_list))
# print(id_list)
data = cms.detailContent(pg,id_list)
# print(data)
return jsonify(data)
if wd: # 搜索
data = cms.searchContent(wd)
# print(data)
return jsonify(data)
# return jsonify({'rule':rule,'js_code':js_code})
home_data = cms.homeContent(pg)
return jsonify(home_data)
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册