修改远程文件无法显示的问题(文件夹可以打开)
This commit is contained in:
parent
06a2ab71e6
commit
04499390f1
@ -83,29 +83,80 @@ class BaiduCloud(BaseCloud):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def list_files(self, remote_path: str) -> List[str]:
|
def list_files(self, remote_path: str) -> List[str]:
|
||||||
|
"""
|
||||||
|
获取远程目录的文件列表
|
||||||
|
|
||||||
|
返回格式:
|
||||||
|
- 目录: "D folder_name"
|
||||||
|
- 文件: "F file_name size"
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
cmd = ["bypy", "list", remote_path]
|
cmd = ["bypy", "list", remote_path]
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
cmd,
|
cmd,
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
timeout=120,
|
timeout=120,
|
||||||
encoding='utf-8',
|
encoding='utf-8',
|
||||||
errors='replace',
|
errors='replace',
|
||||||
env=self.utf8_env
|
env=self.utf8_env
|
||||||
)
|
)
|
||||||
|
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
files = []
|
files = []
|
||||||
for line in result.stdout.split('\n'):
|
output = result.stdout
|
||||||
line = line.strip()
|
|
||||||
if line and not line.startswith('Quota'):
|
# 记录原始输出用于调试
|
||||||
files.append(line)
|
self.logger.debug(f"Baidu list raw output:\n{output}")
|
||||||
|
|
||||||
|
# 解析bypy输出
|
||||||
|
lines = output.split('\n')
|
||||||
|
in_file_list = False
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
# 跳过空行
|
||||||
|
if not line.strip():
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 跳过警告信息
|
||||||
|
if '<W>' in line or 'WARNING' in line or 'WARN' in line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 跳过Quota信息
|
||||||
|
if line.strip().startswith('Quota') or 'Loading quota' in line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 跳过表头和分隔符
|
||||||
|
if '($t $f $s $m $d)' in line or line.strip().startswith('/apps/bypy'):
|
||||||
|
in_file_list = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 跳过包含特殊字符的格式化行
|
||||||
|
if any(x in line for x in ['<W>', '<P>', '<D>', '<T>', '!0!0!', '>"!!']):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 如果已经进入文件列表区域,处理文件信息
|
||||||
|
if in_file_list:
|
||||||
|
line = line.strip()
|
||||||
|
|
||||||
|
# bypy的输出可能是多列格式,需要解析
|
||||||
|
# 典型格式: "D folder_name" 或 "F file_name (size)"
|
||||||
|
if line.startswith('D ') or line.startswith('F '):
|
||||||
|
files.append(line)
|
||||||
|
elif line and not line.startswith('-') and not line.startswith('='):
|
||||||
|
# 尝试将行解析为文件信息
|
||||||
|
# 如果行包含文件名,尝试识别类型
|
||||||
|
# 简单判断:如果没有扩展名,可能是目录
|
||||||
|
if '.' not in line or line.count(' ') > 0:
|
||||||
|
# 可能需要更复杂的解析,暂时标记为文件
|
||||||
|
files.append(f"F {line}")
|
||||||
|
|
||||||
|
self.logger.info(f"Parsed {len(files)} files from Baidu: {remote_path}")
|
||||||
return files
|
return files
|
||||||
else:
|
else:
|
||||||
self.logger.error(f"Baidu list failed: {result.stderr}")
|
self.logger.error(f"Baidu list failed: {result.stderr}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
self.logger.error(f"Baidu list timeout: {remote_path}")
|
self.logger.error(f"Baidu list timeout: {remote_path}")
|
||||||
return []
|
return []
|
||||||
|
|||||||
@ -164,7 +164,13 @@ class SyncTab:
|
|||||||
remote_frame = ttk.LabelFrame(preview_paned, text="远程文件", padding="5")
|
remote_frame = ttk.LabelFrame(preview_paned, text="远程文件", padding="5")
|
||||||
preview_paned.add(remote_frame, weight=1)
|
preview_paned.add(remote_frame, weight=1)
|
||||||
|
|
||||||
self.remote_tree = ttk.Treeview(remote_frame, show="tree")
|
# 创建带隐藏列的Treeview用于存储元数据
|
||||||
|
self.remote_tree = ttk.Treeview(remote_frame, show="tree", columns=("path", "type", "cloud"))
|
||||||
|
# 隐藏columns(宽度设为0)
|
||||||
|
self.remote_tree.column("path", width=0, stretch=False)
|
||||||
|
self.remote_tree.column("type", width=0, stretch=False)
|
||||||
|
self.remote_tree.column("cloud", width=0, stretch=False)
|
||||||
|
|
||||||
remote_scrollbar = ttk.Scrollbar(remote_frame, orient=tk.VERTICAL, command=self.remote_tree.yview)
|
remote_scrollbar = ttk.Scrollbar(remote_frame, orient=tk.VERTICAL, command=self.remote_tree.yview)
|
||||||
self.remote_tree.configure(yscrollcommand=remote_scrollbar.set)
|
self.remote_tree.configure(yscrollcommand=remote_scrollbar.set)
|
||||||
|
|
||||||
@ -174,6 +180,12 @@ class SyncTab:
|
|||||||
remote_frame.columnconfigure(0, weight=1)
|
remote_frame.columnconfigure(0, weight=1)
|
||||||
remote_frame.rowconfigure(0, weight=1)
|
remote_frame.rowconfigure(0, weight=1)
|
||||||
|
|
||||||
|
# 绑定双击事件以展开文件夹
|
||||||
|
self.remote_tree.bind('<Double-1>', self._on_remote_item_double_click)
|
||||||
|
|
||||||
|
# 用于跟踪当前远程目录路径(用于导航)
|
||||||
|
self.current_remote_path_stack = []
|
||||||
|
|
||||||
# 控制区域
|
# 控制区域
|
||||||
control_frame = ttk.Frame(main_frame)
|
control_frame = ttk.Frame(main_frame)
|
||||||
control_frame.grid(row=3, column=0, sticky=(tk.W, tk.E), pady=(10, 0))
|
control_frame.grid(row=3, column=0, sticky=(tk.W, tk.E), pady=(10, 0))
|
||||||
@ -402,6 +414,9 @@ class SyncTab:
|
|||||||
# 显示加载提示
|
# 显示加载提示
|
||||||
self.log_queue.put(f"🔄 正在加载远程文件: {remote_path}")
|
self.log_queue.put(f"🔄 正在加载远程文件: {remote_path}")
|
||||||
|
|
||||||
|
# 保存当前路径
|
||||||
|
self.current_remote_path = remote_path
|
||||||
|
|
||||||
def load_worker():
|
def load_worker():
|
||||||
try:
|
try:
|
||||||
# 获取所有可用的云盘服务
|
# 获取所有可用的云盘服务
|
||||||
@ -424,6 +439,14 @@ class SyncTab:
|
|||||||
|
|
||||||
# 在UI线程中更新树形视图
|
# 在UI线程中更新树形视图
|
||||||
def update_tree():
|
def update_tree():
|
||||||
|
# 如果不是根目录,添加"返回上级"选项
|
||||||
|
if remote_path != self.remote_dir_var.get() and '/' in remote_path:
|
||||||
|
parent_path = '/'.join(remote_path.rstrip('/').split('/')[:-1])
|
||||||
|
if not parent_path:
|
||||||
|
parent_path = self.remote_dir_var.get()
|
||||||
|
back_item = self.remote_tree.insert("", "end", text="⬆️ 返回上级目录",
|
||||||
|
values=(parent_path, 'back', ''))
|
||||||
|
|
||||||
if not all_files:
|
if not all_files:
|
||||||
# 显示"无文件"提示
|
# 显示"无文件"提示
|
||||||
self.remote_tree.insert("", "end", text="📭 远程目录为空或不存在")
|
self.remote_tree.insert("", "end", text="📭 远程目录为空或不存在")
|
||||||
@ -431,31 +454,57 @@ class SyncTab:
|
|||||||
|
|
||||||
# 为每个云盘创建一个分类节点
|
# 为每个云盘创建一个分类节点
|
||||||
for cloud_name, files in all_files.items():
|
for cloud_name, files in all_files.items():
|
||||||
cloud_node = self.remote_tree.insert("", "end", text=f"☁️ {cloud_name}", open=True)
|
# 如果只有一个云盘且文件不多,可以不创建云盘节点
|
||||||
|
if len(self.clouds) == 1 and len(files) < 50:
|
||||||
|
parent_node = ""
|
||||||
|
else:
|
||||||
|
cloud_node = self.remote_tree.insert("", "end", text=f"☁️ {cloud_name}",
|
||||||
|
values=('', 'cloud', cloud_name), open=True)
|
||||||
|
parent_node = cloud_node
|
||||||
|
|
||||||
# 解析文件列表并添加到树中
|
# 分类存储文件夹和文件
|
||||||
|
folders = []
|
||||||
|
regular_files = []
|
||||||
|
|
||||||
|
# 解析文件列表并分类
|
||||||
for file_info in files:
|
for file_info in files:
|
||||||
# bypy的输出格式可能是 "D 文件夹名" 或 "F 文件名 (大小)"
|
|
||||||
file_info = file_info.strip()
|
file_info = file_info.strip()
|
||||||
|
|
||||||
if not file_info:
|
if not file_info:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 尝试解析文件类型和名称
|
# 解析文件类型和名称
|
||||||
if file_info.startswith('D '):
|
if file_info.startswith('D '):
|
||||||
# 目录
|
# 目录
|
||||||
name = file_info[2:].strip()
|
name = file_info[2:].strip()
|
||||||
self.remote_tree.insert(cloud_node, "end", text=f"📁 {name}")
|
folders.append(name)
|
||||||
elif file_info.startswith('F '):
|
elif file_info.startswith('F '):
|
||||||
# 文件
|
# 文件
|
||||||
parts = file_info[2:].split('(')
|
parts = file_info[2:].split('(')
|
||||||
name = parts[0].strip()
|
name = parts[0].strip()
|
||||||
size = parts[1].rstrip(')').strip() if len(parts) > 1 else ""
|
size = parts[1].rstrip(')').strip() if len(parts) > 1 else ""
|
||||||
display_text = f"📄 {name}" + (f" ({size})" if size else "")
|
regular_files.append((name, size))
|
||||||
self.remote_tree.insert(cloud_node, "end", text=display_text)
|
|
||||||
else:
|
else:
|
||||||
# 未知格式,直接显示
|
# 未知格式,尝试直接显示
|
||||||
self.remote_tree.insert(cloud_node, "end", text=f"📄 {file_info}")
|
regular_files.append((file_info, ""))
|
||||||
|
|
||||||
|
# 先显示文件夹(按名称排序)
|
||||||
|
for name in sorted(folders):
|
||||||
|
full_path = f"{remote_path.rstrip('/')}/{name}"
|
||||||
|
folder_item = self.remote_tree.insert(
|
||||||
|
parent_node, "end",
|
||||||
|
text=f"📁 {name}",
|
||||||
|
values=(full_path, 'folder', cloud_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 再显示文件(按名称排序)
|
||||||
|
for name, size in sorted(regular_files):
|
||||||
|
display_text = f"📄 {name}" + (f" ({size})" if size else "")
|
||||||
|
full_path = f"{remote_path.rstrip('/')}/{name}"
|
||||||
|
file_item = self.remote_tree.insert(
|
||||||
|
parent_node, "end",
|
||||||
|
text=display_text,
|
||||||
|
values=(full_path, 'file', cloud_name)
|
||||||
|
)
|
||||||
|
|
||||||
self.log_queue.put("✅ 远程文件列表加载完成")
|
self.log_queue.put("✅ 远程文件列表加载完成")
|
||||||
|
|
||||||
@ -473,6 +522,51 @@ class SyncTab:
|
|||||||
# 在后台线程中加载
|
# 在后台线程中加载
|
||||||
threading.Thread(target=load_worker, daemon=True).start()
|
threading.Thread(target=load_worker, daemon=True).start()
|
||||||
|
|
||||||
|
def _on_remote_item_double_click(self, event):
|
||||||
|
"""处理远程文件树的双击事件"""
|
||||||
|
selection = self.remote_tree.selection()
|
||||||
|
if not selection:
|
||||||
|
return
|
||||||
|
|
||||||
|
item = selection[0]
|
||||||
|
item_data = self.remote_tree.item(item)
|
||||||
|
item_text = item_data.get('text', '')
|
||||||
|
item_values = item_data.get('values', [])
|
||||||
|
|
||||||
|
# 从values中获取路径和类型 (path, type, cloud)
|
||||||
|
if item_values and len(item_values) >= 2:
|
||||||
|
item_path = item_values[0]
|
||||||
|
item_type = item_values[1]
|
||||||
|
else:
|
||||||
|
# 如果没有设置values,尝试从文本判断
|
||||||
|
if item_text.startswith('📁 '):
|
||||||
|
# 这是一个文件夹
|
||||||
|
folder_name = item_text[2:].strip()
|
||||||
|
current_path = getattr(self, 'current_remote_path', self.remote_dir_var.get())
|
||||||
|
item_path = f"{current_path.rstrip('/')}/{folder_name}"
|
||||||
|
item_type = 'folder'
|
||||||
|
elif item_text.startswith('⬆️'):
|
||||||
|
# 返回上级
|
||||||
|
item_type = 'back'
|
||||||
|
current_path = getattr(self, 'current_remote_path', self.remote_dir_var.get())
|
||||||
|
item_path = '/'.join(current_path.rstrip('/').split('/')[:-1]) or self.remote_dir_var.get()
|
||||||
|
else:
|
||||||
|
# 文件或其他,不处理
|
||||||
|
self.log_queue.put(f"ℹ️ 点击的项目不可操作: {item_text}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 如果是文件夹或返回上级,进入该目录
|
||||||
|
if item_type == 'folder' or item_type == 'back':
|
||||||
|
self.log_queue.put(f"📂 进入目录: {item_path}")
|
||||||
|
self._refresh_remote_tree(item_path)
|
||||||
|
elif item_type == 'file':
|
||||||
|
# 文件双击暂不处理,可以在未来添加下载功能
|
||||||
|
self.log_queue.put(f"ℹ️ 文件双击功能待实现: {item_path}")
|
||||||
|
elif item_type == 'cloud':
|
||||||
|
# 双击云盘节点,不做任何操作
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _browse_directory(self):
|
def _browse_directory(self):
|
||||||
"""向后兼容的方法"""
|
"""向后兼容的方法"""
|
||||||
self._browse_and_add_folder()
|
self._browse_and_add_folder()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user