def get_file_list(self, folder_id=-1) -> FileList: """获取文件列表""" page = 1 file_list = FileList() while True: post_data = {'task': 5, 'folder_id': folder_id, 'pg': page} resp = self._post(self._doupload_url, post_data) if not resp: # 网络异常,重试 continue else: resp = resp.json() if resp["info"] == 0: break # 已经拿到了全部的文件信息 else: page += 1 # 下一页 # 文件信息处理 for file in resp["text"]: file_list.append(File( id=int(file['id']), name=file['name_all'], time=file['time'], # 上传时间 size=file['size'], # 文件大小 type=file['name_all'].split('.')[-1], # 文件类型 downs=int(file['downs']), # 下载次数 has_pwd=True if int(file['onof']) == 1 else False, # 是否存在提取码 has_des=True if int(file['is_des']) == 1 else False # 是否存在描述 )) return file_list
def get_rec_file_list(self, folder_id=-1) -> FileList: """获取回收站文件列表""" if folder_id == -1: # 列出回收站根目录文件 # 回收站文件夹中的文件也会显示在根目录 html = self._get(self._mydisk_url, params={ 'item': 'recycle', 'action': 'files' }) if not html: return FileList() html = remove_notes(html.text) files = re.findall( r'fl_sel_ids[^\n]+value="(\d+)".+?filetype/(\w+)\.gif.+?/>\s?(.+?)(?:\.{3})?</a>.+?<td.+?>([\d\-]+?)</td>', html, re.DOTALL) file_list = FileList() file_name_list = [] counter = 1 for fid, ftype, name, time in sorted(files, key=lambda x: x[2]): if not name.endswith(ftype): # 防止文件名太长导致丢失了文件后缀 name = name + '.' + ftype if name in file_name_list: # 防止长文件名前 17:34 个字符相同重名 counter += 1 name = f'{name}({counter})' else: counter = 1 file_name_list.append(name) file_list.append( RecFile(name, int(fid), ftype, size='', time=time)) return file_list else: # 列出回收站中文件夹内的文件,信息只有部分文件名和文件大小 para = { 'item': 'recycle', 'action': 'folder_restore', 'folder_id': folder_id } html = self._get(self._mydisk_url, params=para) if not html or '此文件夹没有包含文件' in html.text: return FileList() html = remove_notes(html.text) files = re.findall( r'com/(\d+?)".+?filetype/(\w+)\.gif.+?/> (.+?)(?:\.{3})?</a> <font color="#CCCCCC">\((.+?)\)</font>', html) file_list = FileList() file_name_list = [] counter = 1 for fid, ftype, name, size in sorted(files, key=lambda x: x[2]): if not name.endswith(ftype): # 防止文件名太长丢失后缀 name = name + '.' + ftype if name in file_name_list: counter += 1 name = f'{name}({counter})' # 防止文件名太长且前17个字符重复 else: counter = 1 file_name_list.append(name) file_list.append( RecFile(name, int(fid), ftype, size=size, time='')) return file_list
def __init__(self): self._prompt = '> ' self._disk = LanZouCloud() self._dir_list = FolderList() self._file_list = FileList() self._path_list = FolderList() self._parent_id = -1 self._parent_name = '' self._work_name = '' self._work_id = -1 self._last_work_id = -1 self._reader_mode = config.reader_mode self._disk.set_max_size(config.max_size) self._is_login = False
def __init__(self): self._prompt = '> ' self._disk = LanZouCloud() self._task_mgr = global_task_mgr self._dir_list = FolderList() self._file_list = FileList() self._path_list = FolderList() self._parent_id = -1 self._parent_name = '' self._work_name = '' self._work_id = -1 self._last_work_id = -1 self._reader_mode = config.reader_mode self._disk.set_max_size(config.max_size) self._disk.set_captcha_handler(captcha_handler)
def __init__(self): self._prompt = '> ' self._disk = LanZouCloud() # self._disk.ignore_limits() self._task_mgr = global_task_mgr self._dir_list = FolderList() self._file_list = FileList() self._path_list = FolderList() self._parent_id = -1 self._parent_name = '' self._work_name = '' self._work_id = -1 self._last_work_id = -1 self._reader_mode = config.reader_mode self._default_dir_pwd = config.default_dir_pwd self._disk.set_max_size(config.max_size) self._disk.set_upload_delay(config.upload_delay)
def get_rec_all(self): """获取整理后回收站的所有信息""" root_files = self.get_rec_file_list() # 回收站根目录文件列表 folder_list = FolderList() # 保存整理后的文件夹列表 for folder in self.get_rec_dir_list(): # 遍历所有子文件夹 this_folder = RecFolder(folder.name, folder.id, folder.size, folder.time, FileList()) for file in self.get_rec_file_list( folder.id): # 文件夹内的文件属性: name,id,type,size if root_files.find_by_id(file.id): # 根目录存在同名文件 file_time = root_files.pop_by_id( file.id).time # 从根目录删除, time 信息用来补充文件夹中的文件 file = file._replace( time=file_time) # 不能直接更新 namedtuple, 需要 _replace this_folder.files.append(file) else: # 根目录没有同名文件(用户手动删了),文件还在文件夹中,只是根目录不显示,time 信息无法补全了 file = file._replace(time=folder.time) # 那就设置时间为文件夹的创建时间 this_folder.files.append(file) folder_list.append(this_folder) return root_files, folder_list
class Commander: """蓝奏网盘命令行""" def __init__(self): self._prompt = '> ' self._disk = LanZouCloud() self._dir_list = FolderList() self._file_list = FileList() self._path_list = FolderList() self._parent_id = -1 self._parent_name = '' self._work_name = '' self._work_id = -1 self._last_work_id = -1 self._reader_mode = config.reader_mode self._disk.set_max_size(config.max_size) self._is_login = False @staticmethod def clear(): clear_screen() @staticmethod def help(): print_help() @staticmethod def update(): check_update() def rmode(self): """适用于屏幕阅读器用户的显示方式""" choice = input("以适宜屏幕阅读器的方式显示(y): ") if choice and choice.lower() == 'y': config.reader_mode = True self._reader_mode = True info("已启用 Reader Mode") else: config.reader_mode = False self._reader_mode = False info("已关闭 Reader Mode") def cdrec(self): """进入回收站模式""" rec = Recovery(self._disk) rec.run() self.refresh() def refresh(self, dir_id=None): """刷新当前文件夹和路径信息""" dir_id = self._work_id if dir_id is None else dir_id self._file_list = self._disk.get_file_list(dir_id) self._dir_list = self._disk.get_dir_list(dir_id) self._path_list = self._disk.get_full_path(dir_id) self._prompt = '/'.join(self._path_list.all_name) + ' > ' self._last_work_id = self._work_id self._work_name = self._path_list[-1].name self._work_id = self._path_list[-1].id if dir_id != -1: # 如果存在上级路径 self._parent_name = self._path_list[-2].name self._parent_id = self._path_list[-2].id def login(self, username=None, password=None): """登录网盘""" if not config.cookie or self._disk.login_by_cookie( config.cookie) != LanZouCloud.SUCCESS: if username is None: username = input('输入用户名:') if password is None: password = getpass('输入密码:') code = self._disk.login(username, password) if code == LanZouCloud.NETWORK_ERROR: error("登录失败,网络连接异常") return self elif code == LanZouCloud.FAILED: error('登录失败,用户名或密码错误 :(') return self # 登录成功保存用户 cookie config.cookie = self._disk.get_cookie() self.refresh() self._is_login = True print("auth success!\n") return self def clogin(self): """使用 cookie 登录""" open_new_tab('https://pc.woozooo.com/') info("请设置 Cookie 内容:") ylogin = input("ylogin="******"phpdisk_info=") if not ylogin or not disk_info: error("请输入正确的 Cookie 信息") return None cookie = {"ylogin": str(ylogin), "phpdisk_info": disk_info} if self._disk.login_by_cookie(cookie) == LanZouCloud.SUCCESS: config.cookie = cookie self.refresh() self._is_login = True else: error("登录失败,请检查 Cookie 是否正确") def logout(self): """注销""" clear_screen() self._prompt = '> ' self._disk.logout() self._file_list.clear() self._dir_list.clear() self._path_list = FolderList() self._parent_id = -1 self._work_id = -1 self._last_work_id = -1 self._parent_name = '' self._work_name = '' self_is_login = False config.cookie = None def ls(self): """列出文件(夹)""" if self._reader_mode: # 方便屏幕阅读器阅读 for folder in self._dir_list: print(f"{folder.name}/ {folder.desc}") for file in self._file_list: print(f"{file.name} 大小:{file.size} 上传时间:{file.time}") else: # 普通用户显示方式 for folder in self._dir_list: pwd_str = '✦' if folder.has_pwd else '✧' print("#{0:<12}{1:<4}{2}{3}/".format( folder.id, pwd_str, text_align(folder.desc, 24), folder.name)) for file in self._file_list: pwd_str = '✦' if file.has_pwd else '✧' print("#{0:<12}{1:<4}{2:<14}{3:<10}{4}".format( file.id, pwd_str, file.time, file.size, file.name)) def cd(self, dir_name): """切换工作目录""" if not dir_name: info('cd .. 返回上级路径, cd - 返回上次路径, cd / 返回根目录') elif dir_name == '..': self.refresh(self._parent_id) elif dir_name == '/': self.refresh(-1) elif dir_name == '-': self.refresh(self._last_work_id) elif dir_name == '.': pass elif folder := self._dir_list.find_by_name(dir_name): self.refresh(folder.id) else:
def get_folder_info_by_url(self, share_url, dir_pwd=''): """获取文件夹里所有文件的信息""" if is_file_url(share_url): return FolderDetail(LanZouCloud.URL_INVALID) try: html = requests.get(share_url, headers=self._headers).text except requests.RequestException: return FolderDetail(LanZouCloud.NETWORK_ERROR) if '文件不存在' in html: return FolderDetail(LanZouCloud.FILE_CANCELLED) if '请输入密码' in html and len(dir_pwd) == 0: return FolderDetail(LanZouCloud.LACK_PASSWORD) try: # 获取文件需要的参数 html = remove_notes(html) lx = re.findall(r"'lx':'?(\d)'?,", html)[0] t = re.findall(r"var [0-9a-z]{6} = '(\d{10})';", html)[0] k = re.findall(r"var [0-9a-z]{6} = '([0-9a-z]{15,})';", html)[0] # 文件夹的信息 folder_id = re.findall(r"'fid':'?(\d+)'?,", html)[0] folder_name = re.findall(r"var.+?='(.+?)';\n.+document.title", html)[0] folder_time = re.findall(r'class="rets">([\d\-]+?)<a', html)[0] # 日期不全 %m-%d folder_desc = re.findall(r'id="filename">(.+?)</span>', html) # 无描述时无法完成匹配 folder_desc = folder_desc[0] if len(folder_desc) == 1 else '' except IndexError: return FolderDetail(LanZouCloud.FAILED) page = 1 files = FileList() while True: try: # 这里不用封装好的 post 函数是为了支持未登录的用户通过 URL 下载, 无密码时设置 pwd 字段也不影响 post_data = {'lx': lx, 'pg': page, 'k': k, 't': t, 'fid': folder_id, 'pwd': dir_pwd} resp = requests.post(self._host_url + '/filemoreajax.php', data=post_data, headers=self._headers).json() except requests.RequestException: return FolderDetail(LanZouCloud.NETWORK_ERROR) if resp['zt'] == 1: # 成功获取一页文件信息 for f in resp["text"]: files.append(FileInFolder( name=f["name_all"], # 文件名 time=f["time"], # 上传时间 size=f["size"], # 文件大小 type=f["name_all"].split('.')[-1], # 文件格式 url=self._host_url + "/" + f["id"] # 文件分享链接 )) page += 1 # 下一页 continue elif resp['zt'] == 2: # 已经拿到全部的文件信息 break elif resp['zt'] == 3: # 提取码错误 return FolderDetail(LanZouCloud.PASSWORD_ERROR) elif resp["zt"] == 4: continue else: return FolderDetail(LanZouCloud.FAILED) # 其它未知错误 # 通过文件的时间信息补全文件夹的年份(如果有文件的话) if files: # 最后一个文件上传时间最早,文件夹的创建年份与其相同 folder_time = files[-1].time.split('-')[0] + '-' + folder_time else: # 可恶,没有文件,日期就设置为今年吧 folder_time = datetime.today().strftime('%Y-%m-%d') return FolderDetail(LanZouCloud.SUCCESS, FolderInfo(folder_name, folder_id, dir_pwd, folder_time, folder_desc, share_url), files)
class Commander: """蓝奏网盘命令行""" def __init__(self): self._prompt = '> ' self._disk = LanZouCloud() # self._disk.ignore_limits() self._task_mgr = global_task_mgr self._dir_list = FolderList() self._file_list = FileList() self._path_list = FolderList() self._parent_id = -1 self._parent_name = '' self._work_name = '' self._work_id = -1 self._last_work_id = -1 self._reader_mode = config.reader_mode self._default_dir_pwd = config.default_dir_pwd self._disk.set_max_size(config.max_size) self._disk.set_upload_delay(config.upload_delay) @staticmethod def clear(): clear_screen() @staticmethod def help(): print_help() @staticmethod def update(): check_update() def bye(self): if self._task_mgr.has_alive_task(): info(f"有任务在后台运行, 退出请直接关闭窗口") else: exit_cmd(0) def rmode(self): """适用于屏幕阅读器用户的显示方式""" choice = input("以适宜屏幕阅读器的方式显示(y): ") if choice and choice.lower() == 'y': config.reader_mode = True self._reader_mode = True info("已启用 Reader Mode") else: config.reader_mode = False self._reader_mode = False info("已关闭 Reader Mode") def cdrec(self): """进入回收站模式""" rec = Recovery(self._disk) rec.run() self.refresh() def xghost(self): """扫描并删除幽灵文件夹""" choice = input("需要清理幽灵文件夹吗(y): ") if choice and choice.lower() == 'y': self._disk.clean_ghost_folders() info("清理已完成") else: info("清理操作已取消") def refresh(self, dir_id=None): """刷新当前文件夹和路径信息""" dir_id = self._work_id if dir_id is None else dir_id self._file_list = self._disk.get_file_list(dir_id) self._dir_list = self._disk.get_dir_list(dir_id) self._path_list = self._disk.get_full_path(dir_id) self._prompt = '/'.join(self._path_list.all_name) + ' > ' self._last_work_id = self._work_id self._work_name = self._path_list[-1].name self._work_id = self._path_list[-1].id if dir_id != -1: # 如果存在上级路径 self._parent_name = self._path_list[-2].name self._parent_id = self._path_list[-2].id def login(self): """使用 cookie 登录""" if not config.cookie or self._disk.login_by_cookie( config.cookie) != LanZouCloud.SUCCESS: open_new_tab('https://pc.woozooo.com/') info("请设置 Cookie 内容:") ylogin = input("ylogin="******"phpdisk_info=") if not ylogin or not disk_info: error("请输入正确的 Cookie 信息") return None cookie = {"ylogin": str(ylogin), "phpdisk_info": disk_info} if self._disk.login_by_cookie(cookie) == LanZouCloud.SUCCESS: config.cookie = cookie else: error("登录失败,请检查 Cookie 是否正确") self.refresh() def logout(self): """注销""" clear_screen() self._prompt = '> ' self._disk.logout() self._file_list.clear() self._dir_list.clear() self._path_list = FolderList() self._parent_id = -1 self._work_id = -1 self._last_work_id = -1 self._parent_name = '' self._work_name = '' config.cookie = None def ls(self): """列出文件(夹)""" if self._reader_mode: # 方便屏幕阅读器阅读 for folder in self._dir_list: pwd_str = '有提取码' if folder.has_pwd else '' print(f"{folder.name}/ {folder.desc} {pwd_str}") for file in self._file_list: pwd_str = '有提取码' if file.has_pwd else '' print( f"{file.name} 大小:{file.size} 上传时间:{file.time} 下载次数:{file.downs} {pwd_str}" ) else: # 普通用户显示方式 for folder in self._dir_list: pwd_str = '✦' if folder.has_pwd else '✧' print("#{0:<12}{1:<4}{2}{3}/".format( folder.id, pwd_str, text_align(folder.desc, 28), folder.name)) for file in self._file_list: pwd_str = '✦' if file.has_pwd else '✧' print("#{0:<12}{1:<4}{2:<12}{3:>8}{4:>6} {5}".format( file.id, pwd_str, file.time, file.size, file.downs, file.name)) def cd(self, dir_name): """切换工作目录""" if not dir_name: info('cd .. 返回上级路径, cd - 返回上次路径, cd / 返回根目录') elif dir_name == '..': self.refresh(self._parent_id) elif dir_name == '/': self.refresh(-1) elif dir_name == '-': self.refresh(self._last_work_id) elif dir_name == '.': pass elif folder := self._dir_list.find_by_name(dir_name): self.refresh(folder.id) else:
class Commander: """蓝奏网盘命令行""" def __init__(self): self._prompt = '> ' self._disk = LanZouCloud() self._is_login = False # self._disk.ignore_limits() self._task_mgr = global_task_mgr self._dir_list = FolderList() self._file_list = FileList() self._path_list = FolderList() self._parent_id = -1 self._parent_name = '' self._work_name = '' self._work_id = -1 self._last_work_id = -1 self._reader_mode = config.reader_mode self._default_dir_pwd = config.default_dir_pwd self._disk.set_max_size(config.max_size) self._disk.set_upload_delay(config.upload_delay) @staticmethod def clear(): clear_screen() @staticmethod def help(): print_help() @staticmethod def update(): check_update() def bye(self): if self._task_mgr.has_alive_task(): info(f"有任务在后台运行, 退出请直接关闭窗口") else: exit_cmd(0) def rmode(self): """适用于屏幕阅读器用户的显示方式""" choice = input("以适宜屏幕阅读器的方式显示(y): ") if choice and choice.lower() == 'y': config.reader_mode = True self._reader_mode = True info("已启用 Reader Mode") else: config.reader_mode = False self._reader_mode = False info("已关闭 Reader Mode") @require_login def cdrec(self): """进入回收站模式""" rec = Recovery(self._disk) rec.run() self.refresh() @require_login def xghost(self): """扫描并删除幽灵文件夹""" choice = input("需要清理幽灵文件夹吗(y): ") if choice and choice.lower() == 'y': self._disk.clean_ghost_folders() info("清理已完成") else: info("清理操作已取消") @require_login def refresh(self, dir_id=None): """刷新当前文件夹和路径信息""" dir_id = self._work_id if dir_id is None else dir_id self._file_list = self._disk.get_file_list(dir_id) self._dir_list = self._disk.get_dir_list(dir_id) self._path_list = self._disk.get_full_path(dir_id) self._prompt = '/'.join(self._path_list.all_name) + ' > ' self._last_work_id = self._work_id self._work_name = self._path_list[-1].name self._work_id = self._path_list[-1].id if dir_id != -1: # 如果存在上级路径 self._parent_name = self._path_list[-2].name self._parent_id = self._path_list[-2].id def login(self): """使用 cookie 登录""" if config.cookie and self._disk.login_by_cookie( config.cookie) == LanZouCloud.SUCCESS: self._is_login = True self.refresh() return auto = input("自动读取浏览器 Cookie 登录(y): ") or "y" if auto != "y": info("请手动设置 Cookie 内容:") ylogin = input("ylogin: "******"" disk_info = input("phpdisk_info: ") or "" cookie = {"ylogin": str(ylogin), "phpdisk_info": disk_info} if not ylogin or not disk_info: error("请输入正确的 Cookie 信息") return else: cookie, browser = load_with_keys('.woozooo.com', ['ylogin', 'phpdisk_info']) if cookie: print() info(f"从 {browser} 读取用户 Cookie 成功") else: info("请在浏览器端登录账号") open_new_tab('https://pc.woozooo.com/') info("浏览器可能等待几秒才将数据写入磁盘, 请稍等") counter = 0 while not cookie: sleep(1) counter += 1 print('.', end='', flush=True) cookie, browser = load_with_keys( '.woozooo.com', ['ylogin', 'phpdisk_info']) if cookie: print() info(f"从 {browser} 读取用户 Cookie 成功") break if counter == 10: # 读取超时 ctn = input("\n暂未读取到浏览器数据, 继续扫描(y) :") or "y" if ctn == "y": counter = 0 continue else: error("自动读取 Cookie 失败") return # 登录蓝奏云 if self._disk.login_by_cookie(cookie) == LanZouCloud.SUCCESS: config.cookie = cookie self._is_login = True self.refresh() else: error("登录失败,请检查 Cookie 是否正确") @require_login def logout(self): """注销""" clear_screen() self._prompt = '> ' self._disk.logout() self._is_login = False self._file_list.clear() self._dir_list.clear() self._path_list = FolderList() self._parent_id = -1 self._work_id = -1 self._last_work_id = -1 self._parent_name = '' self._work_name = '' config.cookie = None info("本地 Cookie 已清除") @require_login def ls(self): """列出文件(夹)""" if self._reader_mode: # 方便屏幕阅读器阅读 for folder in self._dir_list: pwd_str = '有提取码' if folder.has_pwd else '' print(f"{folder.name}/ {folder.desc} {pwd_str}") for file in self._file_list: pwd_str = '有提取码' if file.has_pwd else '' print( f"{file.name} 大小:{file.size} 上传时间:{file.time} 下载次数:{file.downs} {pwd_str}" ) else: # 普通用户显示方式 for folder in self._dir_list: pwd_str = '◆' if folder.has_pwd else '◇' print("#{0:<12}{1:<2}{2}{3}/".format( folder.id, pwd_str, text_align(folder.desc, 28), folder.name)) for file in self._file_list: pwd_str = '◆' if file.has_pwd else '◇' print("#{0:<12}{1:<2}{2:<12}{3:>8}{4:>6}↓ {5}".format( file.id, pwd_str, file.time, file.size, file.downs, file.name)) @require_login def cd(self, dir_name): """切换工作目录""" if not dir_name: info('cd .. 返回上级路径, cd - 返回上次路径, cd / 返回根目录') elif dir_name == '..': self.refresh(self._parent_id) elif dir_name == '/': self.refresh(-1) elif dir_name == '-': self.refresh(self._last_work_id) elif dir_name == '.': pass elif folder := self._dir_list.find_by_name(dir_name): self.refresh(folder.id) else: