class Commander: def __init__(self): self._disk = AliyunPan() self._path_list = PathList(self._disk) self._req = Req() self._config = Config() self._task_config = Config(ROOT_DIR / Path('tasks.yaml')) self._share_link = 'aliyunpan://' self._print = Printer() GLOBAL_VAR.tasks = self._task_config.read() GLOBAL_VAR.txt = '' def __del__(self): self._task_config.write(GLOBAL_VAR.tasks) def init(self, config_file='~/.config/aliyunpan.yaml', refresh_token=None, username=None, password=None, depth=3): self._path_list.depth = depth specify_conf_file = os.environ.get("ALIYUNPAN_CONF", "") config_file = list( filter( lambda x: Path(x).is_file(), map(lambda x: Path(x).expanduser(), [specify_conf_file, config_file]))) if refresh_token: if not len(refresh_token) == 32: raise InvalidRefreshToken self._disk.refresh_token = refresh_token elif username: if not password: raise InvalidPassword if not self._disk.login(username, password): raise LoginFailed elif config_file: self._config.config_file = config_file[0] refresh_token = self._config.get('refresh_token') username = self._config.get('username') password = self._config.get('password') if refresh_token: if not len(refresh_token) == 32: raise InvalidRefreshToken self._disk.refresh_token = refresh_token elif username: if not password: raise InvalidPassword if not self._disk.login(username, password): raise LoginFailed else: raise InvalidConfiguration else: raise ConfigurationFileNotFoundError def ls(self, path, l): for i in self._path_list.get_path_list(path, update=False): if l: if i.type: print(str_of_size(i.size), time.strftime('%d %b %H:%M', i.ctime), i.id, i.name) else: print('-', time.strftime('%d %b %H:%M', i.ctime), i.id, i.name) else: print(i.name, end='\t') def tree(self, path='root'): return self._path_list.tree(path) def rm(self, path): file_id = self._path_list.get_path_fid(path, update=False) if not file_id: raise FileNotFoundError(path) file_id_ = self._disk.delete_file(file_id) if file_id_ == file_id: self._path_list._tree.remove_node(file_id) self._print.remove_info(path, status=False) return file_id_ def mv(self, path, target_path): file_id = self._path_list.get_path_fid(path, update=False) _ = self._disk.move_file( self._path_list.get_path_fid(path, update=False), self._path_list.get_path_fid(target_path, update=False)) if _ and file_id: self._print.move_info(path, target_path, status=True) self._path_list._tree.remove_node(file_id) self._path_list.update_path_list(Path(target_path) / path, is_fid=False) else: self._print.move_info(path, target_path, status=False) return _ def mkdir(self, path): file_id_list = [] path = PurePosixPath(Path(path).as_posix()) if str(path) == 'root': return file_id_list file_id = self._path_list.get_path_fid(path, update=False) if file_id and file_id != 'root': return file_id_list parent_file_id = self._path_list.get_path_fid(path.parent, update=False) if not parent_file_id: file_id_list.extend(self.mkdir(path.parent)) parent_file_id, _ = file_id_list[-1] r = self._disk.create_file(path.name, parent_file_id) try: file_id = r.json()['file_id'] except KeyError: logger.debug(r.json()['message']) return False if file_id: self._print.mkdir_info(path, status=True) self._path_list._tree.create_node(tag=path.name, identifier=file_id, parent=parent_file_id) file_id_list.append((file_id, path)) return file_id_list def upload(self, path, upload_path='root', timeout=10.0, retry=3, force=False, share=False, chunk_size=None, c=False): if isinstance(path, str): path_list = (path, ) else: path_list = path result_list = [] for path in path_list: if path: if self._share_link in path: share_list = [] if share: share_info = parse_share_url(path) file = self._path_list.get_path_node(share_info.name, update=False) if file and not file.data.type: path = path.replace( share_info.name, share_info.name + str(int(time.time()))) share_info = parse_share_url(path) if not self._path_list.get_path_fid(share_info.name, update=False): self.upload_share(share_info) self._path_list.update_path_list(depth=0) if share_info.path == 'root': path_ = share_info.name else: path_ = share_info.path / share_info.name for line in self.cat(path_).split('\n'): if line.startswith(self._share_link): share_list.append(parse_share_url(line)) self.rm(path_) if upload_path == 'root': upload_path = share_info.path else: upload_path /= share_info.path else: share_list = parse_share_url(path) return self.upload_share(share_list, upload_path, force) path = Path(path) if path.is_file(): if share: share_list = [] with open(path, 'r', encoding='utf-8') as f: while True: line = f.readline() if not line: break if line.startswith(self._share_link): share_list.append(parse_share_url(line)) return self.upload_share(share_list, upload_path, force) else: try: file_id = self._disk.upload_file( parent_file_id=self._path_list.get_path_fid( upload_path, update=False), path=path, upload_timeout=timeout, retry_num=retry, force=force, chunk_size=chunk_size, c=c) except KeyboardInterrupt: self.__del__() raise result_list.append(file_id) elif path.is_dir(): if upload_path == 'root': upload_path = '/' upload_path = Path(upload_path) upload_file_list = self.upload_dir(path, upload_path) for file in upload_file_list: try: result = self._disk.upload_file( parent_file_id=self._path_list.get_path_fid( file[0], update=False), path=file[1], upload_timeout=timeout, retry_num=retry, force=force, chunk_size=chunk_size, c=c) except KeyboardInterrupt: self.__del__() raise result_list.append(result) else: raise FileNotFoundError for file_hash, path in GLOBAL_VAR.file_set: if file_hash in GLOBAL_VAR.tasks and GLOBAL_VAR.tasks[ file_hash].upload_time: if isinstance(GLOBAL_VAR.tasks[file_hash].path, str): del GLOBAL_VAR.tasks[file_hash] else: try: GLOBAL_VAR.tasks[file_hash].path.remove(path) except ValueError: pass if not GLOBAL_VAR.tasks[file_hash].path: del GLOBAL_VAR.tasks[file_hash] if len(result_list) == 1: result_list = result_list[0] return result_list def upload_dir(self, path, upload_path): upload_path = upload_path / path.name if not self._path_list.get_path_fid(upload_path, update=False): self.mkdir(upload_path) upload_file_list = [] for file in path.iterdir(): if file.is_dir(): upload_file_list.extend(self.upload_dir(file, upload_path)) else: upload_file_list.append([upload_path, file]) return upload_file_list def upload_share(self, share_info_list: ShareInfo, upload_path='root', force=False): if not isinstance(share_info_list, list): share_info_list = [share_info_list] if upload_path == 'root': upload_path = '' upload_path = PurePosixPath(Path(upload_path).as_posix()) folder_list = [] file_list = [] for share_info in share_info_list: file_id_list = self.mkdir(upload_path / share_info.path) if file_id_list: for file_id, path in file_id_list: folder_list.append((file_id, upload_path / path)) folder_list = tuple(set(folder_list)) for share_info in share_info_list: path = share_info.path if not str(upload_path) and str(path) == 'root': path = Path('') parent_file_id = self._path_list.get_path_fid(upload_path / path) result = self._disk.save_share_link(share_info.name, share_info.content_hash, share_info.content_hash_name, share_info.size, parent_file_id, force) p = PurePosixPath( Path(upload_path / path / share_info.name).as_posix()) file_list.append((result, p)) if result: self._print.upload_info(p, status=True, rapid_upload=True) else: self._print.upload_info(p, status=False) return folder_list, file_list def download(self, path, save_path=None, single_file=False, share=False): if not save_path: save_path = Path().cwd() save_path = Path(save_path) if isinstance(path, str): path_list = (path, ) else: path_list = path for path in path_list: if str(path).startswith(self._share_link) or share: folder_list, file_list = self.upload(path, share=share) folder_list = sorted(folder_list, key=lambda x: x[1]) for file_id, path in folder_list: p = save_path / path try: p.mkdir(parents=True) self._print.mkdir_info(p, status=True) except FileExistsError: pass for file_id, path in file_list: self.download_file(save_path / path, self._disk.get_download_url(file_id)) for file_id, path in file_list: self._path_list.update_path_list(path.parent, depth=0, is_fid=False) try: self.rm(path) except FileNotFoundError: pass for file_id, path in folder_list: try: self.rm(path) except FileNotFoundError: pass continue if isinstance(path, (Path, PurePosixPath, str)): path = PurePosixPath(Path(path).as_posix()) node = self._path_list.get_path_node(path, update=False) if not node: raise FileNotFoundError(path) file_node = node.data self._path_list.update_path_list(file_node.id) if file_node.type: single_file = True else: file_node, path = path, path.name p = save_path / path if file_node.type: if single_file: p = save_path / p.name self._print.download_info(p) self.download_file(p, file_node.download_url) else: self.download(self._path_list.get_fid_list(file_node.id), save_path / p.name) def download_file(self, path, url): try: path.parent.mkdir(parents=True) self._print.mkdir_info(path.parent, status=True) except FileExistsError: pass if path.exists(): temp_size = path.stat().st_size else: temp_size = 0 headers = {'Range': 'bytes=%d-' % temp_size} try: r = self._req.get(url, headers=headers, stream=True) file_size = int(r.headers['Content-Length']) if temp_size == file_size and file_size != 0: self._print.download_info(path, status=True) return True elif temp_size > file_size: mode = 'wb' temp_size = 0 else: mode = 'ab' download_bar = DownloadBar(size=file_size) download_bar.update(refresh_line=False) with path.open(mode) as f: for chunk in r.iter_content(chunk_size=1024): k = temp_size / file_size download_bar.update(ratio=k, refresh_line=True) if chunk: temp_size += len(chunk) f.write(chunk) except requests.exceptions.RequestException: self._print.download_info(path, status=False) return False self._print.download_info(path, status=True, t=download_bar.time, average_speed=download_bar.average_speed, refresh_line=True) return True def cat(self, path, encoding='utf-8'): file_node = self._path_list.get_path_node(path, update=False) if not file_node: raise FileNotFoundError(path) file = file_node.data self._path_list.update_path_list(file.id) r = self._req.get(file.download_url) r.encoding = encoding return r.text def share(self, path, file_id, expire_sec, share_link, download_link, save): def share_(path, file_id, parent_file=''): if path: file_node = self._path_list.get_path_node(path, update=False) if not file_node: raise FileNotFoundError(path) file = file_node.data self._path_list.update_path_list(file.id) else: file = self._path_list._tree.get_node(file_id).data if file.type: share_txt = file.name.center(50, '-') + '\n' if download_link: share_txt += '下载链接'.center(50, '*') + '\n' url = self._disk.get_download_url(file.id, expire_sec) share_txt += url + '\n\n' if share_link: share_txt += '分享链接'.center(50, '*') + '\n' url = f'{self._share_link}{file.name}|{file.content_hash}|{file.size}|{parent_file or "root"}' share_txt += url + '\n' share_txt += '导入链接'.center(50, '*') + '\n' share_txt += f'python main.py upload "{url}"' + '\n\n' print(share_txt) GLOBAL_VAR.txt += share_txt else: for i in self._path_list.get_fid_list(file.id): share_(path=None, file_id=i.id, parent_file=Path(parent_file) / file.name) GLOBAL_VAR.txt += '*' * 50 + '\n' GLOBAL_VAR.txt += '项目地址: https://github.com/wxy1343/aliyunpan' + '\n' GLOBAL_VAR.txt += '*' * 50 + '\n\n' share_(path, file_id) if save: file_name = Path(path).name + f'{int(time.time())}.txt' with open(file_name, 'w', encoding='utf-8') as f: f.write(GLOBAL_VAR.txt) print('文件导入'.center(50, '*')) print(f'python main.py upload -s {file_name}') print('链接导入'.center(50, '*')) file_id = self.upload(file_name) print() if file_id: self._path_list.update_path_list(depth=1) file = self._path_list._tree.get_node(file_id).data url = f'{self._share_link}{Path(path).name}|{file.content_hash}|{file.size}|root' print(f'python main.py upload -s "{url}"')
class Commander: def __init__(self, init=True, *args, **kwargs): self.match = False self.whitelist = False self._disk = AliyunPan() self._path_list = PathList(self._disk) self._req = Req(self._disk) self._config = Config() self._task_config = Config(ROOT_DIR / Path('tasks.yaml')) self._share_link = 'aliyunpan://' self._print = Printer() self._host_url = 'https://www.aliyundrive.com/' self._aria2 = None self.filter_set = set() self._config_set = { '~/.config/aliyunpan.yaml', '.config/aliyunpan.yaml', '~/aliyunpan.yaml', 'aliyunpan.yaml', os.environ.get('ALIYUNPAN_CONF', '') } GLOBAL_VAR.tasks = self._task_config.read() GLOBAL_VAR.txt = '' if init: self.init(*args, **kwargs) def __del__(self): self._task_config.write(GLOBAL_VAR.tasks) if self._disk.refresh_token: try: self._config.update('refresh_token', self._disk.refresh_token) except AttributeError: pass def init(self, config_file=None, refresh_token=None, username=None, password=None, depth=3, timeout=None, drive_id=None, album=False, share_id='', share_pwd='', filter_file=None, whitelist=False, match=False): self._path_list.depth = depth self._req.timeout = timeout self._disk.drive_id = drive_id self._disk.album = album self._disk._share = Share(share_id, share_pwd) self.filter_set.update(filter_file) if filter_file else None self.whitelist = whitelist self.match = match config_file_list = list( filter(lambda x: get_real_path(x).is_file(), map(lambda x: get_real_path(x), self._config_set))) if config_file: if not get_real_path(config_file).is_file(): raise ConfigurationFileNotFoundError self._config.config_file = get_real_path(config_file) elif config_file_list and config_file_list[0]: self._config.config_file = config_file_list[0] if self._config.config_file and self._config.get('aria2'): aria2 = self._config.get('aria2') else: aria2 = {'host': 'http://localhost', 'port': 6800} if aria2: self._aria2 = self.aria2_init(**aria2) if refresh_token: if not len(refresh_token) == 32: raise InvalidRefreshToken self._disk.refresh_token = refresh_token elif username: if not password: raise InvalidPassword self._disk.login(username, password) elif config_file_list: refresh_token = self._config.get('refresh_token') username = self._config.get('username') password = self._config.get('password') if refresh_token: if not len(refresh_token) == 32: raise InvalidRefreshToken self._disk.refresh_token = refresh_token elif username: if not password: raise InvalidPassword self._disk.login(username, password) else: raise InvalidConfiguration else: raise ConfigurationFileNotFoundError def aria2_init(self, **kwargs): kwargs.setdefault('host', 'http://localhost') kwargs.setdefault('port', 6800) kwargs.setdefault('secret', '') self._aria2 = aria2p.API(aria2p.Client(**kwargs)) return self._aria2 def ls(self, path='root', l=False, query=None): if query: file_info_list = self._path_list.get_file_info( self._disk.search(query)) else: file_info_list = self._path_list.get_path_list(path, update=False) if self.filter_set: file_info_list = [ i for i in file_info_list if self.file_filter(i.name) ] for i, j in enumerate(file_info_list): if l: if j.type: print(str_of_size(j.size), time.strftime('%d %b %H:%M', j.ctime), j.id, j.name, end='') else: print('-', time.strftime('%d %b %H:%M', j.ctime), j.id, j.name, end='') if i + 1 < len(file_info_list): print() else: print(j.name, end='\t') if platform.system() != 'Windows': print() def get_path_list(self, path='root') -> List[FileInfo]: return self._path_list.get_path_list(path, update=False) def get_fid_list(self, file_id='root') -> List[FileInfo]: return self._path_list.get_fid_list(file_id, update=False) def tree(self, path='root', stdout=sys.stdout): return self._path_list.tree(path, stdout) def rm(self, path, file_id=None): if not self.file_filter(path): return False if not file_id: file_id = self._path_list.get_path_fid(path, update=False) if file_id: file_id_ = self._disk.delete_file(file_id) if file_id_ == file_id: file_id = file_id_ self._print.remove_info(path or file_id, status=True) self._path_list._tree.remove_node(file_id) self._print.print_line() else: file_id = False self._print.remove_info(path or file_id, status=False) self._print.print_line() else: raise FileNotFoundError(path or file_id) return file_id def rename(self, path, name): if not self.file_filter(path): return False file_id = self._path_list.get_path_fid(path, update=False) status = False existed = False if file_id: file_id_ = self._disk.update_file(file_id, name) if file_id_ == AliyunpanCode.existed: file_id = False existed = True elif file_id_ == file_id: file_id = file_id_ self._path_list.update_path_list( file_id=self._path_list._tree.get_node(file_id).data.pid, depth=0) status = True else: status = False self._print.rename_info(path, name=name, status=status, existed=existed) return file_id def move_by_path_list(self, path_list, target_path) -> List[File]: target_path = AliyunpanPath(target_path) parent_file_id = self._path_list.get_path_fid(target_path, update=False) parent_file_node = self._path_list._tree.get_node(parent_file_id) file_list = [] file_list_ = [] for path in path_list: path = AliyunpanPath(path) if not self.file_filter(path): continue if parent_file_id and parent_file_node: if parent_file_node.data.type: raise FileExistsError(target_path) if self._disk._share and path in ('', '/', '\\', '.', 'root', '..'): file_list.extend(self.move_share_file(path, target_path)) continue file_id = self._path_list.get_path_fid(path, update=False) file_list.append(File(file_id, path)) if file_id: file_list_.append(File(file_id, path)) elif path.parent == target_path.parent: file_id = self.rename(path, target_path.name) file_list.append(File(file_id, path)) self._print.print_line() continue elif not parent_file_id: raise FileNotFoundError(target_path) file_list.extend(self.move_by_file_id_list(file_list_, parent_file_id)) if file_list_: for file in file_list_: if file: if file.file_id: self._print.move_info(file.path, target_path, status=True) self._path_list._tree.remove_node(file.file_id) self._path_list.update_path_list(Path(target_path) / file.path.name, is_fid=False) else: self._print.move_info(file.path, target_path, status=False) self._print.print_line() return file_list def move_by_path(self, path, target_path): return self.move_by_path_list([path], target_path) def move_by_file_id_list(self, file_list, parent_file_id): return self._disk.move_file(file_list, parent_file_id) def move_share_file(self, path: str, target_path: AliyunpanPath) -> List[File]: parent_file_id = 'root' if path == '..': target_path = target_path / self._disk._share.share_id file_list = self.mkdir(target_path) if not file_list: raise CreateDirError parent_file_id = file_list[0].file_id path_list = self.get_path_list() file_list = self._disk.move_file( [File(i.id, target_path / i.name) for i in path_list], parent_file_id) for file in file_list: for path in path_list: if file.file_id == path.id: self._print.move_info(path.name, target_path, status=True) self._path_list.update_path_list(path.name, is_fid=False) self._print.print_line() return file_list def mv(self, path, target_path) -> List[File]: return self.move_by_path(path, target_path) def mkdir(self, path, name=None, parent_file_id=None) -> List[File]: file_list: List[File] = [] if not self.file_filter(path): return [] if not parent_file_id or not name: path = AliyunpanPath(path) name = path.name if str(path) == 'root': return file_list file_id = self._path_list.get_path_fid(path, update=False) if file_id and file_id != 'root': return file_list parent_file_id = self._path_list.get_path_fid(path.parent, update=False) if not parent_file_id: file_list.extend(self.mkdir(path.parent)) parent_file_id, _ = file_list[-1] r = self._disk.create_file(name, parent_file_id) try: file_id = r.json()['file_id'] except KeyError: logger.debug(r.json()['message']) return [] if file_id: self._print.mkdir_info(path, status=True) self._print.print_line() self._path_list._tree.create_node(tag=name, identifier=file_id, parent=parent_file_id, data=FileInfo( name=name, type=False, id=file_id, pid=parent_file_id)) file_list.append(File(file_id, path)) return file_list def file_filter(self, path, whitelist=None): if not path: return False if whitelist is None: whitelist = self.whitelist if isinstance(path, FileInfo): name = path.name else: name = Path(path) for pattern in self.filter_set: if re.match(pattern, str(name)): return whitelist return not whitelist def upload(self, path, upload_path='root', timeout=10.0, retry=3, force=False, share=False, chunk_size=None, c=False, ignore=False): if isinstance(path, (str, AliyunpanPath, Path)): path_list = {path} else: path_list = path if self.match: [self.filter_set.add(i) for i in path_list] if self.whitelist: path_list = set( filter( functools.partial(self.file_filter, whitelist=False), Path().iterdir())) else: path_list = set( filter(functools.partial(self.file_filter, whitelist=True), Path().iterdir())) else: path_list = filter(self.file_filter, path_list) result_list = [] for path in path_list: path: Union[str, AliyunpanPath, Path] if self._share_link in str(path): share_list = [] if share: share_info = parse_share_url(path, self._disk.access_token) file = self._path_list.get_path_node(share_info.name, update=False) if file and not file.data.type: path = path.replace( share_info.name, share_info.name + str(int(time.time()))) share_info = parse_share_url(path, self._disk.access_token) if not self._path_list.get_path_fid(share_info.name, update=False): self.upload_share(share_info) self._path_list.update_path_list(depth=0) if str(share_info.path) == 'root': path_ = share_info.name else: path_ = share_info.path / share_info.name for line in self.cat(path_).split('\n'): if line.startswith(self._share_link): share_list.append( parse_share_url(line, self._disk.access_token)) self.rm(path_) if str(upload_path) == 'root': upload_path = share_info.path else: upload_path /= share_info.path else: share_list = parse_share_url(path, self._disk.access_token) return self.upload_share(share_list, upload_path, force) path = Path(path) if path.is_file(): if share: share_list = [] with open(path, 'r', encoding='utf-8') as f: while True: line = f.readline() if not line: break if line.startswith(self._share_link): share_list.append( parse_share_url(line, self._disk.access_token)) return self.upload_share(share_list, upload_path, force) else: parent_file_id = self._path_list.get_path_fid(upload_path, update=False) if not parent_file_id: raise FileNotFoundError(upload_path) try: result = self._disk.upload_file( parent_file_id=parent_file_id, path=str(path), upload_timeout=timeout, retry_num=retry, force=force, chunk_size=chunk_size, c=c, ignore=ignore) except KeyboardInterrupt: self.__del__() raise if result: if isinstance(result, str): file_id = result else: file_info = self._path_list.get_file_info( result)[0] file_id = file_info.id self._path_list._tree.create_node( tag=file_info.name, identifier=file_info.id, parent=parent_file_id, data=file_info) result_list.append(file_id) elif path.is_dir(): if upload_path == 'root': upload_path = '/' upload_path = Path(upload_path) upload_file_list = self.upload_dir(path, upload_path) upload_file_list = [ i for i in upload_file_list if self.file_filter(i[1]) ] for file in upload_file_list: try: parent_file_id = self._path_list.get_path_fid( file[0], update=False) if not parent_file_id: raise FileNotFoundError(upload_path) result = self._disk.upload_file( parent_file_id=parent_file_id, path=file[1], upload_timeout=timeout, retry_num=retry, force=force, chunk_size=chunk_size, c=c, ignore=ignore) except KeyboardInterrupt: self.__del__() raise if result: if isinstance(result, str): file_id = result else: file_info = self._path_list.get_file_info( result)[0] file_id = file_info.id self._path_list._tree.create_node( tag=file_info.name, identifier=file_info.id, parent=parent_file_id, data=file_info) result_list.append(file_id) else: raise FileNotFoundError for file_hash, path in GLOBAL_VAR.file_set: if file_hash in GLOBAL_VAR.tasks and GLOBAL_VAR.tasks[ file_hash].upload_time: if isinstance(GLOBAL_VAR.tasks[file_hash].path, str): del GLOBAL_VAR.tasks[file_hash] else: try: GLOBAL_VAR.tasks[file_hash].path.remove(path) except ValueError: pass if not GLOBAL_VAR.tasks[file_hash].path: del GLOBAL_VAR.tasks[file_hash] return result_list def upload_dir(self, path, upload_path): upload_path = upload_path / path.name if not self._path_list.get_path_fid(upload_path, update=False): self.mkdir(upload_path) self._print.print_line() upload_file_list = [] for file in path.iterdir(): if file.is_dir(): upload_file_list.extend(self.upload_dir(file, upload_path)) else: upload_file_list.append([upload_path, file]) return upload_file_list def upload_share(self, share_info_list: List[ShareInfo], upload_path='root', force=False): if not isinstance(share_info_list, list): share_info_list = [share_info_list] if upload_path == 'root': upload_path = '' upload_path = AliyunpanPath(upload_path) folder_list = [] file_list = [] for share_info in share_info_list: path = share_info.path if str(upload_path) in ('', '.') and str(path) == 'root': path = Path('') if str(upload_path) == 'root': upload_path = AliyunpanPath() p = upload_path / path if str(p) not in ('', '.'): file_list = self.mkdir(upload_path / path) if file_list: for file_id, path in file_list: folder_list.append((file_id, upload_path / path)) folder_list = list(set(folder_list)) file_list = [] for share_info in share_info_list: share_info: ShareInfo path = share_info.path if str(upload_path) in ('', '.') and str(path) == 'root': path = Path() parent_file_id = self._path_list.get_path_fid(upload_path / path) result = self._disk.save_share_link(share_info.name, share_info.content_hash, share_info.proof_code, share_info.content_hash_name, share_info.size, parent_file_id, force) p = AliyunpanPath(upload_path / path / share_info.name) file_list.append(File(result, p)) self._print.print_line() if result: self._print.upload_info(p, status=True, rapid_upload=True) else: self._print.upload_info(p, status=False) return folder_list, file_list def download(self, path, save_path=None, single_file=False, share=False, chunk_size=None, aria2=False, first=True, **kwargs): if not chunk_size: chunk_size = 1048576 if not save_path: save_path = Path().cwd() save_path = Path(save_path) if isinstance(path, str): path_list = {path} else: path_list = path if not first: path_list = [i for i in path_list if self.file_filter(i)] kwargs.setdefault('referer', self._host_url) for path in path_list: if str(path).startswith(self._share_link) or share: folder_list, file_list = self.upload(path, share=share) folder_list = sorted(folder_list, key=lambda x: x[1]) for file_id, path in folder_list: p = save_path / path try: if not aria2: p.mkdir(parents=True) self._print.mkdir_info(p, status=True) except FileExistsError: pass for file_id, path in file_list: if aria2: kwargs.update({ 'dir': str((save_path / path).parent.absolute()), 'out': path.name }) self._aria2.add_uris( [self._disk.get_download_url(file_id)], Options(self._aria2, kwargs)) else: self.download_file( save_path / path, self._disk.get_download_url(file_id), chunk_size) for file_id, path in file_list: self._path_list.update_path_list(path.parent, depth=0, is_fid=False) try: self.rm(path) except FileNotFoundError: pass for file_id, path in folder_list: try: self.rm(path) except FileNotFoundError: pass continue if isinstance(path, (Path, PurePosixPath, AliyunpanPath, str)): path = AliyunpanPath(path) node = self._path_list.get_path_node(path, update=False) if not node: raise FileNotFoundError(path) file_node = node.data self._path_list.update_path_list(file_node.id) if file_node.type: single_file = True else: file_node, path = path, path.name p = save_path / path if file_node.type: if single_file: p = save_path / p.name if aria2: kwargs.update({ 'dir': str(p.parent.absolute()), 'out': p.name }) self._aria2.add_uris( [self._disk.get_download_url(file_node.id)], Options(self._aria2, kwargs)) self._print.download_info(p, status=True, aria2=True) else: self._print.download_info(p) self._print.print_line() self.download_file(p, file_node.download_url, chunk_size) self._print.print_line() else: self.download(self._path_list.get_fid_list(file_node.id), save_path=save_path / p.name, chunk_size=chunk_size, aria2=aria2, first=False, **kwargs) def download_file(self, path, url, chunk_size=1048576): if not self.file_filter(path): return False try: path.parent.mkdir(parents=True) self._print.print_line() self._print.mkdir_info(path.parent, status=True) self._print.print_line() except FileExistsError: pass if path.exists(): temp_size = path.stat().st_size else: temp_size = 0 headers = {'Range': 'bytes=%d-' % temp_size} try: r = self._req.get(url, headers=headers, stream=True) file_size = int(r.headers['Content-Length']) if temp_size == file_size and file_size != 0: self._print.print_line() self._print.download_info(path, status=True) return True elif temp_size > file_size: mode = 'wb' temp_size = 0 else: mode = 'ab' self._print.print_line() download_bar = DownloadBar(size=file_size) download_bar.update(refresh_line=False) with path.open(mode) as f: for chunk in r.iter_content(chunk_size=chunk_size): k = temp_size / file_size download_bar.update(ratio=k, refresh_line=True) if chunk: temp_size += len(chunk) f.write(chunk) except requests.exceptions.RequestException: self._print.refresh_line() self._print.download_info(path, status=False) self._print.print_line() return False self._print.download_info(path, status=True, t=download_bar.time, average_speed=download_bar.average_speed, refresh_line=True) self._print.print_line() return True def cat(self, path, encoding='utf-8'): file_node = self._path_list.get_path_node(path, update=False) if not file_node: raise FileNotFoundError(path) file = file_node.data self._path_list.update_path_list(file.id) r = self._req.get(file.download_url) r.encoding = encoding return r.text def share(self, path, expire_sec, share_link, download_link, save): if not self.file_filter(path): return False def share_(path, file_id, parent_file=''): if path: file_node = self._path_list.get_path_node(path, update=False) if not file_node: raise FileNotFoundError(path) file = file_node.data self._path_list.update_path_list(file.id) else: file = self._path_list._tree.get_node(file_id).data if file.type: share_txt = file.name.center(50, '-') + '\n' url = self._disk.get_download_url(file.id, expire_sec, file.category) if download_link: share_txt += '下载链接'.center(50, '*') + '\n' share_txt += url + '\n\n' if share_link: share_txt += '分享链接'.center(50, '*') + '\n' url_base64 = base64.b64encode(url.encode()).decode() url = f'{self._share_link}{file.name}|{file.content_hash}|{url_base64}|{file.size}|{parent_file or "root"}' share_txt += url + '\n' share_txt += '导入链接'.center(50, '*') + '\n' share_txt += f'python main.py upload "{url}"' + '\n\n' print(share_txt) GLOBAL_VAR.txt += share_txt else: for i in self._path_list.get_fid_list(file.id): share_(path=None, file_id=i.id, parent_file=Path(parent_file) / file.name) GLOBAL_VAR.txt += '*' * 50 + '\n' GLOBAL_VAR.txt += '项目地址: https://github.com/wxy1343/aliyunpan' + '\n' GLOBAL_VAR.txt += '*' * 50 + '\n\n' if expire_sec is None: expire_sec = 14400 share_(path, file_id=None) if save: file_name = Path(path).name + f'{int(time.time())}.txt' with open(file_name, 'w', encoding='utf-8') as f: f.write(GLOBAL_VAR.txt) print('文件导入'.center(50, '*')) print(f'python main.py upload -s {file_name}') print('链接导入'.center(50, '*')) file_id = self.upload(file_name)[0] print() if file_id: self._path_list.update_path_list(depth=0) file = self._path_list._tree.get_node(file_id).data url_base64 = base64.b64encode( self.disk.get_download_url(file_id).encode()).decode() url = f'{self._share_link}{Path(path).name}|{file.content_hash}|{url_base64}|{file.size}|root' print(f'python main.py upload -s "{url}"') def tui(self): from aliyunpan.cli.tui import AliyunpanTUI aliyunpan_tui = AliyunpanTUI(self) aliyunpan_tui.run() def sync(self, path, upload_path, sync_time, time_out, chunk_size, retry, delete, first=True): if first and path == 'root': self._print.print_info( 'Do you really want to synchronize the root? This operation may delete all your files.', error=True) input('\nEnter to continue.') path = AliyunpanPath(path) relative_path = AliyunpanPath(path.name) if str(relative_path) == '.': return self.sync(path.absolute(), upload_path, sync_time, time_out, chunk_size, retry, delete, first=False) upload_path = AliyunpanPath(upload_path) p = upload_path / relative_path self._path_list.update_path_list(p, is_fid=False) file_id = self._path_list.get_path_fid(p, update=False) if not file_id: self.upload(path, upload_path, timeout=time_out, chunk_size=chunk_size, retry=retry) self._path_list.update_path_list(p, is_fid=False) file_id = self._path_list.get_path_fid(p, update=False) path_ = self._path_list._tree.to_dict( file_id, with_data=True)[str(relative_path)] change_file_list = self._path_list.check_path_diff( path, path_['children'] if 'children' in path_ else []) change_file_list = filter(self.file_filter, change_file_list) for path_ in change_file_list: relative_path = path.name / (path - path_) if path_.exists(): if not self.upload(path_, upload_path / relative_path.parent, force=True, timeout=time_out, chunk_size=chunk_size, retry=retry, ignore=True): if first: self._print.upload_info(path_, status=False) self._print.print_line() elif delete: self.rm(upload_path / relative_path) if sync_time: self._print.wait_info('等待{time}秒后再次同步', t=sync_time, refresh_line=True) self._print.refresh_line() self.sync(path, upload_path, sync_time, time_out, chunk_size, retry, delete=delete, first=False) def sync_local(self, sync_path, save_path, sync_time, chunk_size, delete, **kwargs): if not save_path: save_path = '.' path = AliyunpanPath(save_path) + AliyunpanPath(sync_path).name if not path.exists(): self.download(sync_path, save_path) file_id = self.path_list.get_path_fid(sync_path, update=False) if not file_id: raise FileNotFoundError(sync_path) self._path_list.update_path_list(sync_path, is_fid=False) path_ = self._path_list._tree.to_dict(file_id, with_data=True)[str( AliyunpanPath(sync_path)).name] change_file_list = self._path_list.check_path_diff( path, path_['children'] if 'children' in path_ else []) for path_ in change_file_list: p = str(AliyunpanPath(path_) - AliyunpanPath(save_path)) file_node = self.path_list.get_path_node(p) if not file_node: if delete: Path(path_).unlink() if path_.is_file() else shutil.rmtree( path_) self._print.remove_info(path_, True) self._print.print_line() else: self.download(p, str(save_path / Path(p).parent), chunk_size=chunk_size, **kwargs) if sync_time: self._print.wait_info('等待{time}秒后再次同步', t=sync_time, refresh_line=True) self._print.refresh_line() return self.sync_local(sync_path, save_path, sync_time=sync_time, chunk_size=chunk_size, delete=delete, **kwargs) def share_link(self, path_list, file_id_list=None, expiration=None): path_list = filter(self.file_filter, path_list) t = '' if expiration is None else time.time() + expiration if not file_id_list: file_id_list = [ self._path_list.get_path_fid(path, update=False) for path in path_list ] file_id_list = list(filter(None, file_id_list)) if file_id_list: print(self._disk.share_link(file_id_list, t)) else: raise FileNotFoundError def auto_refresh_token(self, refresh_time): print('Start to refresh token automatically.') while True: time.sleep(refresh_time) self._disk.token_refresh() print( time.strftime("%Y-%m-%d %H:%M:%S: ", time.localtime()) + self.disk.refresh_token) @property def req(self): return self._req @property def config(self): return self._config @property def path_list(self): return self._path_list @property def disk(self): return self._disk
class Commander: def __init__(self): self._disk = AliyunPan() self._path_list = PathList(self._disk) self._req = Req() self.refresh_token = '' def disk_init(self, refresh_token): if len(refresh_token) == 32: self._disk.refresh_token = refresh_token else: raise Exception('Is not a valid refresh_token') def ls(self, path, l): self._path_list.get_path_list(path) for i in self._path_list.get_path_list(path): if l: if i.type: print(StrOfSize(i.size), time.strftime('%d %b %H:%M', i.ctime), i.id, i.name) else: print('-', time.strftime('%d %b %H:%M', i.ctime), i.id, i.name) else: print(i.name, end='\t') def tree(self, path): self._path_list.tree(path) def rm(self, path): self._disk.delete_file(self._path_list.get_path_fid(path)) def mv(self, path, parent_path): self._disk.move_file(self._path_list.get_path_fid(path), self._path_list.get_path_fid(parent_path)) def upload(self, upload_path, path_list, timeout, retry, force): for path in path_list: if path: if os.path.isfile(path): self._disk.upload_file( self._path_list.get_path_fid(upload_path), path, timeout, retry, force) elif os.path.isdir(path): if upload_path == 'root': upload_path = '/' self.upload_dir(path, upload_path, timeout, retry, force) else: raise FileNotFoundError def upload_dir(self, path, upload_path, timeout, retry, force): if not self._path_list.get_path_fid( os.path.join(upload_path, os.path.split(path)[1]).replace('\\', '/')): if upload_path == '/': self._disk.create_file(os.path.split(path)[1], upload_path) else: self._disk.create_file( os.path.split(path)[1], self._path_list.get_path_fid(upload_path)) upload_path = os.path.join(upload_path, os.path.split(path)[1]).replace('\\', '/') for file in os.listdir(path): p = os.path.join(path, file) if os.path.isdir(p): self.upload_dir(p, upload_path, timeout, retry, force) else: self._disk.upload_file( self._path_list.get_path_fid(upload_path), p, timeout, retry, force) def download(self, path_list, save_path): if save_path == '': save_path = os.getcwd() for path in path_list: if isinstance(path, str): file_node = self._path_list.get_path_node(path).data else: file_node = path path = file_node.name path = path.replace('/', '\\') p = os.path.join(save_path, path) if file_node.type: print(f'[*][download]{os.path.join(save_path, path)}') self.download_file(p, file_node.download_url) else: self.download(self._path_list.get_fid_list(file_node.id), p) def download_file(self, path, url): try: p = os.path.split(path)[0] os.makedirs(p) print(f'[+][mkdir]{p}') except FileExistsError: pass if os.path.exists(path): temp_size = os.path.getsize(path) else: temp_size = 0 headers = {'Range': 'bytes=%d-' % temp_size} start_time = time.time() try: r = self._req.get(url, headers=headers, stream=True) file_size = int(r.headers['Content-Length']) if temp_size == file_size and file_size != 0: print(f'[+][download]{path}') return True elif temp_size > file_size: mode = 'wb' else: mode = 'ab' download_info = f'\r下载中... [{"*" * 10}] %0' show_download_info = download_info and file_size >= 1024 * 1024 with open(path, mode) as f: for chunk in r.iter_content(chunk_size=1024): if show_download_info: sys.stdout.write(download_info) if chunk: temp_size += len(chunk) f.write(chunk) total_time = time.time() - start_time k = temp_size / file_size download_info = f'\r下载中... [{"=" * int(k * 10)}{"*" * int((1 - k) * 10)}] %{math.ceil(k * 1000) / 10} {round(temp_size / total_time / 1024 / 1024, 2)}MB/s' if show_download_info: print() except requests.exceptions.RequestException: print(f'[-][download]{path}') return False print(f'[+][download]{path}') return True def share(self, path, file_id, expire_sec): if path: file = self._path_list.get_path_node(path).data else: file = self._path_list.get_node_by_file_id(file_id).data print(self._disk.get_download_url(file.id, expire_sec))
class Commander: def __init__(self): self._disk = AliyunPan() self._path_list = PathList(self._disk) self._req = Req() self._config = Config() def init(self, config_file='', refresh_token=None, username=None, password=None, depth=3): self._path_list.depth = depth spectify_conf_file = os.environ.get("ALIYUNPAN_CONF", "") config_file = list( filter( lambda x: Path(x).is_file(), map(lambda x: Path(x).expanduser(), [spectify_conf_file, config_file]))) if refresh_token: if not len(refresh_token) == 32: raise Exception('Is not a valid refresh_token') self._disk.refresh_token = refresh_token elif username: if not password: raise Exception('Password not found.') self._disk.login(username, password) elif config_file: self._config.config_file = config_file[0] refresh_token = self._config.get('refresh_token') username = self._config.get('username') password = self._config.get('password') if refresh_token: if not len(refresh_token) == 32: raise Exception('Is not a valid refresh_token') self._disk.refresh_token = refresh_token elif username: if not password: raise Exception('Password not found.') self._disk.login(username, password) else: raise Exception('Configuration file error.') def ls(self, path, l): self._path_list.get_path_list(path) for i in self._path_list.get_path_list(path): if l: if i.type: print(StrOfSize(i.size), time.strftime('%d %b %H:%M', i.ctime), i.id, i.name) else: print('-', time.strftime('%d %b %H:%M', i.ctime), i.id, i.name) else: print(i.name, end='\t') def tree(self, path='root'): return self._path_list.tree(path) def rm(self, path, update=False): file_id = self._path_list.get_path_fid(path) _ = self._disk.delete_file(file_id) if _ and file_id and update: self._path_list._tree.remove_node(file_id) return _ def mv(self, path, target_path, update=False): file_id = self._path_list.get_path_fid(path) _ = self._disk.move_file(self._path_list.get_path_fid(path), self._path_list.get_path_fid(target_path)) if update: if _ and file_id: self._path_list._tree.remove_node(file_id) self._path_list.update_path_list(target_path, is_fid=False) return _ def mkdir(self, path, update=False): path = Path(path) file_id = self._path_list.get_path_fid(path) if file_id: return True parent_file_id = self._path_list.get_path_fid(path.parent) r = self._disk.create_file(path.name, parent_file_id) try: file_id = r.json()['file_id'] except KeyError: logger.debug(r.json()['message']) return False if file_id: print(f'[+][mkdir]{path}') if update: self._path_list.update_path_list(path.parent, is_fid=False) else: self._path_list._tree.create_node(tag=path.name, identifier=file_id, parent=parent_file_id) return file_id def upload(self, path, upload_path='root', timeout=10.0, retry=3, force=False): if isinstance(path, str): path_list = (path, ) else: path_list = path for path in path_list: if path: path = Path(path) if path.is_file(): self._disk.upload_file( self._path_list.get_path_fid(upload_path), path, timeout, retry, force) elif path.is_dir(): if upload_path == 'root': upload_path = '/' upload_path = Path(upload_path) upload_file_list = self.upload_dir(path, upload_path, timeout, retry, force) self._path_list.update_path_list(upload_path, is_fid=False) for file in upload_file_list: self._disk.upload_file( self._path_list.get_path_fid(file[0]), *file[1]) else: raise FileNotFoundError def upload_dir(self, path, upload_path, timeout, retry, force): upload_path = upload_path / path.name if not self._path_list.get_path_fid(upload_path): self.mkdir(upload_path) upload_file_list = [] for file in path.iterdir(): if file.is_dir(): upload_file_list.extend( self.upload_dir(file, upload_path, timeout, retry, force)) else: upload_file_list.append( [upload_path, (file, timeout, retry, force)]) return upload_file_list def download(self, path, save_path, single_file=False): if save_path == '': save_path = Path().cwd() save_path = Path(save_path) if isinstance(path, str): path_list = (path, ) else: path_list = path for path in path_list: if isinstance(path, (Path, str)): path = Path(path) node = self._path_list.get_path_node(path) if not node: raise FileNotFoundError(path) file_node = node.data if file_node.type: single_file = True else: file_node, path = path, path.name p = save_path / path if file_node.type: if single_file: p = save_path / p.name print(f'[*][download]{p}') self.download_file(p, file_node.download_url) else: self.download(self._path_list.get_fid_list(file_node.id), save_path / p.name) def download_file(self, path, url): try: path.parent.mkdir(parents=True) print(f'[+][mkdir]{path.parent}') except FileExistsError: pass if path.exists(): temp_size = path.stat().st_size else: temp_size = 0 headers = {'Range': 'bytes=%d-' % temp_size} start_time = time.time() try: r = self._req.get(url, headers=headers, stream=True) file_size = int(r.headers['Content-Length']) if temp_size == file_size and file_size != 0: print(f'[+][download]{path}') return True elif temp_size > file_size: mode = 'wb' temp_size = 0 else: mode = 'ab' download_info = f'\r下载中... [{"*" * 10}] %0' show_download_info = download_info and file_size >= 1024 * 1024 with path.open(mode) as f: for chunk in r.iter_content(chunk_size=1024): if show_download_info: sys.stdout.write(download_info) if chunk: temp_size += len(chunk) f._write(chunk) total_time = time.time() - start_time k = temp_size / file_size download_info = f'\r下载中... [{"=" * int(k * 10)}{"*" * int((1 - k) * 10)}] %{math.ceil(k * 1000) / 10} {round(temp_size / total_time / 1024 / 1024, 2)}MB/s' if show_download_info: print() except requests.exceptions.RequestException: print(f'[-][download]{path}') return False print(f'[+][download]{path}') return True def share(self, path, file_id, expire_sec): if path: file = self._path_list.get_path_node(path).data else: file = self._path_list._tree.get_node(file_id).data print(self._disk.get_download_url(file.id, expire_sec))
class Commander: def __init__(self): self._disk = AliyunPan() self._path_list = PathList(self._disk) self._req = Req() self.refresh_token = '' def disk_init(self, refresh_token): if len(refresh_token) == 32: self._disk.refresh_token = refresh_token else: raise Exception('Is not a valid refresh_token') def ls(self, path, l): self._path_list.get_path_list(path) for i in self._path_list.get_path_list(path): if l: if i.type: print(StrOfSize(i.size), time.strftime('%d %b %H:%M', i.ctime), i.id, i.name) else: print('-', time.strftime('%d %b %H:%M', i.ctime), i.id, i.name) else: print(i.name, end='\t') def tree(self, path): self._path_list.tree(path) def rm(self, path): self._disk.delete_file(self._path_list.get_path_fid(path)) def mv(self, path, parent_path): self._disk.move_file(self._path_list.get_path_fid(path), self._path_list.get_path_fid(parent_path)) def upload(self, upload_path, path_list, timeout, retry, force): for path in path_list: if path: if os.path.isfile(path): self._disk.upload_file( self._path_list.get_path_fid(upload_path), path, timeout, retry, force) elif os.path.isdir(path): if upload_path == 'root': upload_path = '/' self.upload_dir(path, upload_path, timeout, retry, force) def upload_dir(self, path, upload_path, timeout, retry, force): print( os.path.join(upload_path, os.path.split(path)[1]).replace('\\', '/')) if not self._path_list.get_path_fid( os.path.join(upload_path, os.path.split(path)[1]).replace('\\', '/')): if upload_path == '/': self._disk.create_file(os.path.split(path)[1], upload_path) else: self._disk.create_file( os.path.split(path)[1], self._path_list.get_path_fid(upload_path)) upload_path = os.path.join(upload_path, os.path.split(path)[1]).replace('\\', '/') for file in os.listdir(path): p = os.path.join(path, file) if os.path.isdir(p): self.upload_dir(p, upload_path, timeout, retry, force) else: self._disk.upload_file( self._path_list.get_path_fid(upload_path), p, timeout, retry, force) def download(self, path_list, save_path): if save_path == '': save_path = os.getcwd() for path in path_list: if path: file_list = self._path_list.get_path_list(path) if file_list: for file in file_list: if file.download_url: p = os.path.join(save_path, path.lstrip('/')) if os.path.exists(p): temp_size = os.path.getsize(p) else: temp_size = 0 headers = {'Range': 'bytes=%d-' % temp_size} r = self._req.get(file.download_url, headers=headers, stream=True) f = os.path.join(path, file.name).replace("\\", "/") print(f'download {f} to {p}') with open(p, 'ab') as f: for chunk in r.iter_content(chunk_size=1024): if chunk: temp_size += len(chunk) f.write(chunk) print(p, '下载成功') elif not file.type: p = os.path.join(save_path, path.lstrip('/')) try: os.makedirs(os.path.join(p, file.name)) except FileExistsError: pass d = os.path.join(path, file.name).replace('\\', '/') print(f'mkdir {d}') self.download([ os.path.join(path, file.name).replace( '\\', '/') ], os.path.join(p, file.name))