优化cmd2结构
This commit is contained in:
parent
6f78ceac53
commit
2e0e9425fc
270
main.py
270
main.py
@ -4,41 +4,10 @@ from functools import wraps
|
|||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
import colorlog
|
import colorlog
|
||||||
from pikpakFs import FsNode, DirNode, FileNode, PKFs, IsDir, IsFile
|
from pikpakFs import PKFs, IsDir, IsFile
|
||||||
import os
|
import os
|
||||||
|
|
||||||
def RunSyncInLoop(loop):
|
def setup_logging():
|
||||||
def decorator(func):
|
|
||||||
@wraps(func)
|
|
||||||
def decorated(*args, **kwargs):
|
|
||||||
currentLoop = None
|
|
||||||
try:
|
|
||||||
currentLoop = asyncio.get_running_loop()
|
|
||||||
except RuntimeError:
|
|
||||||
pass
|
|
||||||
if currentLoop is loop:
|
|
||||||
return loop.run_until_complete(func(*args, **kwargs))
|
|
||||||
else:
|
|
||||||
return asyncio.run_coroutine_threadsafe(func(*args, **kwargs), loop).result()
|
|
||||||
return decorated
|
|
||||||
return decorator
|
|
||||||
|
|
||||||
def ProvideDecoratorSelfArgs(decorator, argsProvider):
|
|
||||||
def wrapper(func):
|
|
||||||
@wraps(func)
|
|
||||||
def decorated(*args, **kwargs):
|
|
||||||
namespace = args[0]
|
|
||||||
return decorator(argsProvider(namespace))(func)(*args, **kwargs)
|
|
||||||
return decorated
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
class PikpakConsole(cmd2.Cmd):
|
|
||||||
def LoopProvider(self):
|
|
||||||
return self.loop
|
|
||||||
|
|
||||||
RunSync = ProvideDecoratorSelfArgs(RunSyncInLoop, LoopProvider)
|
|
||||||
|
|
||||||
def _setup_logging(self):
|
|
||||||
formatter = colorlog.ColoredFormatter(
|
formatter = colorlog.ColoredFormatter(
|
||||||
"%(log_color)s%(asctime)s - %(levelname)s - %(name)s - %(message)s",
|
"%(log_color)s%(asctime)s - %(levelname)s - %(name)s - %(message)s",
|
||||||
datefmt='%Y-%m-%d %H:%M:%S',
|
datefmt='%Y-%m-%d %H:%M:%S',
|
||||||
@ -64,123 +33,77 @@ class PikpakConsole(cmd2.Cmd):
|
|||||||
logger.addHandler(file_handler)
|
logger.addHandler(file_handler)
|
||||||
logger.setLevel(logging.DEBUG)
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
def IOWorker(self, loop):
|
setup_logging()
|
||||||
self.terminal_lock.acquire() # 我看cmdloop是这么做的,所以我也这么做
|
MainLoop : asyncio.AbstractEventLoop = None
|
||||||
|
Client = PKFs("token.json", proxy="http://127.0.0.1:7890")
|
||||||
|
|
||||||
|
def RunSync(func):
|
||||||
|
@wraps(func)
|
||||||
|
def decorator(*args, **kwargs):
|
||||||
|
currentLoop = None
|
||||||
|
try:
|
||||||
|
currentLoop = asyncio.get_running_loop()
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
||||||
|
if currentLoop is MainLoop:
|
||||||
|
return MainLoop.run_until_complete(func(*args, **kwargs))
|
||||||
|
else:
|
||||||
|
return asyncio.run_coroutine_threadsafe(func(*args, **kwargs), MainLoop).result()
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
class Console(cmd2.Cmd):
|
||||||
|
def _io_worker(self, loop):
|
||||||
|
self.terminal_lock.acquire()
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
try:
|
try:
|
||||||
loop.run_forever()
|
loop.run_forever()
|
||||||
finally:
|
finally:
|
||||||
self.terminal_lock.release()
|
self.terminal_lock.release()
|
||||||
|
|
||||||
async def ainput(self, prompt):
|
async def AsyncInput(self, prompt):
|
||||||
async def ReadInput(prompt):
|
async def _input(prompt):
|
||||||
return self._read_command_line(prompt)
|
return self._read_command_line(prompt)
|
||||||
future = asyncio.run_coroutine_threadsafe(ReadInput(prompt), self.ioLoop)
|
future = asyncio.run_coroutine_threadsafe(_input(prompt), self.ioLoop)
|
||||||
return await asyncio.wrap_future(future)
|
return await asyncio.wrap_future(future)
|
||||||
|
|
||||||
async def aoutput(self, output):
|
async def AsyncPrint(self, output):
|
||||||
async def PrintOuput(output):
|
async def _print(output):
|
||||||
print(output)
|
print(output)
|
||||||
future = asyncio.run_coroutine_threadsafe(PrintOuput(output), self.ioLoop)
|
future = asyncio.run_coroutine_threadsafe(_print(output), self.ioLoop)
|
||||||
await asyncio.wrap_future(future)
|
await asyncio.wrap_future(future)
|
||||||
|
|
||||||
def ParserProvider(self):
|
|
||||||
return cmd2.Cmd2ArgumentParser()
|
|
||||||
|
|
||||||
def AddPathParser(parserProvider, nargs = "?"):
|
|
||||||
def PathParserProvider(self):
|
|
||||||
parser = parserProvider(self)
|
|
||||||
parser.add_argument("path", help="path", default="", nargs=nargs, type=RunSyncInLoop(self.loop)(self.client.PathToNode))
|
|
||||||
return parser
|
|
||||||
return PathParserProvider
|
|
||||||
|
|
||||||
def AddFatherAndSonParser(parserProvider):
|
|
||||||
def PathParserProvider(self):
|
|
||||||
parser = parserProvider(self)
|
|
||||||
parser.add_argument("path", help="path", default="", nargs="?", type=RunSyncInLoop(self.loop)(self.client.PathToFatherNodeAndNodeName))
|
|
||||||
return parser
|
|
||||||
return PathParserProvider
|
|
||||||
|
|
||||||
def AddUrlParser(parserProvider):
|
|
||||||
def PathParserProvider(self):
|
|
||||||
parser = parserProvider(self)
|
|
||||||
parser.add_argument("url", help="url")
|
|
||||||
return parser
|
|
||||||
return PathParserProvider
|
|
||||||
|
|
||||||
def AddUsernamePasswordParser(parserProvider):
|
|
||||||
def PathParserProvider(self):
|
|
||||||
parser = parserProvider(self)
|
|
||||||
parser.add_argument("username", help="username", nargs="?")
|
|
||||||
parser.add_argument("password", help="password", nargs="?")
|
|
||||||
return parser
|
|
||||||
return PathParserProvider
|
|
||||||
|
|
||||||
async def PathCompleter(self, text, line, begidx, endidx, filterFiles):
|
|
||||||
father, sonName = await self.client.PathToFatherNodeAndNodeName(text)
|
|
||||||
if not IsDir(father):
|
|
||||||
return []
|
|
||||||
matches = []
|
|
||||||
matchesNode = []
|
|
||||||
for childId in father.childrenId:
|
|
||||||
child = self.client.GetNodeById(childId)
|
|
||||||
if filterFiles and IsFile(child):
|
|
||||||
continue
|
|
||||||
if child.name.startswith(sonName):
|
|
||||||
self.display_matches.append(child.name)
|
|
||||||
if sonName == "":
|
|
||||||
matches.append(text + child.name)
|
|
||||||
elif text.endswith(sonName):
|
|
||||||
matches.append(text[:text.rfind(sonName)] + child.name)
|
|
||||||
matchesNode.append(child)
|
|
||||||
if len(matchesNode) == 1 and IsDir(matchesNode[0]):
|
|
||||||
matches[0] += "/"
|
|
||||||
self.allow_appended_space = False
|
|
||||||
self.allow_closing_quote = False
|
|
||||||
return matches
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._setup_logging()
|
|
||||||
self.client = PKFs("token.json", proxy="http://127.0.0.1:7890")
|
|
||||||
|
|
||||||
async def Run(self):
|
def preloop(self):
|
||||||
# 1. 设置忽略SIGINT
|
# 1. 设置忽略SIGINT
|
||||||
import signal
|
import signal
|
||||||
def signal_handler(sig, frame):
|
def signal_handler(sig, frame):
|
||||||
pass
|
pass
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
|
||||||
# 2. 创建一个新的事件循环
|
# 2. 创建IO线程处理输入输出
|
||||||
self.loop = asyncio.get_running_loop()
|
|
||||||
self.ioLoop = asyncio.new_event_loop()
|
self.ioLoop = asyncio.new_event_loop()
|
||||||
thread = threading.Thread(target=self.IOWorker, args=(self.ioLoop,))
|
self.ioThread = threading.Thread(target=self._io_worker, args=(self.ioLoop,))
|
||||||
thread.start()
|
self.ioThread.start()
|
||||||
|
|
||||||
# 3. 启动cmd2
|
# 3. 设置console
|
||||||
saved_readline_settings = None
|
self.saved_readline_settings = None
|
||||||
try:
|
|
||||||
# Get sigint protection while we set up readline for cmd2
|
|
||||||
with self.sigint_protection:
|
with self.sigint_protection:
|
||||||
saved_readline_settings = self._set_up_cmd2_readline()
|
saved_readline_settings = self._set_up_cmd2_readline()
|
||||||
|
|
||||||
stop = False
|
def postloop(self):
|
||||||
while not stop:
|
# 1. 还原console设置
|
||||||
# Get sigint protection while we read the command line
|
|
||||||
line = await self.ainput(self.prompt)
|
|
||||||
# Run the command along with all associated pre and post hooks
|
|
||||||
stop = self.onecmd_plus_hooks(line)
|
|
||||||
finally:
|
|
||||||
# Get sigint protection while we restore readline settings
|
|
||||||
with self.sigint_protection:
|
with self.sigint_protection:
|
||||||
if saved_readline_settings is not None:
|
if self.saved_readline_settings is not None:
|
||||||
self._restore_readline(saved_readline_settings)
|
self._restore_readline(self.saved_readline_settings)
|
||||||
|
|
||||||
|
# 2. 停止IO线程
|
||||||
# https://stackoverflow.com/questions/51642267/asyncio-how-do-you-use-run-forever
|
# https://stackoverflow.com/questions/51642267/asyncio-how-do-you-use-run-forever
|
||||||
self.ioLoop.call_soon_threadsafe(self.ioLoop.stop)
|
self.ioLoop.call_soon_threadsafe(self.ioLoop.stop)
|
||||||
thread.join()
|
self.ioThread.join()
|
||||||
|
|
||||||
# commands #
|
# commands #
|
||||||
|
|
||||||
def do_debug(self, args):
|
def do_debug(self, args):
|
||||||
"""
|
"""
|
||||||
Enable debug mode
|
Enable debug mode
|
||||||
@ -195,59 +118,89 @@ class PikpakConsole(cmd2.Cmd):
|
|||||||
logging.getLogger().setLevel(logging.INFO)
|
logging.getLogger().setLevel(logging.INFO)
|
||||||
logging.info("Debug mode disabled")
|
logging.info("Debug mode disabled")
|
||||||
|
|
||||||
|
login_parser = cmd2.Cmd2ArgumentParser()
|
||||||
|
login_parser.add_argument("username", help="username")
|
||||||
|
login_parser.add_argument("password", help="password")
|
||||||
@RunSync
|
@RunSync
|
||||||
@ProvideDecoratorSelfArgs(cmd2.with_argparser, AddUsernamePasswordParser(ParserProvider))
|
@cmd2.with_argparser(login_parser)
|
||||||
async def do_login(self, args):
|
async def do_login(self, args):
|
||||||
"""
|
"""
|
||||||
Login to pikpak
|
Login to pikpak
|
||||||
"""
|
"""
|
||||||
await self.client.Login(args.username, args.password)
|
await Client.Login(args.username, args.password)
|
||||||
await self.aoutput("Logged in successfully")
|
await self.AsyncPrint("Logged in successfully")
|
||||||
|
|
||||||
|
async def _path_completer(self, text, line, begidx, endidx, filterfiles):
|
||||||
|
father, sonName = await Client.PathToFatherNodeAndNodeName(text)
|
||||||
|
if not IsDir(father):
|
||||||
|
return []
|
||||||
|
matches = []
|
||||||
|
matchesNode = []
|
||||||
|
for childId in father.childrenId:
|
||||||
|
child = Client.GetNodeById(childId)
|
||||||
|
if filterfiles and IsFile(child):
|
||||||
|
continue
|
||||||
|
if child.name.startswith(sonName):
|
||||||
|
self.display_matches.append(child.name)
|
||||||
|
if sonName == "":
|
||||||
|
matches.append(text + child.name)
|
||||||
|
elif text.endswith(sonName):
|
||||||
|
matches.append(text[:text.rfind(sonName)] + child.name)
|
||||||
|
matchesNode.append(child)
|
||||||
|
if len(matchesNode) == 1 and IsDir(matchesNode[0]):
|
||||||
|
matches[0] += "/"
|
||||||
|
self.allow_appended_space = False
|
||||||
|
self.allow_closing_quote = False
|
||||||
|
return matches
|
||||||
|
|
||||||
@RunSync
|
@RunSync
|
||||||
async def complete_ls(self, text, line, begidx, endidx):
|
async def complete_ls(self, text, line, begidx, endidx):
|
||||||
return await self.PathCompleter(text, line, begidx, endidx, filterFiles = False)
|
return await self._path_completer(text, line, begidx, endidx, False)
|
||||||
|
|
||||||
|
ls_parser = cmd2.Cmd2ArgumentParser()
|
||||||
|
ls_parser.add_argument("path", help="path", default="", nargs="?", type=RunSync(Client.PathToNode))
|
||||||
@RunSync
|
@RunSync
|
||||||
@ProvideDecoratorSelfArgs(cmd2.with_argparser, AddPathParser(ParserProvider))
|
@cmd2.with_argparser(ls_parser)
|
||||||
async def do_ls(self, args):
|
async def do_ls(self, args):
|
||||||
"""
|
"""
|
||||||
List files in a directory
|
List files in a directory
|
||||||
"""
|
"""
|
||||||
node = args.path
|
node = args.path
|
||||||
if node is None:
|
if node is None:
|
||||||
await self.aoutput("Invalid path")
|
await self.AsyncPrint("Invalid path")
|
||||||
return
|
return
|
||||||
await self.client.Refresh(node)
|
await Client.Refresh(node)
|
||||||
if IsDir(node):
|
if IsDir(node):
|
||||||
for childId in node.childrenId:
|
for childId in node.childrenId:
|
||||||
child = self.client.GetNodeById(childId)
|
child = Client.GetNodeById(childId)
|
||||||
await self.aoutput(child.name)
|
await self.AsyncPrint(child.name)
|
||||||
elif IsFile(node):
|
elif IsFile(node):
|
||||||
await self.aoutput(f"{node.name}: {node.url}")
|
await self.AsyncPrint(f"{node.name}: {node.url}")
|
||||||
|
|
||||||
@RunSync
|
@RunSync
|
||||||
async def complete_cd(self, text, line, begidx, endidx):
|
async def complete_cd(self, text, line, begidx, endidx):
|
||||||
return await self.PathCompleter(text, line, begidx, endidx, filterFiles = True)
|
return await self._path_completer(text, line, begidx, endidx, True)
|
||||||
|
|
||||||
|
cd_parser = cmd2.Cmd2ArgumentParser()
|
||||||
|
cd_parser.add_argument("path", help="path", default="", nargs="?", type=RunSync(Client.PathToNode))
|
||||||
@RunSync
|
@RunSync
|
||||||
@ProvideDecoratorSelfArgs(cmd2.with_argparser, AddPathParser(ParserProvider))
|
@cmd2.with_argparser(cd_parser)
|
||||||
async def do_cd(self, args):
|
async def do_cd(self, args):
|
||||||
"""
|
"""
|
||||||
Change directory
|
Change directory
|
||||||
"""
|
"""
|
||||||
node = args.path
|
node = args.path
|
||||||
if not IsDir(node):
|
if not IsDir(node):
|
||||||
await self.aoutput("Invalid directory")
|
await self.AsyncPrint("Invalid directory")
|
||||||
return
|
return
|
||||||
self.client.currentLocation = node
|
Client.currentLocation = node
|
||||||
|
|
||||||
@RunSync
|
@RunSync
|
||||||
async def do_cwd(self, args):
|
async def do_cwd(self, args):
|
||||||
"""
|
"""
|
||||||
Print current working directory
|
Print current working directory
|
||||||
"""
|
"""
|
||||||
await self.aoutput(self.client.NodeToPath(self.client.currentLocation))
|
await self.AsyncPrint(Client.NodeToPath(Client.currentLocation))
|
||||||
|
|
||||||
def do_clear(self, args):
|
def do_clear(self, args):
|
||||||
"""
|
"""
|
||||||
@ -257,50 +210,69 @@ class PikpakConsole(cmd2.Cmd):
|
|||||||
|
|
||||||
@RunSync
|
@RunSync
|
||||||
async def complete_rm(self, text, line, begidx, endidx):
|
async def complete_rm(self, text, line, begidx, endidx):
|
||||||
return await self.PathCompleter(text, line, begidx, endidx, filterFiles = False)
|
return await self._path_completer(text, line, begidx, endidx, False)
|
||||||
|
|
||||||
|
rm_parser = cmd2.Cmd2ArgumentParser()
|
||||||
|
rm_parser.add_argument("paths", help="paths", default="", nargs="+", type=RunSync(Client.PathToNode))
|
||||||
@RunSync
|
@RunSync
|
||||||
@ProvideDecoratorSelfArgs(cmd2.with_argparser, AddPathParser(ParserProvider, "+"))
|
@cmd2.with_argparser(rm_parser)
|
||||||
async def do_rm(self, args):
|
async def do_rm(self, args):
|
||||||
"""
|
"""
|
||||||
Remove a file or directory
|
Remove a file or directory
|
||||||
"""
|
"""
|
||||||
await self.client.Delete(args.path)
|
await Client.Delete(args.paths)
|
||||||
|
|
||||||
@RunSync
|
@RunSync
|
||||||
async def complete_mkdir(self, text, line, begidx, endidx):
|
async def complete_mkdir(self, text, line, begidx, endidx):
|
||||||
return await self.PathCompleter(text, line, begidx, endidx, filterFiles = True)
|
return await self._path_completer(text, line, begidx, endidx, True)
|
||||||
|
|
||||||
|
mkdir_parser = cmd2.Cmd2ArgumentParser()
|
||||||
|
mkdir_parser.add_argument("path_and_son", help="path and son", default="", nargs="?", type=RunSync(Client.PathToFatherNodeAndNodeName))
|
||||||
@RunSync
|
@RunSync
|
||||||
@ProvideDecoratorSelfArgs(cmd2.with_argparser, AddFatherAndSonParser(ParserProvider))
|
@cmd2.with_argparser(mkdir_parser)
|
||||||
async def do_mkdir(self, args):
|
async def do_mkdir(self, args):
|
||||||
"""
|
"""
|
||||||
Create a directory
|
Create a directory
|
||||||
"""
|
"""
|
||||||
father, sonName = args.path
|
father, sonName = args.path_and_son
|
||||||
if not IsDir(father) or sonName == "" or sonName == None:
|
if not IsDir(father) or sonName == "" or sonName == None:
|
||||||
await self.aoutput("Invalid path")
|
await self.AsyncPrint("Invalid path")
|
||||||
return
|
return
|
||||||
child = self.client.FindChildInDirByName(father, sonName)
|
child = Client.FindChildInDirByName(father, sonName)
|
||||||
if child is not None:
|
if child is not None:
|
||||||
await self.aoutput("Path already exists")
|
await self.AsyncPrint("Path already exists")
|
||||||
return
|
return
|
||||||
await self.client.MakeDir(father, sonName)
|
await Client.MakeDir(father, sonName)
|
||||||
|
|
||||||
|
download_parser = cmd2.Cmd2ArgumentParser()
|
||||||
|
download_parser.add_argument("url", help="url")
|
||||||
|
download_parser.add_argument("path", help="path", default="", nargs="?", type=RunSync(Client.PathToNode))
|
||||||
@RunSync
|
@RunSync
|
||||||
@ProvideDecoratorSelfArgs(cmd2.with_argparser, AddPathParser(AddUrlParser(ParserProvider)))
|
@cmd2.with_argparser(download_parser)
|
||||||
async def do_download(self, args):
|
async def do_download(self, args):
|
||||||
"""
|
"""
|
||||||
Download a file
|
Download a file
|
||||||
"""
|
"""
|
||||||
node = args.path
|
node = args.path
|
||||||
if not IsDir(node):
|
if not IsDir(node):
|
||||||
await self.aoutput("Invalid directory")
|
await self.AsyncPrint("Invalid directory")
|
||||||
return
|
return
|
||||||
await self.client.Download(args.url, node)
|
await Client.Download(args.url, node)
|
||||||
|
|
||||||
|
async def mainLoop():
|
||||||
|
global MainLoop, Client
|
||||||
|
MainLoop = asyncio.get_running_loop()
|
||||||
|
|
||||||
|
console = Console()
|
||||||
|
console.preloop()
|
||||||
|
try:
|
||||||
|
stop = False
|
||||||
|
while not stop:
|
||||||
|
line = await console.AsyncInput(console.prompt)
|
||||||
|
stop = console.onecmd_plus_hooks(line)
|
||||||
|
finally:
|
||||||
|
console.postloop()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
nest_asyncio.apply()
|
nest_asyncio.apply()
|
||||||
prog = PikpakConsole()
|
asyncio.run(mainLoop())
|
||||||
asyncio.run(prog.Run())
|
|
||||||
|
18
pikpakFs.py
18
pikpakFs.py
@ -1,13 +1,12 @@
|
|||||||
import httpx
|
import httpx
|
||||||
from hashlib import md5
|
|
||||||
from pikpakapi import PikPakApi
|
from pikpakapi import PikPakApi
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import json
|
import json
|
||||||
import re
|
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
|
||||||
class PKTaskStatus(Enum):
|
class PKTaskStatus(Enum):
|
||||||
@ -24,6 +23,7 @@ class PkTask:
|
|||||||
self.taskId = id
|
self.taskId = id
|
||||||
self.status = status
|
self.status = status
|
||||||
|
|
||||||
|
self.runningTask : asyncio.Task = None
|
||||||
self.toDirId = toDirId
|
self.toDirId = toDirId
|
||||||
self.torrent = torrent
|
self.torrent = torrent
|
||||||
self.url = None
|
self.url = None
|
||||||
@ -86,9 +86,14 @@ class PkToken:
|
|||||||
return cls(**data)
|
return cls(**data)
|
||||||
|
|
||||||
class PKFs:
|
class PKFs:
|
||||||
async def RunTasks(self):
|
async def _task_worker(self, task : PkTask):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def RunTask(self, task : PkTask):
|
||||||
|
self.tasks.append(task)
|
||||||
|
if task.runningTask is None or task.runningTask.done():
|
||||||
|
task.runningTask = asyncio.create_task(self._task_worker(task))
|
||||||
|
|
||||||
def __init__(self, loginCachePath : str = None, proxy : str = None, rootId = None):
|
def __init__(self, loginCachePath : str = None, proxy : str = None, rootId = None):
|
||||||
self.nodes : Dict[str, FsNode] = {}
|
self.nodes : Dict[str, FsNode] = {}
|
||||||
self.root = DirNode(rootId, "", None)
|
self.root = DirNode(rootId, "", None)
|
||||||
@ -275,9 +280,14 @@ class PKFs:
|
|||||||
|
|
||||||
async def Download(self, url : str, dirNode : DirNode) -> PkTask :
|
async def Download(self, url : str, dirNode : DirNode) -> PkTask :
|
||||||
task = PkTask(url, dirNode.id)
|
task = PkTask(url, dirNode.id)
|
||||||
self.tasks.append(task)
|
self.RunTask(task)
|
||||||
return task
|
return task
|
||||||
|
|
||||||
|
async def QueryTasks(self, filterByStatus : PKTaskStatus = None) -> list[PkTask]:
|
||||||
|
if filterByStatus is None:
|
||||||
|
return self.tasks
|
||||||
|
return [task for task in self.tasks if task.status == filterByStatus]
|
||||||
|
|
||||||
async def Delete(self, nodes : list[FsNode]) -> None:
|
async def Delete(self, nodes : list[FsNode]) -> None:
|
||||||
nodeIds = [node.id for node in nodes]
|
nodeIds = [node.id for node in nodes]
|
||||||
await self.client.delete_to_trash(nodeIds)
|
await self.client.delete_to_trash(nodeIds)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user