implement table view in cli
This commit is contained in:
parent
667cb4e902
commit
27ace55242
2 changed files with 227 additions and 166 deletions
|
|
@ -213,26 +213,28 @@ class MigrationEngine:
|
||||||
categories = await self.discord_reader.get_categories()
|
categories = await self.discord_reader.get_categories()
|
||||||
channels = await self.discord_reader.get_channels()
|
channels = await self.discord_reader.get_channels()
|
||||||
|
|
||||||
|
# Filter items if not forcing
|
||||||
|
if not force:
|
||||||
|
categories = [cat for cat in categories if not self.state.get_fluxer_category_id(str(cat.id))]
|
||||||
|
channels = [ch for ch in channels if not self.state.get_fluxer_channel_id(str(ch.id))]
|
||||||
|
|
||||||
total = len(categories) + len(channels)
|
total = len(categories) + len(channels)
|
||||||
current_idx = 0
|
current_idx = 0
|
||||||
|
|
||||||
|
if total == 0:
|
||||||
|
return
|
||||||
|
|
||||||
# Migrate Categories first
|
# Migrate Categories first
|
||||||
for cat in categories:
|
for cat in categories:
|
||||||
if not self.is_running: break
|
if not self.is_running: break
|
||||||
|
|
||||||
state_key = str(cat.id)
|
state_key = str(cat.id)
|
||||||
fluxer_id = None if force else self.state.get_fluxer_category_id(state_key)
|
|
||||||
status = "Copying"
|
|
||||||
|
|
||||||
if not fluxer_id:
|
|
||||||
# 4 corresponds to Category type in Discord/Fluxer typically
|
# 4 corresponds to Category type in Discord/Fluxer typically
|
||||||
fluxer_id = await self.fluxer_writer.create_channel(cat.name, type=4)
|
fluxer_id = await self.fluxer_writer.create_channel(cat.name, type=4)
|
||||||
self.state.set_category_mapping(state_key, fluxer_id)
|
self.state.set_category_mapping(state_key, fluxer_id)
|
||||||
else:
|
|
||||||
status = "Skipping"
|
|
||||||
|
|
||||||
current_idx += 1
|
current_idx += 1
|
||||||
if progress_callback: await progress_callback(f"Cat: {cat.name}", status, current_idx, total)
|
if progress_callback: await progress_callback(f"Cat: {cat.name}", "Copying", current_idx, total)
|
||||||
await asyncio.sleep(self.config.migration.rate_limit_delay_seconds)
|
await asyncio.sleep(self.config.migration.rate_limit_delay_seconds)
|
||||||
|
|
||||||
# Migrate Text Channels
|
# Migrate Text Channels
|
||||||
|
|
@ -240,10 +242,6 @@ class MigrationEngine:
|
||||||
if not self.is_running: break
|
if not self.is_running: break
|
||||||
|
|
||||||
state_key = str(channel.id)
|
state_key = str(channel.id)
|
||||||
fluxer_id = None if force else self.state.get_fluxer_channel_id(state_key)
|
|
||||||
status = "Copying"
|
|
||||||
|
|
||||||
if not fluxer_id:
|
|
||||||
topic = channel.topic if channel.topic else ""
|
topic = channel.topic if channel.topic else ""
|
||||||
parent_id = self.state.get_fluxer_category_id(str(channel.category_id)) if channel.category_id else None
|
parent_id = self.state.get_fluxer_category_id(str(channel.category_id)) if channel.category_id else None
|
||||||
|
|
||||||
|
|
@ -254,11 +252,9 @@ class MigrationEngine:
|
||||||
parent_id=parent_id
|
parent_id=parent_id
|
||||||
)
|
)
|
||||||
self.state.set_channel_mapping(state_key, fluxer_id)
|
self.state.set_channel_mapping(state_key, fluxer_id)
|
||||||
else:
|
|
||||||
status = "Skipping"
|
|
||||||
|
|
||||||
current_idx += 1
|
current_idx += 1
|
||||||
if progress_callback: await progress_callback(channel.name, status, current_idx, total)
|
if progress_callback: await progress_callback(channel.name, "Copying", current_idx, total)
|
||||||
await asyncio.sleep(self.config.migration.rate_limit_delay_seconds)
|
await asyncio.sleep(self.config.migration.rate_limit_delay_seconds)
|
||||||
|
|
||||||
async def sync_permissions(self, progress_callback: Callable[[str, int, int], Awaitable[None]] | None = None):
|
async def sync_permissions(self, progress_callback: Callable[[str, int, int], Awaitable[None]] | None = None):
|
||||||
|
|
@ -266,32 +262,34 @@ class MigrationEngine:
|
||||||
categories = await self.discord_reader.get_categories()
|
categories = await self.discord_reader.get_categories()
|
||||||
channels = await self.discord_reader.get_channels()
|
channels = await self.discord_reader.get_channels()
|
||||||
|
|
||||||
|
# Only sync for items that are already mapped
|
||||||
|
categories = [c for c in categories if self.state.get_fluxer_category_id(str(c.id))]
|
||||||
|
channels = [c for c in channels if self.state.get_fluxer_channel_id(str(c.id))]
|
||||||
|
|
||||||
total = len(categories) + len(channels)
|
total = len(categories) + len(channels)
|
||||||
current_idx = 0
|
current_idx = 0
|
||||||
|
|
||||||
|
if total == 0:
|
||||||
|
return
|
||||||
|
|
||||||
# Sync Category Permissions (Role Overwrites)
|
# Sync Category Permissions (Role Overwrites)
|
||||||
for cat in categories:
|
for cat in categories:
|
||||||
if not self.is_running: break
|
if not self.is_running: break
|
||||||
fluxer_id = self.state.get_fluxer_channel_id(str(cat.id))
|
fluxer_id = self.state.get_fluxer_channel_id(str(cat.id))
|
||||||
if fluxer_id:
|
|
||||||
# In a real implementation, we would diff discord perms
|
# In a real implementation, we would diff discord perms
|
||||||
# and apply them to fluxer_id using client methods.
|
# and apply them to fluxer_id using client methods.
|
||||||
pass
|
|
||||||
|
|
||||||
current_idx += 1
|
current_idx += 1
|
||||||
if progress_callback: await progress_callback(f"Cat: {cat.name}", current_idx, total)
|
if progress_callback: await progress_callback(f"Cat: {cat.name}", current_idx, total)
|
||||||
await asyncio.sleep(self.config.migration.rate_limit_delay_seconds)
|
|
||||||
|
|
||||||
# Sync Channel Permissions
|
# Sync Channel Permissions
|
||||||
for channel in channels:
|
for channel in channels:
|
||||||
if not self.is_running: break
|
if not self.is_running: break
|
||||||
fluxer_id = self.state.get_fluxer_channel_id(str(channel.id))
|
fluxer_id = self.state.get_fluxer_channel_id(str(channel.id))
|
||||||
if fluxer_id:
|
# apply perms
|
||||||
pass
|
|
||||||
|
|
||||||
current_idx += 1
|
current_idx += 1
|
||||||
if progress_callback: await progress_callback(channel.name, current_idx, total)
|
if progress_callback: await progress_callback(channel.name, current_idx, total)
|
||||||
await asyncio.sleep(self.config.migration.rate_limit_delay_seconds)
|
|
||||||
|
|
||||||
async def analyze_migration(self, source_channel_id: int, after_message_id: int | None = None, progress_callback: Callable[[int], Awaitable[None]] | None = None) -> Dict[str, int]:
|
async def analyze_migration(self, source_channel_id: int, after_message_id: int | None = None, progress_callback: Callable[[int], Awaitable[None]] | None = None) -> Dict[str, int]:
|
||||||
"""
|
"""
|
||||||
|
|
@ -416,16 +414,21 @@ class MigrationEngine:
|
||||||
|
|
||||||
return message_count
|
return message_count
|
||||||
|
|
||||||
async def migrate_roles(self, progress_callback: Callable[[str, int, int], Awaitable[None]] | None = None):
|
async def migrate_roles(self, progress_callback: Callable[[str, int, int], Awaitable[None]] | None = None, force: bool = False):
|
||||||
"""Copies roles and their baseline permissions."""
|
"""Copies roles and their baseline permissions."""
|
||||||
roles = await self.discord_reader.get_roles()
|
roles = await self.discord_reader.get_roles()
|
||||||
|
|
||||||
|
if not force:
|
||||||
|
roles = [r for r in roles if not self.state.get_fluxer_role_id(str(r.id))]
|
||||||
|
|
||||||
total = len(roles)
|
total = len(roles)
|
||||||
|
|
||||||
|
if total == 0:
|
||||||
|
return
|
||||||
|
|
||||||
for idx, role in enumerate(roles):
|
for idx, role in enumerate(roles):
|
||||||
if not self.is_running: break
|
if not self.is_running: break
|
||||||
|
|
||||||
fluxer_id = self.state.get_fluxer_role_id(str(role.id))
|
|
||||||
if not fluxer_id:
|
|
||||||
fluxer_id = await self.fluxer_writer.create_role(
|
fluxer_id = await self.fluxer_writer.create_role(
|
||||||
name=role.name,
|
name=role.name,
|
||||||
color=role.color.value,
|
color=role.color.value,
|
||||||
|
|
@ -452,17 +455,19 @@ class MigrationEngine:
|
||||||
stickers = await self.discord_reader.get_stickers()
|
stickers = await self.discord_reader.get_stickers()
|
||||||
objs.extend([(s, "Sticker") for s in stickers])
|
objs.extend([(s, "Sticker") for s in stickers])
|
||||||
|
|
||||||
|
if not force:
|
||||||
|
objs = [(obj, obj_type) for obj, obj_type in objs if not (
|
||||||
|
self.state.get_fluxer_emoji_id(str(obj.id)) if obj_type == "Emoji" else self.state.get_fluxer_sticker_id(str(obj.id))
|
||||||
|
)]
|
||||||
|
|
||||||
total = len(objs)
|
total = len(objs)
|
||||||
|
|
||||||
|
if total == 0:
|
||||||
|
return
|
||||||
|
|
||||||
for idx, (obj, obj_type) in enumerate(objs):
|
for idx, (obj, obj_type) in enumerate(objs):
|
||||||
if not self.is_running: break
|
if not self.is_running: break
|
||||||
|
|
||||||
if obj_type == "Emoji":
|
|
||||||
fluxer_id = None if force else self.state.get_fluxer_emoji_id(str(obj.id))
|
|
||||||
else:
|
|
||||||
fluxer_id = None if force else self.state.get_fluxer_sticker_id(str(obj.id))
|
|
||||||
|
|
||||||
if not fluxer_id:
|
|
||||||
try:
|
try:
|
||||||
if obj_type == "Emoji":
|
if obj_type == "Emoji":
|
||||||
img_data = await self.discord_reader.download_emoji(obj)
|
img_data = await self.discord_reader.download_emoji(obj)
|
||||||
|
|
|
||||||
236
src/ui/app.py
236
src/ui/app.py
|
|
@ -4,6 +4,7 @@ import logging
|
||||||
import re
|
import re
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from rich.prompt import Prompt, Confirm
|
from rich.prompt import Prompt, Confirm
|
||||||
|
from rich.table import Table
|
||||||
from rich.panel import Panel
|
from rich.panel import Panel
|
||||||
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn
|
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn
|
||||||
from src.config import load_config, save_config
|
from src.config import load_config, save_config
|
||||||
|
|
@ -248,43 +249,48 @@ class MigrationCLI:
|
||||||
await self.engine.close_connections()
|
await self.engine.close_connections()
|
||||||
return
|
return
|
||||||
|
|
||||||
console.print("\n[bold]Server Template Preview:[/bold]")
|
table = Table(show_header=True, header_style="bold magenta")
|
||||||
|
table.add_column("Type", width=12)
|
||||||
# Group channels by category
|
table.add_column("Discord Name")
|
||||||
import discord
|
table.add_column("Status", justify="right")
|
||||||
channels_by_cat = {}
|
|
||||||
uncategorized = []
|
|
||||||
|
|
||||||
|
# Group channels by category for status check
|
||||||
|
missing_by_cat = {}
|
||||||
|
missing_uncategorized = []
|
||||||
for ch in channels:
|
for ch in channels:
|
||||||
if ch.category_id:
|
cat_id = str(ch.category_id) if ch.category_id else None
|
||||||
if ch.category_id not in channels_by_cat:
|
if not self.engine.state.get_fluxer_channel_id(str(ch.id)):
|
||||||
channels_by_cat[ch.category_id] = []
|
if cat_id:
|
||||||
channels_by_cat[ch.category_id].append(ch)
|
if cat_id not in missing_by_cat: missing_by_cat[cat_id] = []
|
||||||
|
missing_by_cat[cat_id].append(ch)
|
||||||
else:
|
else:
|
||||||
uncategorized.append(ch)
|
missing_uncategorized.append(ch)
|
||||||
|
|
||||||
def print_channel(ch):
|
|
||||||
if isinstance(ch, discord.TextChannel):
|
|
||||||
color = "cyan"
|
|
||||||
elif isinstance(ch, discord.VoiceChannel):
|
|
||||||
color = "green"
|
|
||||||
elif isinstance(ch, discord.ForumChannel):
|
|
||||||
color = "magenta"
|
|
||||||
else:
|
|
||||||
color = "white"
|
|
||||||
console.print(f" [{color}]- {ch.name}[/{color}]")
|
|
||||||
|
|
||||||
|
# Build the unified preview table
|
||||||
for cat in categories:
|
for cat in categories:
|
||||||
console.print(f"[bold yellow]{cat.name}[/bold yellow]")
|
cat_id_str = str(cat.id)
|
||||||
cat_channels = channels_by_cat.get(cat.id, [])
|
fluxer_cat_id = self.engine.state.get_fluxer_category_id(cat_id_str)
|
||||||
|
|
||||||
|
status = f"[cyan]{fluxer_cat_id}[/cyan]" if fluxer_cat_id else "[bold red]Missing[/bold red]"
|
||||||
|
table.add_row("Category", f"[bold yellow]{cat.name}[/bold yellow]", status)
|
||||||
|
|
||||||
|
# Show ALL channels under this category
|
||||||
|
cat_channels = [ch for ch in channels if str(ch.category_id) == cat_id_str]
|
||||||
for ch in cat_channels:
|
for ch in cat_channels:
|
||||||
print_channel(ch)
|
fluxer_ch_id = self.engine.state.get_fluxer_channel_id(str(ch.id))
|
||||||
|
ch_status = f"[cyan]{fluxer_ch_id}[/cyan]" if fluxer_ch_id else "[red]Missing[/red]"
|
||||||
|
table.add_row(" Channel", ch.name, ch_status)
|
||||||
|
|
||||||
|
# Show Uncategorized
|
||||||
|
uncategorized = [ch for ch in channels if not ch.category_id]
|
||||||
if uncategorized:
|
if uncategorized:
|
||||||
console.print(f"[bold yellow]Uncategorized[/bold yellow]")
|
table.add_row("Uncategorized", "", "")
|
||||||
for ch in uncategorized:
|
for ch in uncategorized:
|
||||||
print_channel(ch)
|
fluxer_ch_id = self.engine.state.get_fluxer_channel_id(str(ch.id))
|
||||||
|
ch_status = f"[cyan]{fluxer_ch_id}[/cyan]" if fluxer_ch_id else "[red]Missing[/red]"
|
||||||
|
table.add_row(" Channel", ch.name, ch_status)
|
||||||
|
|
||||||
|
console.print(table)
|
||||||
console.print("")
|
console.print("")
|
||||||
|
|
||||||
# Check for existing mappings to determine if we should suggest a force re-copy
|
# Check for existing mappings to determine if we should suggest a force re-copy
|
||||||
|
|
@ -295,42 +301,7 @@ class MigrationCLI:
|
||||||
force = False
|
force = False
|
||||||
if cached_count > 0:
|
if cached_count > 0:
|
||||||
console.print(f"[yellow]\u26a0 {cached_count}/{all_ids_len} item(s) already in state.json cache.[/yellow]")
|
console.print(f"[yellow]\u26a0 {cached_count}/{all_ids_len} item(s) already in state.json cache.[/yellow]")
|
||||||
|
# End of table consolidated section, back to standard flow logic.
|
||||||
# List missing items
|
|
||||||
missing_categories = [cat for cat in categories if not self.engine.state.get_fluxer_category_id(str(cat.id))]
|
|
||||||
missing_channels = [ch for ch in channels if not self.engine.state.get_fluxer_channel_id(str(ch.id))]
|
|
||||||
|
|
||||||
if missing_categories or missing_channels:
|
|
||||||
console.print("\n[bold red]The following channels/categories are missing in your fluxer server:[/bold red]")
|
|
||||||
|
|
||||||
# Group missing channels by their categories
|
|
||||||
missing_by_cat = {}
|
|
||||||
missing_uncategorized = []
|
|
||||||
for ch in missing_channels:
|
|
||||||
cat_id = str(ch.category_id) if ch.category_id else None
|
|
||||||
if cat_id:
|
|
||||||
if cat_id not in missing_by_cat: missing_by_cat[cat_id] = []
|
|
||||||
missing_by_cat[cat_id].append(ch)
|
|
||||||
else:
|
|
||||||
missing_uncategorized.append(ch)
|
|
||||||
|
|
||||||
# Iterate through all categories to print missing ones or categories with missing children
|
|
||||||
for cat in categories:
|
|
||||||
cat_id_str = str(cat.id)
|
|
||||||
is_cat_missing = not self.engine.state.get_fluxer_category_id(cat_id_str)
|
|
||||||
child_missing_channels = missing_by_cat.get(cat_id_str, [])
|
|
||||||
|
|
||||||
if is_cat_missing or child_missing_channels:
|
|
||||||
footer = " [dim](Category itself is missing)[/dim]" if is_cat_missing else ""
|
|
||||||
console.print(f"[bold yellow]{cat.name}[/bold yellow]{footer}")
|
|
||||||
for ch in child_missing_channels:
|
|
||||||
print_channel(ch)
|
|
||||||
|
|
||||||
if missing_uncategorized:
|
|
||||||
console.print(f"[bold yellow]Uncategorized[/bold yellow]")
|
|
||||||
for ch in missing_uncategorized:
|
|
||||||
print_channel(ch)
|
|
||||||
console.print("")
|
|
||||||
|
|
||||||
console.print("[bold green](Y) Continue with only missing items[/bold green]")
|
console.print("[bold green](Y) Continue with only missing items[/bold green]")
|
||||||
console.print("[bold red](F) Force re-clone, creates duplicate channels![/bold red]")
|
console.print("[bold red](F) Force re-clone, creates duplicate channels![/bold red]")
|
||||||
|
|
@ -381,7 +352,7 @@ class MigrationCLI:
|
||||||
|
|
||||||
async def copy_roles(self):
|
async def copy_roles(self):
|
||||||
console.print("\n[bold]Role & Permission Options[/bold]")
|
console.print("\n[bold]Role & Permission Options[/bold]")
|
||||||
console.print("(1) Copy Roles & Role Permissions")
|
console.print("(1) Clone Roles & Role Permissions")
|
||||||
console.print("(2) Sync Category Permissions & Channel Permissions")
|
console.print("(2) Sync Category Permissions & Channel Permissions")
|
||||||
console.print("(B) Back")
|
console.print("(B) Back")
|
||||||
|
|
||||||
|
|
@ -391,8 +362,47 @@ class MigrationCLI:
|
||||||
return
|
return
|
||||||
|
|
||||||
if choice == "1":
|
if choice == "1":
|
||||||
console.print("\n[bold green]Starting Role Migration...[/bold green]")
|
|
||||||
try:
|
try:
|
||||||
|
await self.engine.start_connections()
|
||||||
|
|
||||||
|
with console.status("[yellow]Checking Fluxer for existing roles...[/yellow]"):
|
||||||
|
await self.engine.sync_roles_state()
|
||||||
|
|
||||||
|
roles = await self.engine.discord_reader.get_roles()
|
||||||
|
|
||||||
|
table = Table(show_header=True, header_style="bold magenta")
|
||||||
|
table.add_column("Discord Role")
|
||||||
|
table.add_column("Status", justify="center")
|
||||||
|
table.add_column("Fluxer ID", justify="right")
|
||||||
|
|
||||||
|
cached_count = 0
|
||||||
|
for r in roles:
|
||||||
|
fluxer_id = self.engine.state.get_fluxer_role_id(str(r.id))
|
||||||
|
status = "[bold green]NEW[/bold green]"
|
||||||
|
fid_str = "[dim]N/A[/dim]"
|
||||||
|
if fluxer_id:
|
||||||
|
status = "[dim]already copied[/dim]"
|
||||||
|
fid_str = f"[cyan]{fluxer_id}[/cyan]"
|
||||||
|
cached_count += 1
|
||||||
|
table.add_row(r.name, status, fid_str)
|
||||||
|
|
||||||
|
console.print(table)
|
||||||
|
|
||||||
|
force = False
|
||||||
|
if cached_count > 0:
|
||||||
|
console.print(f"\n[yellow]{cached_count} role(s) already in state cache.[/yellow]")
|
||||||
|
console.print("[bold green](Y) Sync missing roles only[/bold green]")
|
||||||
|
console.print("[bold red](F) Force Overwrite[/bold red]")
|
||||||
|
console.print("[bold yellow](B) Back[/bold yellow]")
|
||||||
|
|
||||||
|
sub_choice = Prompt.ask("Select an option", choices=["Y", "F", "B"], default="Y").upper()
|
||||||
|
|
||||||
|
if sub_choice == "B":
|
||||||
|
return
|
||||||
|
elif sub_choice == "F":
|
||||||
|
force = True
|
||||||
|
|
||||||
|
console.print("\n[bold green]Starting Role Migration...[/bold green]")
|
||||||
with Progress(
|
with Progress(
|
||||||
SpinnerColumn(),
|
SpinnerColumn(),
|
||||||
TextColumn("[progress.description]{task.description}"),
|
TextColumn("[progress.description]{task.description}"),
|
||||||
|
|
@ -401,14 +411,13 @@ class MigrationCLI:
|
||||||
console=console
|
console=console
|
||||||
) as progress:
|
) as progress:
|
||||||
|
|
||||||
role_task = progress.add_task("[cyan]Copying Roles...", total=100)
|
role_task = progress.add_task("[cyan]Syncing Roles...", total=100)
|
||||||
|
|
||||||
async def update_progress(item_name: str, current: int, total: int):
|
async def update_progress(item_name: str, current: int, total: int):
|
||||||
progress.update(role_task, total=total, completed=current, description=f"[cyan]Copying Role: {item_name}")
|
progress.update(role_task, total=total, completed=current, description=f"[cyan]Syncing Role: {item_name}")
|
||||||
|
|
||||||
await self.engine.start_connections()
|
|
||||||
self.engine.is_running = True
|
self.engine.is_running = True
|
||||||
await self.engine.migrate_roles(progress_callback=update_progress)
|
await self.engine.migrate_roles(progress_callback=update_progress, force=force)
|
||||||
|
|
||||||
console.print("[bold green]Role migration complete![/bold green]")
|
console.print("[bold green]Role migration complete![/bold green]")
|
||||||
|
|
||||||
|
|
@ -419,8 +428,27 @@ class MigrationCLI:
|
||||||
self.engine.is_running = False
|
self.engine.is_running = False
|
||||||
|
|
||||||
elif choice == "2":
|
elif choice == "2":
|
||||||
console.print("\n[bold green]Syncing Category & Channel Permissions...[/bold green]")
|
|
||||||
try:
|
try:
|
||||||
|
await self.engine.start_connections()
|
||||||
|
|
||||||
|
with console.status("[yellow]Analyzing categories and channels...[/yellow]"):
|
||||||
|
categories = await self.engine.discord_reader.get_categories()
|
||||||
|
channels = await self.engine.discord_reader.get_channels()
|
||||||
|
|
||||||
|
mapped_cats = sum(1 for c in categories if self.engine.state.get_fluxer_category_id(str(c.id)))
|
||||||
|
mapped_chs = sum(1 for c in channels if self.engine.state.get_fluxer_channel_id(str(c.id)))
|
||||||
|
total_mapped = mapped_cats + mapped_chs
|
||||||
|
|
||||||
|
console.print(f"\n[yellow]Ready to sync permissions for {total_mapped} items ({mapped_cats} categories, {mapped_chs} channels).[/yellow]")
|
||||||
|
console.print("[bold green](Y) Proceed with Permission synchronization[/bold green]")
|
||||||
|
console.print("[bold yellow](B) Back[/bold yellow]")
|
||||||
|
|
||||||
|
sub_choice = Prompt.ask("Select an option", choices=["Y", "B"], default="Y").upper()
|
||||||
|
|
||||||
|
if sub_choice == "B":
|
||||||
|
return
|
||||||
|
|
||||||
|
console.print("\n[bold green]Syncing Category & Channel Permissions...[/bold green]")
|
||||||
with Progress(
|
with Progress(
|
||||||
SpinnerColumn(),
|
SpinnerColumn(),
|
||||||
TextColumn("[progress.description]{task.description}"),
|
TextColumn("[progress.description]{task.description}"),
|
||||||
|
|
@ -434,7 +462,6 @@ class MigrationCLI:
|
||||||
async def update_progress(item_name: str, current: int, total: int):
|
async def update_progress(item_name: str, current: int, total: int):
|
||||||
progress.update(perm_task, total=total, completed=current, description=f"[cyan]Syncing: {item_name}")
|
progress.update(perm_task, total=total, completed=current, description=f"[cyan]Syncing: {item_name}")
|
||||||
|
|
||||||
await self.engine.start_connections()
|
|
||||||
self.engine.is_running = True
|
self.engine.is_running = True
|
||||||
await self.engine.sync_permissions(progress_callback=update_progress)
|
await self.engine.sync_permissions(progress_callback=update_progress)
|
||||||
|
|
||||||
|
|
@ -457,22 +484,29 @@ class MigrationCLI:
|
||||||
emojis = await self.engine.discord_reader.get_emojis()
|
emojis = await self.engine.discord_reader.get_emojis()
|
||||||
stickers = await self.engine.discord_reader.get_stickers()
|
stickers = await self.engine.discord_reader.get_stickers()
|
||||||
|
|
||||||
console.print(f"\n[bold]Custom emojis found: {len(emojis)}[/bold]")
|
table = Table(show_header=True, header_style="bold magenta")
|
||||||
|
table.add_column("Type", width=10)
|
||||||
|
table.add_column("Name")
|
||||||
|
table.add_column("Status", justify="right")
|
||||||
|
|
||||||
|
cached_emojis = 0
|
||||||
for e in emojis:
|
for e in emojis:
|
||||||
already = self.engine.state.get_fluxer_emoji_id(str(e.id))
|
already = self.engine.state.get_fluxer_emoji_id(str(e.id))
|
||||||
tag = " [dim](already copied)[/dim]" if already else ""
|
status = "[dim]already copied[/dim]" if already else "[bold green]NEW[/bold green]"
|
||||||
console.print(f" - Emoji: {e.name}{tag}")
|
if already: cached_emojis += 1
|
||||||
|
table.add_row("Emoji", e.name, status)
|
||||||
|
|
||||||
console.print(f"[bold]Custom stickers found: {len(stickers)}[/bold]")
|
cached_stickers = 0
|
||||||
for s in stickers:
|
for s in stickers:
|
||||||
already = self.engine.state.get_fluxer_sticker_id(str(s.id))
|
already = self.engine.state.get_fluxer_sticker_id(str(s.id))
|
||||||
tag = " [dim](already copied)[/dim]" if already else ""
|
status = "[dim]already copied[/dim]" if already else "[bold green]NEW[/bold green]"
|
||||||
console.print(f" - Sticker: {s.name}{tag}")
|
if already: cached_stickers += 1
|
||||||
|
table.add_row("Sticker", s.name, status)
|
||||||
|
|
||||||
|
console.print(table)
|
||||||
|
|
||||||
# Warn if everything is already in the state cache
|
# Warn if everything is already in the state cache
|
||||||
force = False
|
force = False
|
||||||
cached_emojis = sum(1 for e in emojis if self.engine.state.get_fluxer_emoji_id(str(e.id)))
|
|
||||||
cached_stickers = sum(1 for s in stickers if self.engine.state.get_fluxer_sticker_id(str(s.id)))
|
|
||||||
total_items = len(emojis) + len(stickers)
|
total_items = len(emojis) + len(stickers)
|
||||||
cached_count = cached_emojis + cached_stickers
|
cached_count = cached_emojis + cached_stickers
|
||||||
|
|
||||||
|
|
@ -558,9 +592,17 @@ class MigrationCLI:
|
||||||
icon_status = "[bold green]FOUND[/bold green]" if metadata.get("icon_url") else "[yellow]NOT FOUND[/yellow]"
|
icon_status = "[bold green]FOUND[/bold green]" if metadata.get("icon_url") else "[yellow]NOT FOUND[/yellow]"
|
||||||
banner_status = "[bold green]FOUND[/bold green]" if metadata.get("banner_url") else "[yellow]NOT FOUND[/yellow]"
|
banner_status = "[bold green]FOUND[/bold green]" if metadata.get("banner_url") else "[yellow]NOT FOUND[/yellow]"
|
||||||
|
|
||||||
console.print(f"\n[bold]Server Name:[/bold] {name}")
|
banner_status = "[bold green]FOUND[/bold green]" if metadata.get("banner_url") else "[yellow]NOT FOUND[/yellow]"
|
||||||
console.print(f"[bold]Server Icon:[/bold] {icon_status}")
|
|
||||||
console.print(f"[bold]Server Banner:[/bold] {banner_status}")
|
table = Table(show_header=False, box=None)
|
||||||
|
table.add_column("Property", style="bold")
|
||||||
|
table.add_column("Value")
|
||||||
|
|
||||||
|
table.add_row("Server Name:", name)
|
||||||
|
table.add_row("Server Icon:", icon_status)
|
||||||
|
table.add_row("Server Banner:", banner_status)
|
||||||
|
|
||||||
|
console.print(Panel(table, title="[bold]Discord Server Metadata[/bold]", expand=False))
|
||||||
|
|
||||||
console.print("\n(1) Sync Name only")
|
console.print("\n(1) Sync Name only")
|
||||||
console.print("(2) Sync Icon only")
|
console.print("(2) Sync Icon only")
|
||||||
|
|
@ -762,16 +804,30 @@ class MigrationCLI:
|
||||||
finally:
|
finally:
|
||||||
self.engine.is_running = False
|
self.engine.is_running = False
|
||||||
|
|
||||||
console.print(f"\n[bold]Migration Summary:[/bold]")
|
table = Table(show_header=True, header_style="bold magenta", title="Migration Summary & Estimates")
|
||||||
console.print(f"Number of messages: [bold cyan]{stats['messages']}[/bold cyan]")
|
table.add_column("Item", width=15)
|
||||||
console.print(f"Number of threads: [bold cyan]{stats['threads']}[/bold cyan]")
|
table.add_column("Count", justify="right", width=10)
|
||||||
console.print(f"Number of attachments: [bold cyan]{stats['attachments']}[/bold cyan]")
|
table.add_column("Overhead/Details")
|
||||||
|
|
||||||
console.print("\n[bold yellow]Estimated Overhead:[/bold yellow]")
|
|
||||||
msg_time = stats['messages'] * self.config.migration.rate_limit_delay_seconds
|
msg_time = stats['messages'] * self.config.migration.rate_limit_delay_seconds
|
||||||
console.print(f"- [bold]Messages:[/bold] ~{msg_time}s delay (rate limiting), {stats['messages']} API writes.")
|
table.add_row(
|
||||||
console.print(f"- [bold]Threads:[/bold] {stats['threads'] * 2} extra marker messages, {stats['threads']} extra history fetches.")
|
"Messages",
|
||||||
console.print(f"- [bold]Attachments:[/bold] {stats['attachments']} downloads and uploads (bandwidth & API calls).")
|
f"[bold cyan]{stats['messages']}[/bold cyan]",
|
||||||
|
f"~{msg_time}s delay (rate limiting), {stats['messages']} API writes"
|
||||||
|
)
|
||||||
|
table.add_row(
|
||||||
|
"Threads",
|
||||||
|
f"[bold cyan]{stats['threads']}[/bold cyan]",
|
||||||
|
f"{stats['threads'] * 2} extra marker messages, {stats['threads']} extra history fetches"
|
||||||
|
)
|
||||||
|
table.add_row(
|
||||||
|
"Attachments",
|
||||||
|
f"[bold cyan]{stats['attachments']}[/bold cyan]",
|
||||||
|
f"{stats['attachments']} downloads and uploads (bandwidth & API calls)"
|
||||||
|
)
|
||||||
|
|
||||||
|
console.print("")
|
||||||
|
console.print(table)
|
||||||
|
|
||||||
if not Confirm.ask(f"\nMigrate messages from Discord [cyan]#{source_channel.name}[/cyan] to Fluxer [magenta]#{target_channel.get('name')}[/magenta]?"):
|
if not Confirm.ask(f"\nMigrate messages from Discord [cyan]#{source_channel.name}[/cyan] to Fluxer [magenta]#{target_channel.get('name')}[/magenta]?"):
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue