Source code for p115client.tool.extract

#!/usr/bin/env python3
# encoding: utf-8

__all__ = [
    "extract_push", "extract_push_progress", "extract_iterdir_raw", 
    "extract_file", "extract_progress", 
]
__doc__ = "这个模块提供了一些和压缩包的增删改查有关的函数"

from collections.abc import AsyncIterator, Callable, Coroutine, Iterable, Iterator, Mapping
from os import PathLike
from typing import cast, overload, Any, Literal

from dicttools import get_first
from iterutils import run_gen_step, run_gen_step_iter, YieldFrom

from ..client import P115Client, check_response


@overload
def extract_push(
    client: str | PathLike | P115Client, 
    pickcode: str | int | Mapping, 
    secret: str = "", 
    app: str = "web", 
    *, 
    async_: Literal[False] = False, 
    **request_kwargs, 
) -> dict:
    ...
@overload
def extract_push(
    client: str | PathLike | P115Client, 
    pickcode: str | int | Mapping, 
    secret: str = "", 
    app: str = "web", 
    *, 
    async_: Literal[True], 
    **request_kwargs, 
) -> Coroutine[Any, Any, dict]:
    ...
[docs] def extract_push( client: str | PathLike | P115Client, pickcode: str | int | Mapping, secret: str = "", app: str = "web", *, async_: Literal[False, True] = False, **request_kwargs, ) -> dict | Coroutine[Any, Any, dict]: """推送云解压任务 .. warning:: 只能云解压 20GB 以内文件,也不支持云解压分卷压缩包,只支持 .zip、.rar 和 .7z 等。 如果超出此限制,就要自己动手了,但如此的话,压缩包里面的单个文件往往就不支持随机定位了。 .. note:: 响应信息里面有个 "unzip_status" 字段 - 0: 未解压 - 1: 解压中 - 4: 解压成功 - 6: 解压成功(重复提交已成功任务,但密码错误) .. code:: python from time import sleep from p115client import P115Client from p115client.tool import * client = P115Client.from_path() # NOTE: 待搜索的目录 cid = 0 # 罗列此目录内所有的压缩包 files = list(iter_files(client, cid, type=5, use_media_api=True)) for i, file in enumerate(files, 1): if not file: continue # 只支持云解压不超过 20 GB 的压缩包 if file["size"] > (1 << 30) * 20: print(i, f"[SKIPPED] 文件过大: {file}\n\n") continue # 推送解压任务 try: resp = extract_push(client, file, app="android") except FileNotFoundError: print(i, f"[SKIPPED] 文件不存在: {file}\n\n") continue unzip_status = resp["data"]["unzip_status"] if resp["data"]["unzip_status"] != 4: print(i, f"[SKIPPED] unzip_status={unzip_status} 云解压未成: {file}\n\n") continue print(i, "开始解压:", file) try: task_id = extract_file(client, file["pickcode"], to_pid=file["parent_id"]) except Exception as e: print(i, f"[FAILED] 解压失败: {file} 异常: {e}\n\n") continue while True: try: resp = extract_progress(client, task_id) except Exception: continue percent = resp["data"]["percent"] print(f"\r进度(百分比): {percent}%", end="") if percent == 100: print() break sleep(1) client.fs_delete(file["id"]) files[i-1] = None print(i, "[SUCCESS] 解压完成,文件已删除\n\n") :param client: 115 客户端或 cookies :param pickcode: 压缩包文件的 提取码、id :param secret: 解压密码,没有就不传 :param app: 使用指定 app(设备)的接口 :param async_: 是否异步 :param request_kwargs: 其它请求参数 :return: 接口响应 """ if isinstance(client, (str, PathLike)): client = P115Client(client) if app in ("", "web", "desktop", "aps"): extract_push: Callable = client.extract_push else: extract_push = client.extract_push_app request_kwargs["app"] = app if isinstance(pickcode, Mapping): pickcode = cast(str | int, get_first(pickcode, "pickcode", "id")) return check_response(extract_push( {"pick_code": client.to_pickcode(pickcode), "secret": secret}, async_=async_, **request_kwargs, ))
@overload def extract_push_progress( client: str | PathLike | P115Client, pickcode: str | int | Mapping, app: str = "web", *, async_: Literal[False] = False, **request_kwargs, ) -> dict: ... @overload def extract_push_progress( client: str | PathLike | P115Client, pickcode: str | int | Mapping, app: str = "web", *, async_: Literal[True], **request_kwargs, ) -> Coroutine[Any, Any, dict]: ...
[docs] def extract_push_progress( client: str | PathLike | P115Client, pickcode: str | int | Mapping, app: str = "web", *, async_: Literal[False, True] = False, **request_kwargs, ) -> dict | Coroutine[Any, Any, dict]: """获取云解压任务进度 .. warning:: 只能云解压 20GB 以内文件,也不支持云解压分卷压缩包,只支持 .zip、.rar 和 .7z 等。 如果超出此限制,就要自己动手了,但如此的话,压缩包里面的单个文件往往就不支持随机定位了。 .. note:: 响应信息里面有个 "unzip_status" 字段 - 0: 未解压 - 1: 解压中 - 4: 解压成功 - 6: 解压失败 :param client: 115 客户端或 cookies :param pickcode: 压缩包文件的 提取码、id :param app: 使用指定 app(设备)的接口 :param async_: 是否异步 :param request_kwargs: 其它请求参数 :return: 接口响应 """ if isinstance(client, (str, PathLike)): client = P115Client(client) if app in ("", "web", "desktop", "aps"): extract_push: Callable = client.extract_push_progress else: extract_push = client.extract_push_progress_app request_kwargs["app"] = app if isinstance(pickcode, Mapping): pickcode = cast(str | int, get_first(pickcode, "pickcode", "id")) return check_response(extract_push( {"pick_code": client.to_pickcode(pickcode)}, async_=async_, **request_kwargs, ))
@overload def extract_iterdir_raw( client: str | PathLike | P115Client, pickcode: str, path: str = "", page_size: int = 999, app: str = "web", *, async_: Literal[False] = False, **request_kwargs, ) -> Iterator[dict]: ... @overload def extract_iterdir_raw( client: str | PathLike | P115Client, pickcode: str, path: str = "", page_size: int = 999, app: str = "web", *, async_: Literal[True], **request_kwargs, ) -> AsyncIterator[dict]: ...
[docs] def extract_iterdir_raw( client: str | PathLike | P115Client, pickcode: str, path: str = "", page_size: int = 999, app: str = "web", *, async_: Literal[False, True] = False, **request_kwargs, ) -> Iterator[dict] | AsyncIterator[dict]: """对压缩包迭代目录,获取(原始的)文件信息 .. note:: 你可以使用 ``p115client.tool.extract_iterdir`` 作为替代,以获取经过处理的信息 :param client: 115 客户端或 cookies :param pickcode: 压缩包文件的 提取码、id :param path: 压缩包内(目录)路径,为空则是压缩包的根目录 :param page_size: 分页大小,最大 999 :param app: 使用指定 app(设备)的接口 :param async_: 是否异步 :param request_kwargs: 其它请求参数 :return: 迭代器,返回此目录内的文件信息(文件和目录) """ if isinstance(client, (str, PathLike)): client = P115Client(client) def gen_step(): extract_list = client.extract_list next_marker = "" while True: resp = yield extract_list( pickcode, path=path, next_marker=next_marker, page_count=page_size, app=app, async_=async_, **request_kwargs, ) check_response(resp) data = resp["data"] yield YieldFrom(data["list"]) if not (next_marker := data.get("next_marker")): break return run_gen_step_iter(gen_step, async_)
@overload def extract_file( client: str | PathLike | P115Client, pickcode: str, files: str | Iterable[str] = "", dirs: str | Iterable[str] = "", dirname: str = "", to_pid: int | str = 0, app: str = "web", *, async_: Literal[False] = False, **request_kwargs, ) -> int: ... @overload def extract_file( client: str | PathLike | P115Client, pickcode: str, files: str | Iterable[str] = "", dirs: str | Iterable[str] = "", dirname: str = "", to_pid: int | str = 0, app: str = "web", *, async_: Literal[True], **request_kwargs, ) -> Coroutine[Any, Any, int]: ...
[docs] def extract_file( client: str | PathLike | P115Client, pickcode: str, files: str | Iterable[str] = "", dirs: str | Iterable[str] = "", dirname: str = "", to_pid: int | str = 0, app: str = "web", *, async_: Literal[False, True] = False, **request_kwargs, ) -> int | Coroutine[Any, Any, int]: """解压缩到某个网盘目录 :param client: 115 客户端或 cookies :param pickcode: 压缩文件的提取码 :param files: 待解压缩的文件路径(相对于 ``dirname``),如果以 "/" 结尾,则视为目录 :param dirs: 待解压缩的文件路径(相对于 ``dirname``) :param dirname: 压缩包内路径,为空则是压缩包的根目录 :param to_pid: 解压到网盘的目录 id :param app: 使用此设备的接口 :param async_: 是否异步 :param request_kwargs: 其它请求参数 :return: 任务 id """ if isinstance(client, (str, PathLike)): client = P115Client(client) def gen_step(): resp = yield client.extract_file( pickcode, files=files, dirs=dirs, dirname=dirname, to_pid=client.to_id(to_pid), app=app, async_=async_, **request_kwargs, ) check_response(resp) return resp["data"]["extract_id"] return run_gen_step(gen_step, async_)
@overload def extract_progress( client: str | PathLike | P115Client, extract_id: int, app: str = "web", *, async_: Literal[False] = False, **request_kwargs, ) -> dict: ... @overload def extract_progress( client: str | PathLike | P115Client, extract_id: int, app: str = "web", *, async_: Literal[True], **request_kwargs, ) -> Coroutine[Any, Any, dict]: ...
[docs] def extract_progress( client: str | PathLike | P115Client, extract_id: int, app: str = "web", *, async_: Literal[False, True] = False, **request_kwargs, ) -> dict | Coroutine[Any, Any, dict]: """获取【解压到网盘】任务进度 :param client: 115 客户端或 cookies :param extract_id: 解压任务 id :param app: 使用此设备的接口 :param async_: 是否异步 :param request_kwargs: 其它请求参数 :return: 接口响应 """ if isinstance(client, (str, PathLike)): client = P115Client(client) if app in ("", "web", "desktop", "aps"): extract_progress: Callable = client.extract_progress else: extract_progress = client.extract_progress_app request_kwargs["app"] = app return check_response(extract_progress(extract_id, async_=async_, **request_kwargs))