Merge pull request #2365 from InfinityPacer/main
This commit is contained in:
@@ -18,16 +18,10 @@ class Emby:
|
||||
def __init__(self):
|
||||
self._host = settings.EMBY_HOST
|
||||
if self._host:
|
||||
if not self._host.endswith("/"):
|
||||
self._host += "/"
|
||||
if not self._host.startswith("http"):
|
||||
self._host = "http://" + self._host
|
||||
self._host = RequestUtils.standardize_base_url(self._host)
|
||||
self._playhost = settings.EMBY_PLAY_HOST
|
||||
if self._playhost:
|
||||
if not self._playhost.endswith("/"):
|
||||
self._playhost += "/"
|
||||
if not self._playhost.startswith("http"):
|
||||
self._playhost = "http://" + self._playhost
|
||||
self._playhost = RequestUtils.standardize_base_url(self._playhost)
|
||||
self._apikey = settings.EMBY_API_KEY
|
||||
self.user = self.get_user(settings.SUPERUSER)
|
||||
self.folders = self.get_emby_folders()
|
||||
|
@@ -15,16 +15,10 @@ class Jellyfin:
|
||||
def __init__(self):
|
||||
self._host = settings.JELLYFIN_HOST
|
||||
if self._host:
|
||||
if not self._host.endswith("/"):
|
||||
self._host += "/"
|
||||
if not self._host.startswith("http"):
|
||||
self._host = "http://" + self._host
|
||||
self._host = RequestUtils.standardize_base_url(self._host)
|
||||
self._playhost = settings.JELLYFIN_PLAY_HOST
|
||||
if self._playhost:
|
||||
if not self._playhost.endswith("/"):
|
||||
self._playhost += "/"
|
||||
if not self._playhost.startswith("http"):
|
||||
self._playhost = "http://" + self._playhost
|
||||
self._playhost = RequestUtils.standardize_base_url(self._playhost)
|
||||
self._apikey = settings.JELLYFIN_API_KEY
|
||||
self.user = self.get_user(settings.SUPERUSER)
|
||||
self.serverid = self.get_server_id()
|
||||
|
@@ -6,29 +6,26 @@ from urllib.parse import quote_plus
|
||||
from cachetools import TTLCache, cached
|
||||
from plexapi import media
|
||||
from plexapi.server import PlexServer
|
||||
from requests import Response, Session
|
||||
|
||||
from app import schemas
|
||||
from app.core.config import settings
|
||||
from app.log import logger
|
||||
from app.schemas import MediaType
|
||||
from app.utils.http import RequestUtils
|
||||
|
||||
|
||||
class Plex:
|
||||
_plex = None
|
||||
_session = None
|
||||
|
||||
def __init__(self):
|
||||
self._host = settings.PLEX_HOST
|
||||
if self._host:
|
||||
if not self._host.endswith("/"):
|
||||
self._host += "/"
|
||||
if not self._host.startswith("http"):
|
||||
self._host = "http://" + self._host
|
||||
self._host = RequestUtils.standardize_base_url(self._host)
|
||||
self._playhost = settings.PLEX_PLAY_HOST
|
||||
if self._playhost:
|
||||
if not self._playhost.endswith("/"):
|
||||
self._playhost += "/"
|
||||
if not self._playhost.startswith("http"):
|
||||
self._playhost = "http://" + self._playhost
|
||||
self._playhost = RequestUtils.standardize_base_url(self._playhost)
|
||||
self._token = settings.PLEX_TOKEN
|
||||
if self._host and self._token:
|
||||
try:
|
||||
@@ -37,6 +34,7 @@ class Plex:
|
||||
except Exception as e:
|
||||
self._plex = None
|
||||
logger.error(f"Plex服务器连接失败:{str(e)}")
|
||||
self._session = self.__adapt_plex_session()
|
||||
|
||||
def is_inactive(self) -> bool:
|
||||
"""
|
||||
@@ -727,3 +725,71 @@ class Plex:
|
||||
))
|
||||
offset += num
|
||||
return ret_resume[:num]
|
||||
|
||||
def get_data(self, endpoint: str, **kwargs) -> Optional[Response]:
|
||||
"""
|
||||
自定义从媒体服务器获取数据
|
||||
:param endpoint: 端点
|
||||
:param kwargs: 其他请求参数,如headers, cookies, proxies等
|
||||
"""
|
||||
return self.__request(method="get", endpoint=endpoint, **kwargs)
|
||||
|
||||
def post_data(self, endpoint: str, **kwargs) -> Optional[Response]:
|
||||
"""
|
||||
自定义从媒体服务器获取数据
|
||||
:param endpoint: 端点
|
||||
:param kwargs: 其他请求参数,如headers, cookies, proxies等
|
||||
"""
|
||||
return self.__request(method="post", endpoint=endpoint, **kwargs)
|
||||
|
||||
def put_data(self, endpoint: str, **kwargs) -> Optional[Response]:
|
||||
"""
|
||||
自定义从媒体服务器获取数据
|
||||
:param endpoint: 端点
|
||||
:param kwargs: 其他请求参数,如headers, cookies, proxies等
|
||||
"""
|
||||
return self.__request(method="put", endpoint=endpoint, **kwargs)
|
||||
|
||||
def __request(self, method: str, endpoint: str, **kwargs) -> Optional[Response]:
|
||||
"""
|
||||
自定义从媒体服务器获取数据
|
||||
:param method: HTTP方法,如 get, post, put 等
|
||||
:param endpoint: 端点
|
||||
:param kwargs: 其他请求参数,如headers, cookies, proxies等
|
||||
"""
|
||||
if not self._session:
|
||||
return
|
||||
try:
|
||||
url = RequestUtils.adapt_request_url(host=self._host, endpoint=endpoint)
|
||||
kwargs.setdefault("headers", self.__get_request_headers())
|
||||
kwargs.setdefault("raise_exception", True)
|
||||
request_method = getattr(RequestUtils(session=self._session), f"{method}_res", None)
|
||||
if request_method:
|
||||
return request_method(url=url, **kwargs)
|
||||
else:
|
||||
logger.error(f"方法 {method} 不存在")
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"连接Plex出错:" + str(e))
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def __get_request_headers() -> dict:
|
||||
"""获取请求头"""
|
||||
return {
|
||||
"X-Plex-Token": settings.PLEX_TOKEN,
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def __adapt_plex_session() -> Session:
|
||||
"""
|
||||
创建并配置一个针对Plex服务的requests.Session实例
|
||||
这个会话包括特定的头部信息,用于处理所有的Plex请求
|
||||
"""
|
||||
# 设置请求头部,通常包括验证令牌和接受/内容类型头部
|
||||
headers = Plex.__get_request_headers()
|
||||
session = Session()
|
||||
session.headers = headers
|
||||
return session
|
||||
|
@@ -1,10 +1,13 @@
|
||||
from typing import Union, Any, Optional
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import requests
|
||||
import urllib3
|
||||
from requests import Session, Response
|
||||
from urllib3.exceptions import InsecureRequestWarning
|
||||
|
||||
from app.log import logger
|
||||
|
||||
urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
|
||||
@@ -48,128 +51,160 @@ class RequestUtils:
|
||||
if timeout:
|
||||
self._timeout = timeout
|
||||
|
||||
def post(self, url: str, data: Any = None, json: dict = None) -> Optional[Response]:
|
||||
def request(self, method: str, url: str, raise_exception: bool = False, **kwargs) -> Optional[Response]:
|
||||
"""
|
||||
发起HTTP请求
|
||||
:param method: HTTP方法,如 get, post, put 等
|
||||
:param url: 请求的URL
|
||||
:param raise_exception: 是否在发生异常时抛出异常,否则默认拦截异常返回None
|
||||
:param kwargs: 其他请求参数,如headers, cookies, proxies等
|
||||
:return: HTTP响应对象
|
||||
:raises: requests.exceptions.RequestException 仅raise_exception为True时会抛出
|
||||
"""
|
||||
if self._session is None:
|
||||
req_method = requests.request
|
||||
else:
|
||||
req_method = self._session.request
|
||||
kwargs.setdefault("headers", self._headers)
|
||||
kwargs.setdefault("cookies", self._cookies)
|
||||
kwargs.setdefault("proxies", self._proxies)
|
||||
kwargs.setdefault("timeout", self._timeout)
|
||||
kwargs.setdefault("verify", False)
|
||||
kwargs.setdefault("stream", False)
|
||||
try:
|
||||
return req_method(method, url, **kwargs)
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.debug(f"请求失败: {e}")
|
||||
if raise_exception:
|
||||
raise
|
||||
return None
|
||||
|
||||
def get(self, url: str, params: dict = None, **kwargs) -> Optional[str]:
|
||||
"""
|
||||
发送GET请求
|
||||
:param url: 请求的URL
|
||||
:param params: 请求的参数
|
||||
:param kwargs: 其他请求参数,如headers, cookies, proxies等
|
||||
:return: 响应的内容,若发生RequestException则返回None
|
||||
"""
|
||||
response = self.request(method="get", url=url, params=params, **kwargs)
|
||||
return str(response.content, "utf-8") if response else None
|
||||
|
||||
def post(self, url: str, data: Any = None, json: dict = None, **kwargs) -> Optional[Response]:
|
||||
"""
|
||||
发送POST请求
|
||||
:param url: 请求的URL
|
||||
:param data: 请求的数据
|
||||
:param json: 请求的JSON数据
|
||||
:param kwargs: 其他请求参数,如headers, cookies, proxies等
|
||||
:return: HTTP响应对象,若发生RequestException则返回None
|
||||
"""
|
||||
if json is None:
|
||||
json = {}
|
||||
try:
|
||||
if self._session:
|
||||
return self._session.post(url,
|
||||
data=data,
|
||||
verify=False,
|
||||
headers=self._headers,
|
||||
proxies=self._proxies,
|
||||
cookies=self._cookies,
|
||||
timeout=self._timeout,
|
||||
json=json,
|
||||
stream=False)
|
||||
else:
|
||||
return requests.post(url,
|
||||
data=data,
|
||||
verify=False,
|
||||
headers=self._headers,
|
||||
proxies=self._proxies,
|
||||
cookies=self._cookies,
|
||||
timeout=self._timeout,
|
||||
json=json,
|
||||
stream=False)
|
||||
except requests.exceptions.RequestException:
|
||||
return None
|
||||
return self.request(method="post", url=url, data=data, json=json, **kwargs)
|
||||
|
||||
def get(self, url: str, params: dict = None) -> Optional[str]:
|
||||
try:
|
||||
if self._session:
|
||||
r = self._session.get(url,
|
||||
verify=False,
|
||||
headers=self._headers,
|
||||
proxies=self._proxies,
|
||||
cookies=self._cookies,
|
||||
timeout=self._timeout,
|
||||
params=params)
|
||||
else:
|
||||
r = requests.get(url,
|
||||
verify=False,
|
||||
headers=self._headers,
|
||||
proxies=self._proxies,
|
||||
cookies=self._cookies,
|
||||
timeout=self._timeout,
|
||||
params=params)
|
||||
return str(r.content, 'utf-8')
|
||||
except requests.exceptions.RequestException:
|
||||
return None
|
||||
def put(self, url: str, data: Any = None, **kwargs) -> Optional[Response]:
|
||||
"""
|
||||
发送PUT请求
|
||||
:param url: 请求的URL
|
||||
:param data: 请求的数据
|
||||
:param kwargs: 其他请求参数,如headers, cookies, proxies等
|
||||
:return: HTTP响应对象,若发生RequestException则返回None
|
||||
"""
|
||||
return self.request(method="put", url=url, data=data, **kwargs)
|
||||
|
||||
def get_res(self, url: str,
|
||||
def get_res(self,
|
||||
url: str,
|
||||
params: dict = None,
|
||||
data: Any = None,
|
||||
json: dict = None,
|
||||
allow_redirects: bool = True,
|
||||
raise_exception: bool = False
|
||||
) -> Optional[Response]:
|
||||
try:
|
||||
if self._session:
|
||||
return self._session.get(url,
|
||||
params=params,
|
||||
data=data,
|
||||
json=json,
|
||||
verify=False,
|
||||
headers=self._headers,
|
||||
proxies=self._proxies,
|
||||
cookies=self._cookies,
|
||||
timeout=self._timeout,
|
||||
allow_redirects=allow_redirects,
|
||||
stream=False)
|
||||
else:
|
||||
return requests.get(url,
|
||||
params=params,
|
||||
data=data,
|
||||
json=json,
|
||||
verify=False,
|
||||
headers=self._headers,
|
||||
proxies=self._proxies,
|
||||
cookies=self._cookies,
|
||||
timeout=self._timeout,
|
||||
allow_redirects=allow_redirects,
|
||||
stream=False)
|
||||
except requests.exceptions.RequestException:
|
||||
if raise_exception:
|
||||
raise requests.exceptions.RequestException
|
||||
return None
|
||||
raise_exception: bool = False,
|
||||
**kwargs) -> Optional[Response]:
|
||||
"""
|
||||
发送GET请求并返回响应对象
|
||||
:param url: 请求的URL
|
||||
:param params: 请求的参数
|
||||
:param data: 请求的数据
|
||||
:param json: 请求的JSON数据
|
||||
:param allow_redirects: 是否允许重定向
|
||||
:param raise_exception: 是否在发生异常时抛出异常,否则默认拦截异常返回None
|
||||
:param kwargs: 其他请求参数,如headers, cookies, proxies等
|
||||
:return: HTTP响应对象,若发生RequestException则返回None
|
||||
:raises: requests.exceptions.RequestException 仅raise_exception为True时会抛出
|
||||
"""
|
||||
return self.request(method="get",
|
||||
url=url,
|
||||
params=params,
|
||||
data=data,
|
||||
json=json,
|
||||
allow_redirects=allow_redirects,
|
||||
raise_exception=raise_exception,
|
||||
**kwargs)
|
||||
|
||||
def post_res(self, url: str, data: Any = None, params: dict = None,
|
||||
def post_res(self,
|
||||
url: str,
|
||||
data: Any = None,
|
||||
params: dict = None,
|
||||
allow_redirects: bool = True,
|
||||
files: Any = None,
|
||||
json: dict = None,
|
||||
raise_exception: bool = False) -> Optional[Response]:
|
||||
try:
|
||||
if self._session:
|
||||
return self._session.post(url,
|
||||
data=data,
|
||||
params=params,
|
||||
verify=False,
|
||||
headers=self._headers,
|
||||
proxies=self._proxies,
|
||||
cookies=self._cookies,
|
||||
timeout=self._timeout,
|
||||
allow_redirects=allow_redirects,
|
||||
files=files,
|
||||
json=json,
|
||||
stream=False)
|
||||
else:
|
||||
return requests.post(url,
|
||||
data=data,
|
||||
params=params,
|
||||
verify=False,
|
||||
headers=self._headers,
|
||||
proxies=self._proxies,
|
||||
cookies=self._cookies,
|
||||
timeout=self._timeout,
|
||||
allow_redirects=allow_redirects,
|
||||
files=files,
|
||||
json=json,
|
||||
stream=False)
|
||||
except requests.exceptions.RequestException:
|
||||
if raise_exception:
|
||||
raise requests.exceptions.RequestException
|
||||
return None
|
||||
raise_exception: bool = False,
|
||||
**kwargs) -> Optional[Response]:
|
||||
"""
|
||||
发送POST请求并返回响应对象
|
||||
:param url: 请求的URL
|
||||
:param data: 请求的数据
|
||||
:param params: 请求的参数
|
||||
:param allow_redirects: 是否允许重定向
|
||||
:param files: 请求的文件
|
||||
:param json: 请求的JSON数据
|
||||
:param kwargs: 其他请求参数,如headers, cookies, proxies等
|
||||
:param raise_exception: 是否在发生异常时抛出异常,否则默认拦截异常返回None
|
||||
:return: HTTP响应对象,若发生RequestException则返回None
|
||||
:raises: requests.exceptions.RequestException 仅raise_exception为True时会抛出
|
||||
"""
|
||||
return self.request(method="post",
|
||||
url=url,
|
||||
data=data,
|
||||
params=params,
|
||||
allow_redirects=allow_redirects,
|
||||
files=files,
|
||||
json=json,
|
||||
raise_exception=raise_exception,
|
||||
**kwargs)
|
||||
|
||||
def put_res(self,
|
||||
url: str,
|
||||
data: Any = None,
|
||||
params: dict = None,
|
||||
allow_redirects: bool = True,
|
||||
files: Any = None,
|
||||
json: dict = None,
|
||||
raise_exception: bool = False,
|
||||
**kwargs) -> Optional[Response]:
|
||||
"""
|
||||
发送PUT请求并返回响应对象
|
||||
:param url: 请求的URL
|
||||
:param data: 请求的数据
|
||||
:param params: 请求的参数
|
||||
:param allow_redirects: 是否允许重定向
|
||||
:param files: 请求的文件
|
||||
:param json: 请求的JSON数据
|
||||
:param raise_exception: 是否在发生异常时抛出异常,否则默认拦截异常返回None
|
||||
:param kwargs: 其他请求参数,如headers, cookies, proxies等
|
||||
:return: HTTP响应对象,若发生RequestException则返回None
|
||||
:raises: requests.exceptions.RequestException 仅raise_exception为True时会抛出
|
||||
"""
|
||||
return self.request(method="put",
|
||||
url=url,
|
||||
data=data,
|
||||
params=params,
|
||||
allow_redirects=allow_redirects,
|
||||
files=files,
|
||||
json=json,
|
||||
raise_exception=raise_exception,
|
||||
**kwargs)
|
||||
|
||||
@staticmethod
|
||||
def cookie_parse(cookies_str: str, array: bool = False) -> Union[list, dict]:
|
||||
@@ -182,15 +217,41 @@ class RequestUtils:
|
||||
if not cookies_str:
|
||||
return {}
|
||||
cookie_dict = {}
|
||||
cookies = cookies_str.split(';')
|
||||
cookies = cookies_str.split(";")
|
||||
for cookie in cookies:
|
||||
cstr = cookie.split('=')
|
||||
cstr = cookie.split("=")
|
||||
if len(cstr) > 1:
|
||||
cookie_dict[cstr[0].strip()] = cstr[1].strip()
|
||||
if array:
|
||||
cookiesList = []
|
||||
for cookieName, cookieValue in cookie_dict.items():
|
||||
cookies = {'name': cookieName, 'value': cookieValue}
|
||||
cookiesList.append(cookies)
|
||||
return cookiesList
|
||||
return [{"name": k, "value": v} for k, v in cookie_dict.items()]
|
||||
return cookie_dict
|
||||
|
||||
@staticmethod
|
||||
def standardize_base_url(host: str) -> str:
|
||||
"""
|
||||
标准化提供的主机地址,确保它以http://或https://开头,并且以斜杠(/)结尾
|
||||
:param host: 提供的主机地址字符串
|
||||
:return: 标准化后的主机地址字符串
|
||||
"""
|
||||
if not host:
|
||||
return host
|
||||
if not host.endswith("/"):
|
||||
host += "/"
|
||||
if not host.startswith("http://") and not host.startswith("https://"):
|
||||
host = "http://" + host
|
||||
return host
|
||||
|
||||
@staticmethod
|
||||
def adapt_request_url(host: str, endpoint: str) -> Optional[str]:
|
||||
"""
|
||||
基于传入的host,适配请求的URL,确保每个请求的URL是完整的,用于在发送请求前自动处理和修正请求的URL。
|
||||
:param host: 主机头
|
||||
:param endpoint: 端点
|
||||
:return: 完整的请求URL字符串
|
||||
"""
|
||||
if not host and not endpoint:
|
||||
return None
|
||||
if endpoint.startswith(("http://", "https://")):
|
||||
return endpoint
|
||||
host = RequestUtils.standardize_base_url(host)
|
||||
return urljoin(host, endpoint) if host else endpoint
|
||||
|
Reference in New Issue
Block a user