diff --git a/misskey_export.py b/misskey_export.py index 76741be..a8105fa 100644 --- a/misskey_export.py +++ b/misskey_export.py @@ -137,28 +137,59 @@ def download_file(file_info, folder_path): except Exception as e: print(f" Failed to download {file_name}: {e}") +def get_folder_path(folder_id, folder_map): + """Resolves the full path of a folder from the folder map.""" + path_parts = [] + curr_id = folder_id + while curr_id and curr_id in folder_map: + folder = folder_map[curr_id] + folder_name = folder.get("name", curr_id) + safe_name = "".join(c for c in folder_name if c.isalnum() or c in "._- ") + if not safe_name: + safe_name = curr_id + path_parts.insert(0, safe_name) + curr_id = folder.get("parentId") + return Path(*path_parts) if path_parts else Path("") + def export_drive_admin(user_id, base_path): - """Exports all drive files for a user using admin endpoint.""" + """Exports all drive files for a user with folder hierarchy.""" print(f" Exporting drive for {user_id}...") - files_path = base_path / "files" - if not files_path.exists(): - files_path.mkdir() + files_base_path = base_path / "files" + if not files_base_path.exists(): + files_base_path.mkdir() + + all_files = [] + folder_map = {} until_id = None - count = 0 while True: files = fetch_admin_drive_files(user_id, until_id) if not files: break for file in files: - download_file(file, files_path) - count += 1 + all_files.append(file) + # Build folder map from the 'folder' property if available in the packed file + curr = file.get("folder") + while curr: + folder_map[curr["id"]] = curr + # Some Misskey versions might pack the parent as well + curr = curr.get("parent") if len(files) < 100: break until_id = files[-1]["id"] - print(f" Exported {count} files.") + for file in all_files: + folder_id = file.get("folderId") + rel_folder_path = get_folder_path(folder_id, folder_map) + full_folder_path = files_base_path / rel_folder_path + + if not full_folder_path.exists(): + full_folder_path.mkdir(parents=True, exist_ok=True) + + download_file(file, full_folder_path) + + print(f" Exported {len(all_files)} files.") def export_user_data(user, base_path): """Exports user profile data to user-data.txt.""" print(f" Exporting profile data for {user['username']}...")