增加PROXY_SUPPLEMENT变量

1、增加proxychains4模块,用于解决pip在socks5代理时,pip无法使用全局代理的问题
2、增加`PROXY_SUPPLEMENT`变量,可以手动控制,实现使用镜像站进行更新时,但缺少pip镜像站或者GitHub镜像站时,可以使用全局代理补全缺失的代理
This commit is contained in:
Aqr-K
2024-08-03 18:29:06 +08:00
parent 7adae64955
commit c69d317054
6 changed files with 275 additions and 17 deletions

View File

@@ -34,6 +34,7 @@ RUN apt-get update -y \
rsync \
ffmpeg \
nano \
proxychains4 \
&& \
if [ "$(uname -m)" = "x86_64" ]; \
then ln -s /usr/lib/x86_64-linux-musl/libc.so /lib/libc.musl-x86_64.so.1; \

View File

@@ -1,4 +1,6 @@
import secrets
from urllib.parse import urlparse
import sys
import threading
from pathlib import Path
@@ -148,6 +150,8 @@ class Settings(BaseSettings):
GITHUB_PROXY: Optional[str] = ''
# pip镜像站点格式https://pypi.tuna.tsinghua.edu.cn/simple
PIP_PROXY: Optional[str] = ''
# 代理补全开关,支持 True、False, 在没有配置镜像站的时候True 使用 PROXY_HOST 补全镜像站缺失False 在没有配置镜像站的时候,不使用全局补全
PROXY_SUPPLEMENT: bool = True
# 大内存模式
BIG_MEMORY_MODE: bool = False
@@ -226,6 +230,58 @@ class Settings(BaseSettings):
}
return None
@property
def PROXY_URLPARSE(self, url: str = PROXY_HOST):
"""
解析地址组成 - 允许其他地址调用
"""
if url:
# 解析 URL
parsed_url = urlparse(url)
# 协议
protocol = parsed_url.scheme or ""
# 用户名
username = parsed_url.username or ""
# 密码
password = parsed_url.password or ""
# 主机
host = parsed_url.hostname or ""
# 端口:
port = parsed_url.port or ""
# 路径
path = parsed_url.path or ""
# 用户名:密码@主机:端口
netloc = parsed_url.netloc or ""
# 查询参数: ?key=value
query = parsed_url.query or ""
# 使用;分割的参数
params = parsed_url.params or ""
# 片段: #fragment
fragment = parsed_url.fragment or ""
if not port:
if protocol == "https":
port = 443
elif protocol == "http":
port = 80
elif protocol in {"socks5", "socks5h", "socks4", "socks4a"}:
port = 1080
# 返回解析结果
return {
"protocol": protocol,
"username": username,
"password": password,
"host": host,
"port": port,
"path": path,
"netloc": netloc,
"query": query,
"params": params,
"fragment": fragment
}
return None
@property
def PROXY_SERVER(self):
if self.PROXY_HOST:

View File

@@ -222,8 +222,52 @@ class PluginHelper(metaclass=Singleton):
# 插件目录下如有requirements.txt则安装依赖
requirements_file = plugin_dir / "requirements.txt"
if requirements_file.exists():
PIP_PROXY = f" -i {settings.PIP_PROXY} " if settings.PIP_PROXY else ""
SystemUtils.execute(f"pip install -r {requirements_file} {PIP_PROXY} > /dev/null 2>&1")
# 初始化
protocol = host = port = username = password = PROXY_CHAINS = PIP_PROXY = ""
# 返回json格式解析结果
parsed_url = settings.PROXY_URLPARSE()
if parsed_url:
protocol = parsed_url.get("scheme", "").lower()
username = parsed_url.get("username", "")
password = parsed_url.get("password", "")
host = parsed_url.get("host", "").lower()
port = parsed_url.get("port", "")
# 全局优先,镜像站不存在时,使用全局代理
if settings.PROXY_SUPPLEMENT:
# 检查settings.PROXY_HOST的协议类型http或https
if protocol in {"http", "https"}:
if settings.PIP_PROXY:
PIP_PROXY = f" -i {settings.PIP_PROXY} " if settings.PIP_PROXY else ""
else:
# 有主机名与端口号的时候
if host and port:
PIP_PROXY = f" --proxy={settings.PROXY_HOST} " if settings.PROXY_HOST else ""
# Todo:目前proxychains4的临时调用命令不支持socks5h和socks4a需要生成临时配置文件才能解决后面考虑支持一下
elif protocol in {"socks4", "socks4a", "socks5", "socks5h"}:
# 没有主机名,端口号
if not host or not port:
PIP_PROXY = f" -i {settings.PIP_PROXY} " if settings.PIP_PROXY else ""
# 将拓展的socks协议转换为proxychains4支持的socks4和socks5
else:
if protocol in {"socks5", "socks5h"}:
protocol = "socks5"
elif protocol in {"socks4", "socks4a"}:
protocol = "socks4"
# 生成配置
PROXY_CHAINS = f"proxychains4 -f <( echo -e '[ProxyList]\n{protocol} {host} {port} {username} {password}')"
# 不支持的协议类型
else:
PIP_PROXY = f" -i {settings.PIP_PROXY} " if settings.PIP_PROXY else ""
# 本地优先,镜像站不存在时,不使用全局代理
else:
PIP_PROXY = f" -i {settings.PIP_PROXY} " if settings.PIP_PROXY else ""
SystemUtils.execute(f"{PROXY_CHAINS} pip install -r {requirements_file} {PIP_PROXY} > /dev/null 2>&1")
# 安装成功后统计
self.install_reg(pid)

View File

@@ -17,6 +17,8 @@ DOH_ENABLE=true
META_CACHE_EXPIRE=0
# 自动检查和更新站点资源包(索引、认证等)
AUTO_UPDATE_RESOURCE=true
# 代理补全开关,支持 True、False, 在没有配置镜像站的时候True 使用 PROXY_HOST 补全镜像站缺失False 在没有配置镜像站的时候,不使用全局补全
PROXY_INTERNET_PRIORITY=true
# 【*】API密钥建议更换复杂字符串有Jellyseerr/Overseerr、媒体服务器Webhook等配置以及部分支持API_TOKEN的API中使用
API_TOKEN=moviepilot
# 登录页面电影海报tmdb/bingtmdb要求能正常连接api.themoviedb.org

132
update
View File

@@ -41,8 +41,8 @@ function install_backend_and_download_resources() {
if download_and_unzip "${GITHUB_PROXY}https://github.com/jxxghp/MoviePilot/archive/refs/${1}" "App"; then
INFO "后端程序下载成功"
INFO "依赖安装中..."
pip install ${PIP_OPTIONS} --upgrade --root-user-action pip > /dev/null
if pip install ${PIP_OPTIONS} --root-user-action -r /tmp/App/requirements.txt > /dev/null; then
${PROXY_CHAINS} pip install ${PIP_OPTIONS} --upgrade --root-user-action pip > /dev/null
if ${PROXY_CHAINS} pip install ${PIP_OPTIONS} --root-user-action -r /tmp/App/requirements.txt > /dev/null; then
INFO "安装依赖成功"
frontend_version=$(curl ${CURL_OPTIONS} "https://api.github.com/repos/jxxghp/MoviePilot-Frontend/releases/latest" ${CURL_HEADERS} | jq -r .tag_name)
if [[ "${frontend_version}" == *v* ]]; then
@@ -80,7 +80,7 @@ function install_backend_and_download_resources() {
# 插件仓库
rsync -av --remove-source-files /tmp/Plugins/plugins/* /app/app/plugins/ > /dev/null
# 提前安装插件依赖
find /app/app/plugins -name requirements.txt -exec pip install --root-user-action ${PIP_OPTIONS} -r {} \; > /dev/null
find /app/app/plugins -name requirements.txt -exec ${PROXY_CHAINS} pip install --root-user-action ${PIP_OPTIONS} -r {} \; > /dev/null
# 清理临时目录
rm -rf /tmp/*
INFO "插件更新成功"
@@ -116,26 +116,128 @@ function install_backend_and_download_resources() {
fi
}
# 使用python进行URL解析$1为PROXY_HOST
function parse_url() {
local result
result=$(./parse_url.py ${1})
# 解析结果并提取各项
PROTOCOL=$(echo "$result" | grep "^SCHEME:" | awk '{print $2}')
USERNAME=$(echo "$result" | grep "^USERNAME:" | awk '{print $2}')
PASSWORD=$(echo "$result" | grep "^PASSWORD:" | awk '{print $2}')
HOST=$(echo "$result" | grep "^HOST:" | awk '{print $2}')
PORT=$(echo "$result" | grep "^PORT:" | awk '{print $2}')
}
if [[ "${MOVIEPILOT_AUTO_UPDATE}" = "true" ]] || [[ "${MOVIEPILOT_AUTO_UPDATE}" = "release" ]] || [[ "${MOVIEPILOT_AUTO_UPDATE}" = "dev" ]]; then
if [[ -n "${PIP_PROXY}" ]] || [[ -n "${GITHUB_PROXY}" ]]; then
CURL_OPTIONS="-sL"
PIP_OPTIONS=${PIP_PROXY:+-i ${PIP_PROXY}}
GITHUB_PROXY=${GITHUB_PROXY:-""}
# 判断不同的代理组合
if [ -z "${PIP_OPTIONS}" ] && [ -n "${GITHUB_PROXY}" ]; then
INFO "不使用代理更新环境依赖使用Github镜像代理更新程序"
elif [ -n "${PIP_OPTIONS}" ] && [ -z "${GITHUB_PROXY}" ]; then
INFO "使用Pip镜像代理更新环境依赖不使用代理更新程序"
# 默认不使用proxychains代理PIP
PROXY_CHAINS=""
# 解析代理地址,判断代理合法性
if [[ -n "${PROXY_HOST}" ]]; then
parse_url "${PROXY_HOST}"
INFO "检测到代理地址,开始解析..."
if [[ "${PROTOCOL}" =~ ^http ]]; then
PROXY_HOST_MODE="true"
SOCKS_MODE="false"
elif [[ "${PROTOCOL}" =~ ^socks ]]; then
PROXY_HOST_MODE="true"
SOCKS_MODE="true"
else
INFO "使用Pip镜像代理更新环境依赖使用Github镜像代理更新程序"
PROXY_HOST_MODE="false"
SOCKS_MODE="false"
WARN "【PROXY_HOST】代理地址错误无法添加全局代理环境开始使用其他更新方式"
fi
elif [ -n "${PROXY_HOST}" ]; then
fi
# 模式1镜像站点代理
if [[ -n "${PIP_PROXY}" ]] || [[ -n "${GITHUB_PROXY}" ]]; then
# 通用代理参数
GITHUB_PROXY=${GITHUB_PROXY:-""}
# 模式1-1全局代理补充本地网络代理并修改pip支持socks代理
if [[ "${PROXY_SUPPLEMENT}" = "true" ]] && [[ "${PROXY_HOST_MODE}" = "true" ]]; then
CURL_OPTIONS="-sL -x ${PROXY_HOST}"
# 针对socks模式下启用proxychains
if [[ "${SOCKS_MODE}" == "true" ]]; then
PROXY_CHAINS="proxychains4 -f <( echo -e '[ProxyList]\n${PROTOCOL} ${HOST} ${PORT} ${USERNAME} ${PASSWORD}')"
PIP_OPTIONS=${PIP_PROXY:+-i ${PIP_PROXY}}
# http/https代理不需要启用proxychains
else
PROXY_CHAINS=""
# http/https代理下优先使用-i镜像站
if [[ -n "${PIP_PROXY}" ]]; then
PIP_OPTIONS="-i ${PIP_PROXY}"
else
PIP_OPTIONS="--proxy=${PROXY_HOST}"
fi
fi
# 双镜像站去除proxychains
if [[ -n "${PIP_OPTIONS}" && -n "${GITHUB_PROXY}" ]]; then
PROXY_CHAINS=""
INFO "使用Pip镜像代理更新环境依赖使用Github镜像代理更新程序"
# 单Github镜像站保留proxychains
elif [[ -z "${PIP_OPTIONS}" && -n "${GITHUB_PROXY}" ]];then
# 全局为socks代理时优先使用-i镜像站去除proxychains
if [[ -n "${PIP_OPTIONS}" ]]; then
PROXY_CHAINS=""
fi
INFO "使用全局代理更新环境依赖使用Github镜像代理更新程序"
# 单Pip镜像站去除proxychains
elif [[ -n "${PIP_OPTIONS}" && -z "${GITHUB_PROXY}" ]];then
PROXY_CHAINS=""
INFO "使用Pip镜像代理更新环境依赖使用全局代理更新程序"
# 没有镜像站,一般情况下不会出现,过不了第一层判断
else
INFO "使用全局代理更新程序与环境依赖"
fi
# 模式1-2本地网络优先不使用全局代理补全
elif [[ "${PROXY_SUPPLEMENT}" = "false" ]]; then
CURL_OPTIONS="-sL"
PIP_OPTIONS=${PIP_PROXY:+-i ${PIP_PROXY}}
PROXY_CHAINS=""
# 双镜像站
if [[ -n "${PIP_PROXY}" && -n "${GITHUB_PROXY}" ]]; then
INFO "使用Pip镜像代理更新环境依赖使用Github镜像代理更新程序"
# 单Github镜像站
elif [[ -z "${PIP_OPTIONS}" && -n "${GITHUB_PROXY}" ]]; then
INFO "不使用代理更新环境依赖使用Github镜像代理更新程序"
# 单Pip镜像站
elif [[ -n "${PIP_OPTIONS}" && -z "${GITHUB_PROXY}" ]]; then
INFO "使用Pip镜像代理更新环境依赖不使用代理更新程序"
# 没有镜像站,一般情况下不会出现,过不了第一层判断
else
INFO "不使用任何代理更新程序与环境依赖"
fi
# 模式1-3其他情况一般不会出现
else
CURL_OPTIONS="-sL"
PIP_OPTIONS=""
GITHUB_PROXY=""
PROXY_CHAINS=""
WARN "出现了未知的情况,不使用任何代理更新程序与环境依赖"
fi
# 模式3代理地址正常则使用全局代理
elif [[ -n "${PROXY_HOST}" && "${PROXY_HOST_MODE}" = "true" ]]; then
CURL_OPTIONS="-sL -x ${PROXY_HOST}"
PIP_OPTIONS="--proxy=${PROXY_HOST}"
# 针对socks模式下启用proxychains4
if [[ "${SOCKS_MODE}" == "true" ]]; then
PIP_OPTIONS=""
PROXY_CHAINS="proxychains4 -f <( echo -e '[ProxyList]\n${PROTOCOL} ${HOST} ${PORT} ${USERNAME} ${PASSWORD}')"
else
PROXY_CHAINS=""
PIP_OPTIONS="--proxy=${PROXY_HOST}"
fi
GITHUB_PROXY=""
PROXY_CHAINS=""
INFO "使用全局代理更新程序与环境依赖"
# 模式4其他情况统一不使用代理
else
CURL_OPTIONS="-sL"
PIP_OPTIONS=""
GITHUB_PROXY=""
PROXY_CHAINS=""
INFO "不使用任何代理更新程序与环境依赖"
fi
if [ -n "${GITHUB_TOKEN}" ]; then

53
urlparse.py Normal file
View File

@@ -0,0 +1,53 @@
import sys
from urllib.parse import urlparse
def parse_url(url):
parsed_url = urlparse(url)
# 提取各个部分
protocol = parsed_url.scheme or ""
username = parsed_url.username or ""
password = parsed_url.password or ""
hostname = parsed_url.hostname or ""
port = parsed_url.port or ""
if hostname:
hostname = hostname.lower()
if not port:
if protocol == "https":
port = 443
elif protocol == "http":
port = 80
elif protocol in {"socks5", "socks5h", "socks4", "socks4a"}:
port = 1080
# socks协议转换适配proxychains4的临时命令不支持的socks4a与socks5h
if protocol:
protocol = protocol.lower()
if protocol in {"socks5", "socks5h"}:
protocol = "socks5"
elif protocol in {"socks4", "socks4a"}:
protocol = "socks4"
# 打印提取的部分
print(f"SCHEME:{protocol}")
print(f"USERNAME:{username}")
print(f"PASSWORD:{password}")
print(f"HOST:{hostname}")
print(f"PORT:{port}")
if __name__ == "__main__":
# 参数不全,直接返回空解析结果
if len(sys.argv) != 2:
print(f"SCHEME:''")
print(f"USERNAME:''")
print(f"PASSWORD:''")
print(f"HOST:''")
print(f"PORT:''")
# 参数全解析URL
PROXY_HOST = sys.argv[1]
parse_url(url=PROXY_HOST)