# -*- coding: utf-8 -*- """ 封装 Cloudreve 客户端 """ from typing import Generator from urllib.parse import quote from authenticator import Authenticator from request import Request class Cloudreve: """Cloudreve 客户端""" def __init__(self): # 实例化认证器 self.authenticator = Authenticator() # 实例化请求客户端 self.http_client = Request() def _get_upload_session(self, uri: str, size: int) -> str: """ 获取上传会话标识 :param uri: 统一资源标识符 :param size: 文件大小 :return: 上传会话标识 """ response = self.http_client.put( url=f"https://cloudreve.liubiren.cloud/api/v4/file/upload", headers={ "Authorization": f"Bearer {self.authenticator.get_token(servicer="cloudreve")}", "Content-Type": "application/json; charset=utf-8", }, json={ "uri": quote(string=uri, safe=":/?&="), # 编码统一资源标识 "size": size, "policy_id": "zpHb", # https://cloudreve.liubiren.cloud/api/v4/file?uri=cloudreve://my/转直链 可查看该文件夹储存策略 }, ) # 若非响应成功则抛出异常 if not response["code"] == 0: raise RuntimeError("创建上传会话发生异常") return response["data"]["session_id"] def _upload_file_chunk(self, session_id: str, index: int, chunk: bytes) -> None: """ 上传文件块 :param session_id: 上传会话标识 :param index: 文件块索引 :param chunk: 文件块数据 :return: None """ response = self.http_client.post( url=f"https://cloudreve.liubiren.cloud/api/v4/file/upload/{session_id}/{index}", headers={ "Authorization": f"Bearer {self.authenticator.get_token(servicer="cloudreve")}", "Content-Type": "application/octet-stream", "Content-Length": str(len(chunk)), }, data=chunk, ) if not response["code"] == 0: raise RuntimeError("上传文件块发生异常") def _upload_file(self, uri: str, size: int, generator: Generator) -> None: """ 上传文件 :param uri: 统一资源标识符 :param size: 文件大小 :param generator: 文件块生成器 :return: None """ # 获取上传会话标识 session_id = self._get_upload_session(uri=uri, size=size) for index, chunk in enumerate(generator): # 上传文件块 self._upload_file_chunk(session_id=session_id, index=index, chunk=chunk) def _create_direct_link(self, uri: str) -> str: """ 创建直链 :param uri: 统一资源标识符 :return: 直链 """ response = self.http_client.put( url="https://cloudreve.liubiren.cloud/api/v4/file/source", headers={ "Authorization": f"Bearer {self.authenticator.get_token(servicer="cloudreve")}", "Content-Type": "application/json; charset=utf-8", }, json={ "uris": [quote(string=uri, safe=":/?&=")], # 编码统一资源标识 }, ) if not response["code"] == 0: raise RuntimeError("获取直链发生异常") return response["data"][0]["link"] def get_direct_link(self, uri: str, size: int, generator: Generator) -> str: """ 获取直链 :param uri: 统一资源标识符 :return: 直链 """ response = self.http_client.get( url=f"https://cloudreve.liubiren.cloud/api/v4/file/info", headers={ "Authorization": f"Bearer {self.authenticator.get_token(servicer="cloudreve")}", "Content-Type": "application/json; charset=utf-8", }, params={ "uri": quote(string=uri, safe=":/?&="), # 编码统一资源标识 "extended": "true", # 获取文件扩展信息 }, ) # 若文件已存在则返回直链,否则上传文件并创建直连 if response["code"] == 0: return response["data"]["extended_info"]["direct_links"][0]["url"] # 上传文件 self._upload_file( generator=generator, uri=uri, size=size, ) # 创建直连 direct_link = self._create_direct_link(uri=uri) return direct_link