From cb031512321d3f2feb634b35865aead7ea4fb32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=9A=E9=A3=8E=E6=8B=82=E6=9F=B3=E9=A2=9C?= <434857005@qq.com> Date: Fri, 12 May 2023 12:02:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=90=8E=E7=AB=AF=E4=BB=A3?= =?UTF-8?q?=E7=90=86,=E8=A7=A3=E5=86=B3=E9=83=A8=E5=88=86=E7=BD=91?= =?UTF-8?q?=E9=A1=B5=E7=9A=84=E6=92=AD=E6=94=BE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 25 ++++++--- base/config.py | 1 + controllers/web.py | 58 +++++++++++++++++++-- js/version.txt | 2 +- templates/admin.html | 2 +- templates/cms/mxpro/detailContent.html | 72 +++++++++++++++++++------- templates/cms/mxpro/js/commonUtil.js | 39 ++++++++++++++ 7 files changed, 169 insertions(+), 30 deletions(-) create mode 100644 templates/cms/mxpro/js/commonUtil.js diff --git a/app.py b/app.py index b3992b7..951576c 100644 --- a/app.py +++ b/app.py @@ -9,11 +9,12 @@ from flask_migrate import Migrate from base import config from base.database import db from utils.log import logger -from utils.system import get_wlan_info,getHost +from utils.system import get_wlan_info, getHost from controllers import * from js.rules import getRuleLists import sys + def create_flask_app(): app = Flask(__name__, static_folder='static', static_url_path='/static') app.config.from_object(config) # 单独的配置文件里写了,这里就不用弄json中文显示了 @@ -31,22 +32,28 @@ def create_flask_app(): # logger.info(f"自定义播放解析地址:{lsg.getItem('PLAY_URL')}") logger.info(f'当前操作系统{sys.platform}') rule_list = getRuleLists() - wlan_info,_ = get_wlan_info() + wlan_info, _ = get_wlan_info() logger.info(rule_list) - logger.info(f'局域网: {getHost(1, app.config.get("HTTP_PORT"))}/index\n本地: {getHost(0, app.config.get("HTTP_PORT"))}/index\nwlan_info:{wlan_info}') + logger.info( + f'局域网: {getHost(1, app.config.get("HTTP_PORT"))}/index\n本地: {getHost(0, app.config.get("HTTP_PORT"))}/index\nwlan_info:{wlan_info}') db.init_app(app) db.app = app db.create_all(app=app) return app + app = create_flask_app() migrate = Migrate(app, db) now_python_ver = ".".join([str(i) for i in sys.version_info[:3]]) -if sys.version_info < (3,9): +if sys.version_info < (3, 9): from gevent.pywsgi import WSGIServer + # from gevent import monkey - # monkey.patch_socket() # 开启socket异步 + # monkey.patch_all() # 多线程,只能放在最开头,import其它包之前 + + from gevent import monkey + monkey.patch_socket() # 开启socket异步 print(f'当前python版本{now_python_ver}为3.9.0及以下,支持gevent') else: print(f'当前python版本{now_python_ver}为3.9.0及以上,不支持gevent') @@ -54,10 +61,16 @@ else: if __name__ == "__main__": http_port = int(app.config.get('HTTP_PORT', 5705)) http_host = app.config.get('HTTP_HOST', '0.0.0.0') + threaded = app.config.get('Thread') + if threaded is None: + threaded = True + # https://www.zhihu.com/question/64096559 + print('threaded:',threaded) + # if sys.version_info < (3, 9) and not sys.platform.startswith('win'): if sys.version_info < (3, 9): # server = WSGIServer(('0.0.0.0', 5705), app, handler_class=WebSocketHandler,log=app.logger) # server = WSGIServer(('0.0.0.0', 5705), app, handler_class=WebSocketHandler,log=None) server = WSGIServer((http_host, http_port), app, log=logger) server.serve_forever() else: - app.run(debug=False, host=http_host, port=http_port) \ No newline at end of file + app.run(debug=False, host=http_host, port=http_port, threaded=threaded) \ No newline at end of file diff --git a/base/config.py b/base/config.py index 8af858c..bc30990 100644 --- a/base/config.py +++ b/base/config.py @@ -56,3 +56,4 @@ JS_PROXY = 'http://localhost:5705/admin/view/=>https://ghproxy.net/https://raw.g ALI_TOKEN = '' # 适用于初始配置的阿里云token ENV = '{"bili_cookie":""}' # 自定义环境变量 UPDATE_PROXY = 'https://ghproxy.net/' # 检测升级代理 +Thread = True # 开启windows多线程调用 diff --git a/controllers/web.py b/controllers/web.py index e636c93..a75cc56 100644 --- a/controllers/web.py +++ b/controllers/web.py @@ -6,10 +6,11 @@ import functools import json import os - +from urllib.parse import urljoin +import requests from flask import Blueprint, abort, request, render_template, send_from_directory, render_template_string, jsonify, \ make_response, redirect, \ - current_app + current_app, url_for from time import time from utils.web import getParmas, get_interval from utils.cfg import cfg @@ -38,12 +39,14 @@ def custom_static_cms(filename): # print(filename) return send_from_directory('templates/cms', filename) + @web.route('/player/') def custom_static_player(filename): # 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}} # print(filename) return send_from_directory('templates/player', filename) + @web.route('//') def web_index(web_name, theme): ctx = {'web_name': web_name, 'key': '关键词', 'description': '描述'} @@ -67,7 +70,7 @@ def web_index(web_name, theme): ctx['tid'] = tid ctx['tname'] = tname ctx['url'] = url - print('tid:',tid) + print('tid:', tid) file_path = os.path.abspath(f'js/{web_name}.js') print(file_path) @@ -86,4 +89,51 @@ def web_index(web_name, theme): else: return render_template(f'cms/{theme}/homeContent.html', ctx=ctx) except Exception as e: - return render_template('404.html', ctx=ctx, error=f'发生错误的原因可能是下面路径未找到:{e}') \ No newline at end of file + return render_template('404.html', ctx=ctx, error=f'发生错误的原因可能是下面路径未找到:{e}') + + +@web.route('/302redirect') +def get302UrlResponse(): + url = getParmas('url') + if not url: + abort(403) + params = {} + if not url.startswith('http'): + url = urljoin(request.root_url, url) + # url = urljoin('http://localhost:5705/',url) + print(url) + items = url.split('vod?')[1].split('&') + for item in items: + params[item.split('=')[0]] = item.split('=')[1] + print(params) + # abort(403) + + timeout = getParmas('timeout') or 5000 + rurl = url + try: + timeout = int(timeout) + headers = { + # 'referer': url, + 'user-agent': 'Mozilla/5.0' + } + print('开始调用接口:', url) + r = requests.get(url, headers=headers, timeout=timeout, verify=False) + rurl = r.url + + # rurl = url_for('vod.vod_home', **params) + # print(rurl) + print('结束调用接口:', rurl) + return jsonify({ + 'url': rurl, + 'redirect': rurl != url, + 'data': r.text, + }) + + except Exception as e: + logger.info(f'发生了错误:{e}') + return jsonify({ + 'url': rurl, + 'redirect': rurl != url, + 'data': None, + 'error': f'{e}', + }) diff --git a/js/version.txt b/js/version.txt index c4f14f7..daec681 100644 --- a/js/version.txt +++ b/js/version.txt @@ -1 +1 @@ -3.9.41beta26 \ No newline at end of file +3.9.41beta27 \ No newline at end of file diff --git a/templates/admin.html b/templates/admin.html index fb54922..a7f1513 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -277,7 +277,7 @@ {% for rule in rules.list %}
- + diff --git a/templates/cms/mxpro/detailContent.html b/templates/cms/mxpro/detailContent.html index ee5c008..907b899 100644 --- a/templates/cms/mxpro/detailContent.html +++ b/templates/cms/mxpro/detailContent.html @@ -22,6 +22,7 @@ + @@ -243,39 +244,72 @@ const app = createApp({ const photoVisible = ref(false); const iframeRef = ref(null); var sniffer; - + const {isVideo,getRealUrl} = commonUtil; + // get302UrlResponse('/vod?pwd=dzyyds&rule=007影视&ext=&play_url=https%3A//www.007ts.me/play/69636-3-1.html',(resp)=>{ + // console.log('重定向到:',resp); + // }); + // getRealUrl('/vod?pwd=dzyyds&rule=007影视&ext=&play_url=https%3A//www.007ts.me/play/69636-3-1.html',(res)=>{ + // console.log('重定向到:',res); + // }); const methods = { async lazyPlay(url){ iframeShow.value = true; console.log('准备处理播放地址:'+url); clearInterval(sniffer); try { - if(/\.(m3u8|mp4)/.test(url)){ + if(isVideo(url)){ console.log('直接播放'); methods.setPlayUrl(url); return } - const res = await axios.get(url,{maxRedirects: 0}); - const { status, headers: { Location } } = res; - // console.log(status); - console.log(res.request.responseURL); - if (status === 302) { - console.log(Location); + const res =await getRealUrl(url,(resp)=>{ + // console.log('代理数据:',resp.data); + return resp.data + }); + // console.log(res); + let res_data = res.data; + try { + res_data = JSON.parse(res_data); + }catch (e) { + } - console.log(res.data); - if(typeof(res.data)==='string' && /#EXTM3U/.test(res.data)){ + // console.log(res_data); + // console.log(res.url); + // console.log(res.redirect); + if(res.redirect){ // 重定向的直接设置播放器的值 + if(isVideo(res.url)){ // 判断重定向的为直链 + methods.setPlayUrl(res.url); + }else{ + console.log('重定向待嗅探页面,但是由于跨域问题,只好内嵌播放页播放'); + iframeSrc.value = res.url; + } + return + // throw new Error('重定向网页直接播放,尝试嗅探(存在跨域无法嗅探问题,暂时考虑直接内嵌人家的播放页)'); + } + + // const res = await axios.get(url,{maxRedirects: 0}); + // const { status, headers: { Location } } = res; + // // console.log(status); + // console.log(res.request.responseURL); + // if (status === 302) { + // console.log(Location); + // } + // console.log(res.data); + + console.log(res_data); + if(typeof(res_data)==='string'){ iframeRef.value.contentWindow.location.reload(); iframeSrc.value = url; - throw new Error('重定向类文件无法直接播放,尝试嗅探'); - } else if(!res.data.parse&&res.data.url){ - methods.setPlayUrl(res.data.url); - }else if(/url=/.test(res.data.url)){ - iframeSrc.value = res.data.url; - } else if((res.data.parse||res.data.jx)&&res.data.url){ + throw new Error('返回的数据是文本无法直接播放,尝试嗅探'); + } else if(!res_data.parse&&res_data.url){ + methods.setPlayUrl(res_data.url); + }else if(/url=/.test(res_data.url)){ + iframeSrc.value = res_data.url; + } else if((res_data.parse||res_data.jx)&&res_data.url){ console.log(ctx.value); - iframeSrc.value = res.data.url; + iframeSrc.value = res_data.url; if(confirm('该视频来自其它正版地址,drpy网页暂未实现解析功能,是否跳到正版站通过油猴插件等手段播放?')){ - open(res.data.url); + open(res_data.url); } } }catch (e) { @@ -365,6 +399,7 @@ const app = createApp({ photoVisible:photoVisible, iframeRef:iframeRef, sniffer:sniffer, + isVideo,getRealUrl } }, }); @@ -392,6 +427,7 @@ eruda.init(); + diff --git a/templates/cms/mxpro/js/commonUtil.js b/templates/cms/mxpro/js/commonUtil.js new file mode 100644 index 0000000..53a42bc --- /dev/null +++ b/templates/cms/mxpro/js/commonUtil.js @@ -0,0 +1,39 @@ +var commonUtil = { + isVideo(playUrl){ + let res_url = playUrl.split('?')[0]; + if(playUrl.endsWith('.m3u8')||res_url.endsWith('.m3u8')){ + return true + }else if(playUrl.endsWith('.mp4')||res_url.endsWith('.mp4')){ + return true + }else if(/\.(m4a|mp3|flv|aac)$/.test(playUrl)||/\.(m4a|mp3|flv|aac)$/.test(res_url)){ + return true + } + return false + }, + getLocationFromRedirect( + originUrl, + method = "GET" + ){ + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.open(method, originUrl, true); + xhr.onload = function () { + resolve(xhr.responseURL); + }; + xhr.onerror = reject; + xhr.send(null); + }) + }, + get302UrlResponse(url, callback) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.onload = function () { + callback(xhr.responseURL); + } + xhr.send(null); + }, + async getRealUrl(url,callback){ + const res = await axios.get(`web/302redirect?url=${encodeURIComponent(url)}`); + return callback(res); + } +}; \ No newline at end of file