add graceful handling of duplicate channel names

This commit is contained in:
rambros 2026-03-01 16:54:42 +05:30
parent fea2f8f573
commit 27f8d98c69
4 changed files with 58 additions and 10 deletions

View file

@ -1,7 +1,7 @@
import sys
import asyncio
import logging
from src.ui.disco_reaper_app import run_disco_reaper
from src.ui.reaper_app import run_disco_reaper
from src.core.configuration import load_config
def setup_logging():

View file

@ -2,7 +2,7 @@ import sys
import asyncio
import logging
from pathlib import Path
from src.ui.app import run_cli
from src.ui.shuttle_app import run_cli
from src.core.configuration import load_config
def setup_logging():

View file

@ -85,10 +85,10 @@ class DiscoReaperCLI:
console.print("(1) Backup Server Profile")
console.print("(2) Backup Messages")
console.print("(3) Update & Sync Backup")
console.print("(C) Configuration")
console.print("(4) Configuration")
console.print("(Q) Exit")
choice = Prompt.ask("\nSelect an option", choices=["1", "2", "3", "C", "Q"], default="Q", show_choices=False).upper()
choice = Prompt.ask("\nSelect an option", choices=["1", "2", "3", "4", "Q"], default="Q", show_choices=False).upper()
if choice == "1":
await self.backup_server_profile()
@ -96,7 +96,7 @@ class DiscoReaperCLI:
await self.backup_messages()
elif choice == "3":
await self.sync_backup()
elif choice == "C":
elif choice == "4":
await self.edit_configuration()
elif choice == "Q":
await self.engine.close_connections()
@ -154,7 +154,11 @@ class DiscoReaperCLI:
await self.exporter.export_channels_structure()
# 2. Select Channels
all_channels = await self.engine.discord_reader.get_channels()
with console.status("[yellow]Fetching channels & categories...[/yellow]"):
all_channels = await self.engine.discord_reader.get_channels()
all_categories = await self.engine.discord_reader.get_categories()
cat_map = {c.id: c.name for c in all_categories}
# Filter for exportable channels
eligible_channels = [
c for c in all_channels
@ -166,8 +170,19 @@ class DiscoReaperCLI:
return
console.print(f"\n[bold]Select Channels to Backup ({len(eligible_channels)} total):[/bold]")
# Identify duplicate names to show categories for them
name_counts = {}
for chan in eligible_channels:
name_counts[chan.name] = name_counts.get(chan.name, 0) + 1
for i, chan in enumerate(eligible_channels):
console.print(f"({i+1}) {chan.name}")
display_name = chan.name
if name_counts[chan.name] > 1:
cat_name = cat_map.get(chan.category_id)
if cat_name:
display_name = f"{chan.name} [{cat_name}]"
console.print(f"({i+1}) {display_name}")
console.print("(A) [bold green]All Channels[/bold green]")
console.print("(B) Back")

View file

@ -1065,17 +1065,30 @@ class MigrationCLI:
return
try:
with console.status("[yellow]Fetching Discord channels...[/yellow]"):
with console.status("[yellow]Fetching Discord channels & categories...[/yellow]"):
await self.engine.start_connections()
d_channels = await self.engine.discord_reader.get_channels()
d_categories = await self.engine.discord_reader.get_categories()
d_cat_map = {c.id: c.name for c in d_categories}
if not d_channels:
console.print("[yellow]No text channels found in Discord server.[/yellow]")
return
console.print("\n[bold]Select Source Discord Channel:[/bold]")
# Identify duplicate names to show categories for them
d_name_counts = {}
for ch in d_channels:
d_name_counts[ch.name] = d_name_counts.get(ch.name, 0) + 1
for i, ch in enumerate(d_channels):
console.print(f"({i+1}) {ch.name}")
display_name = ch.name
if d_name_counts[ch.name] > 1:
cat_name = d_cat_map.get(ch.category_id)
if cat_name:
display_name = f"{ch.name} [{cat_name}]"
console.print(f"({i+1}) {display_name}")
console.print("(B) Back")
d_choices = [str(i+1) for i in range(len(d_channels))] + ["B", "b"]
@ -1113,8 +1126,28 @@ class MigrationCLI:
console.print(f"\n[bold]Select Target {platform_name} Channel:[/bold]")
# Identify duplicate names to show categories for them
f_name_counts = {}
for ch in f_channels:
name = ch.get('name', 'Unnamed Channel')
f_name_counts[name] = f_name_counts.get(name, 0) + 1
# Get category map for target platform
# For Fluxer/Stoat, the channel object in f_channels contains 'parent_id'
# We need to resolve these IDs to names.
target_cat_names = {}
for ch in full_f_channels: # use full list including categories (type 4)
if ch.get('type') == 4:
target_cat_names[str(ch.get('id'))] = ch.get('name')
for i, ch in enumerate(f_channels):
console.print(f"({i+1}) {ch.get('name', 'Unnamed Channel')}")
name = ch.get('name', 'Unnamed Channel')
display_name = name
if f_name_counts[name] > 1:
parent_id = ch.get('parent_id')
if parent_id and str(parent_id) in target_cat_names:
display_name = f"{name} [{target_cat_names[str(parent_id)]}]"
console.print(f"({i+1}) {display_name}")
f_choices = [str(i+1) for i in range(len(f_channels))] + ["B", "b", "N", "n"]