修改远程文件无法显示的问题(文件夹可以打开)

This commit is contained in:
taiyi 2025-10-12 08:20:02 +08:00
parent 06a2ab71e6
commit 04499390f1
2 changed files with 165 additions and 20 deletions

View File

@ -83,29 +83,80 @@ class BaiduCloud(BaseCloud):
return False
def list_files(self, remote_path: str) -> List[str]:
"""
获取远程目录的文件列表
返回格式
- 目录: "D folder_name"
- 文件: "F file_name size"
"""
try:
cmd = ["bypy", "list", remote_path]
result = subprocess.run(
cmd,
capture_output=True,
text=True,
cmd,
capture_output=True,
text=True,
timeout=120,
encoding='utf-8',
errors='replace',
env=self.utf8_env
)
if result.returncode == 0:
files = []
for line in result.stdout.split('\n'):
line = line.strip()
if line and not line.startswith('Quota'):
files.append(line)
output = result.stdout
# 记录原始输出用于调试
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
else:
self.logger.error(f"Baidu list failed: {result.stderr}")
return []
except subprocess.TimeoutExpired:
self.logger.error(f"Baidu list timeout: {remote_path}")
return []

View File

@ -164,7 +164,13 @@ class SyncTab:
remote_frame = ttk.LabelFrame(preview_paned, text="远程文件", padding="5")
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)
self.remote_tree.configure(yscrollcommand=remote_scrollbar.set)
@ -174,6 +180,12 @@ class SyncTab:
remote_frame.columnconfigure(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.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.current_remote_path = remote_path
def load_worker():
try:
# 获取所有可用的云盘服务
@ -424,6 +439,14 @@ class SyncTab:
# 在UI线程中更新树形视图
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:
# 显示"无文件"提示
self.remote_tree.insert("", "end", text="📭 远程目录为空或不存在")
@ -431,31 +454,57 @@ class SyncTab:
# 为每个云盘创建一个分类节点
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:
# bypy的输出格式可能是 "D 文件夹名" 或 "F 文件名 (大小)"
file_info = file_info.strip()
if not file_info:
continue
# 尝试解析文件类型和名称
# 解析文件类型和名称
if file_info.startswith('D '):
# 目录
name = file_info[2:].strip()
self.remote_tree.insert(cloud_node, "end", text=f"📁 {name}")
folders.append(name)
elif file_info.startswith('F '):
# 文件
parts = file_info[2:].split('(')
name = parts[0].strip()
size = parts[1].rstrip(')').strip() if len(parts) > 1 else ""
display_text = f"📄 {name}" + (f" ({size})" if size else "")
self.remote_tree.insert(cloud_node, "end", text=display_text)
regular_files.append((name, size))
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("✅ 远程文件列表加载完成")
@ -473,6 +522,51 @@ class SyncTab:
# 在后台线程中加载
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):
"""向后兼容的方法"""
self._browse_and_add_folder()