fix duplicate folders for target server
This commit is contained in:
parent
17d20df80a
commit
fe5e680fa4
5 changed files with 42 additions and 51 deletions
|
|
@ -13,44 +13,17 @@ logger = logging.getLogger(__name__)
|
|||
class MigrationContext:
|
||||
"""Holds state and connections for reading from Discord and writing to the target platform."""
|
||||
|
||||
def __init__(self, config: AppConfig, target_platform: str | None = None, source_mode: str = "live"):
|
||||
def __init__(self, config: AppConfig, target_platform: str | None = None, source_mode: str = "live", base_dir: str = ""):
|
||||
self.config = config
|
||||
self.source_mode = source_mode
|
||||
# If caller didn't specify, fall back to config value
|
||||
self.target_platform = target_platform or config.target_platform or "fluxer"
|
||||
|
||||
server_id = config.target_server_id or "unconfigured"
|
||||
fillers = {"000000000000000000", "DISCORD_SERVER_ID", "FLUXER_COMMUNITY_ID",
|
||||
"STOAT_SERVER_ID", "TARGET_SERVER_ID", ""}
|
||||
if server_id in fillers:
|
||||
server_id = "unconfigured"
|
||||
|
||||
# Try to find an existing state folder for this server_id
|
||||
import os
|
||||
|
||||
state_file: str | Path = ""
|
||||
messages_file: str | Path = ""
|
||||
|
||||
if server_id != "unconfigured":
|
||||
logger.info(f"Probing for existing migration folder for Server ID: {server_id}")
|
||||
for d in Path(".").iterdir():
|
||||
if d.is_dir() and d.name.endswith(f"-{server_id}"):
|
||||
logger.info(f"Targeting existing folder: {d.name}")
|
||||
state_file = d / "state-migration.json"
|
||||
messages_file = d / "message-tracker.json"
|
||||
break
|
||||
else:
|
||||
logger.info(f"No existing folder found for {server_id}. A new one will be created upon first state change.")
|
||||
|
||||
self.state = MigrationState(
|
||||
state_file=state_file,
|
||||
messages_file=messages_file
|
||||
)
|
||||
self.state = MigrationState()
|
||||
|
||||
# Select the appropriate source reader
|
||||
if source_mode == "backup":
|
||||
from src.core.backup_reader import BackupReader
|
||||
backup_path = self._find_backup_path(config.discord_server_id)
|
||||
backup_path = self._find_backup_path(config.discord_server_id, base_dir)
|
||||
self.discord_reader = BackupReader(backup_path)
|
||||
logger.info(f"Source mode: BACKUP — reading from {backup_path}")
|
||||
else:
|
||||
|
|
@ -76,16 +49,26 @@ class MigrationContext:
|
|||
|
||||
self.is_running = False
|
||||
|
||||
@staticmethod
|
||||
def _find_backup_path(server_id: str) -> Path:
|
||||
def _find_backup_path(self, server_id: str, base_dir_str: str) -> Path:
|
||||
"""Searches workspace for a DISCORD_BACKUP-{server_id} directory. Creates it if missing."""
|
||||
base_dir = Path(base_dir_str) if base_dir_str else Path(".")
|
||||
|
||||
# 1. Search inside the specific workspace directory first
|
||||
if base_dir.exists() and base_dir.is_dir():
|
||||
for d in base_dir.iterdir():
|
||||
if d.is_dir() and d.name.endswith(f"-{server_id}") and "DISCORD_BACKUP" in d.name:
|
||||
logger.info(f"Found backup directory: {d}")
|
||||
return d
|
||||
|
||||
# 2. Fallback to global search if it wasn't found in the workspace
|
||||
for d in Path(".").rglob(f"DISCORD_BACKUP-{server_id}"):
|
||||
if d.is_dir():
|
||||
logger.info(f"Found backup directory: {d}")
|
||||
logger.info(f"Found backup directory globally: {d}")
|
||||
return d
|
||||
|
||||
# If not found, create it in the current directory
|
||||
new_path = Path(".") / f"DISCORD_BACKUP-{server_id}"
|
||||
# If not found anywhere, create it inside the workspace
|
||||
base_dir.mkdir(exist_ok=True)
|
||||
new_path = base_dir / f"DISCORD_BACKUP-{server_id}"
|
||||
logger.info(f"No existing backup directory found for {server_id}. Creating new one: {new_path}")
|
||||
new_path.mkdir(exist_ok=True)
|
||||
return new_path
|
||||
|
|
|
|||
|
|
@ -323,15 +323,21 @@ class MigrationState:
|
|||
new_folder = base / f"{clean_name}-{server_id}"
|
||||
logger.info(f"Setting active migration folder: {new_folder}")
|
||||
|
||||
# If we have an existing folder that is different, rename it
|
||||
if self.state_file and self.state_file.parent.exists() and self.state_file.parent != new_folder:
|
||||
# Check if it's actually in a server-specific folder (not roots)
|
||||
if self.state_file.parent.name.endswith(f"-{server_id}"):
|
||||
logger.info(f"Renaming active folder from {self.state_file.parent.name} to {new_folder.name}")
|
||||
try:
|
||||
self.state_file.parent.rename(new_folder)
|
||||
except Exception as e:
|
||||
logger.debug(f"Could not rename {self.state_file.parent} to {new_folder}: {e}")
|
||||
# 1. Search base_dir to see if an older folder for this server_id exists
|
||||
existing_folder: Path | None = None
|
||||
if base.exists() and base.is_dir():
|
||||
for d in base.iterdir():
|
||||
if d.is_dir() and d.name.endswith(f"-{server_id}"):
|
||||
existing_folder = d
|
||||
break
|
||||
|
||||
# 2. Rename it if it doesn't match the new desired name
|
||||
if existing_folder and existing_folder != new_folder:
|
||||
logger.info(f"Renaming existing folder {existing_folder.name} to {new_folder.name}")
|
||||
try:
|
||||
existing_folder.rename(new_folder)
|
||||
except Exception as e:
|
||||
logger.debug(f"Could not rename {existing_folder} to {new_folder}: {e}")
|
||||
|
||||
new_folder.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ class DiscordExporter:
|
|||
|
||||
return data
|
||||
|
||||
async def export_channel_messages(self, channel_id: int, progress_callback=None, force=False, accumulated_count=0):
|
||||
async def export_channel_messages(self, channel_id: int, progress_callback=None, force=False, accumulated_count=0, after_id: int | None = None):
|
||||
"""Fetches and saves message history for a channel, handling incremental sync. Returns the total messages processed."""
|
||||
channel = await self.reader.get_channel(channel_id)
|
||||
if not channel:
|
||||
|
|
@ -372,7 +372,9 @@ class DiscordExporter:
|
|||
last_id = None
|
||||
|
||||
# Load existing messages for incremental sync (skip if force)
|
||||
if not force and json_file.exists():
|
||||
if after_id is not None:
|
||||
last_id = after_id
|
||||
elif not force and json_file.exists():
|
||||
try:
|
||||
with open(json_file, "r", encoding="utf-8") as f:
|
||||
old_data = json.load(f)
|
||||
|
|
@ -669,7 +671,7 @@ class DiscordExporter:
|
|||
|
||||
return data
|
||||
|
||||
async def export_threads(self, channel_id: int, progress_callback=None, force=False, accumulated_count=0):
|
||||
async def export_threads(self, channel_id: int, progress_callback=None, force=False, accumulated_count=0, after_id: int | None = None):
|
||||
"""Exports active and archived threads for a channel. Returns accumulated message count."""
|
||||
channel = await self.reader.get_channel(channel_id)
|
||||
if not hasattr(channel, "threads") and not hasattr(channel, "public_archived_threads"):
|
||||
|
|
@ -711,7 +713,7 @@ class DiscordExporter:
|
|||
await asyncio.sleep(0) # important yield between threads
|
||||
|
||||
# First backup the full thread — this creates {thread_id}.json with totalAttachmentSizeBytes
|
||||
accumulated_count = await self.export_channel_messages(thread.id, progress_callback=progress_callback, force=force, accumulated_count=accumulated_count)
|
||||
accumulated_count = await self.export_channel_messages(thread.id, progress_callback=progress_callback, force=force, accumulated_count=accumulated_count, after_id=after_id)
|
||||
thread_count += 1
|
||||
|
||||
# Then populate the forum root JSON with the starter message
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class BackupPane(Container):
|
|||
self.cfg_name = cfg_name
|
||||
self.config_path = cfg_path
|
||||
self.config = load_config(cfg_path)
|
||||
self.engine = MigrationContext(self.config, target_platform=self.config.target_platform or "fluxer")
|
||||
self.engine = MigrationContext(self.config, target_platform=self.config.target_platform or "fluxer", base_dir=f"Reaper-{self.cfg_name}")
|
||||
self.exporter = DiscordExporter(self.engine.discord_reader, base_dir=f"Reaper-{self.cfg_name}")
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
|
|
@ -74,7 +74,7 @@ class BackupPane(Container):
|
|||
|
||||
def reload_config(self) -> None:
|
||||
self.config = load_config(self.config_path)
|
||||
self.engine = MigrationContext(self.config, target_platform=self.config.target_platform or "fluxer")
|
||||
self.engine = MigrationContext(self.config, target_platform=self.config.target_platform or "fluxer", base_dir=f"Reaper-{self.cfg_name}")
|
||||
self.exporter = DiscordExporter(self.engine.discord_reader, base_dir=f"Reaper-{self.cfg_name}")
|
||||
self._validate()
|
||||
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ class ShuttlePane(Container):
|
|||
|
||||
def _rebuild_engine(self):
|
||||
source = "backup" if self.config.tool_mode == "backup_transfer" else "live"
|
||||
self.engine = MigrationContext(self.config, self.target_platform, source_mode=source)
|
||||
self.engine = MigrationContext(self.config, self.target_platform, source_mode=source, base_dir=self._base_dir())
|
||||
|
||||
# ── labels ────────────────────────────────────────────────────────────
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue