Remove Instagram accounts or web aggregators from sources.yaml configuration
Removes Instagram accounts or web aggregators from your sources.yaml configuration file. Used when you want to delete sources by handle, URL, or name.
/plugin marketplace add aniketpanjwani/local_media_tools/plugin install newsletter-events@local-media-toolsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
<essential_principles>
All sources are stored in ~/.config/local-media-tools/sources.yaml.
| Input | Matches |
|---|---|
@handle | Instagram account by handle |
handle (no @) | Instagram account by handle |
https://site.com | Web aggregator by URL |
"Page Name" | Any source by name (asks if ambiguous) |
Note: Facebook events are not stored in configuration, so there's nothing to remove.
Examples:
@localvenue - Remove Instagram account@venue1 @venue2 - Remove multiple Instagram accountshttps://events.com - Remove web aggregator"Local Venue" - Remove by name (any type)Provide the source(s) to remove: </intake>
<process> ## Step 1: Parse IdentifiersAnalyze the user's input to extract sources to remove:
Instagram detection:
@ → Instagram handleWeb Aggregator detection:
Name detection:
Extract multiple sources:
from pathlib import Path
import yaml
config_path = Path.home() / ".config" / "local-media-tools" / "sources.yaml"
if not config_path.exists():
print("ERROR: sources.yaml not found. Run /newsletter-events:setup first.")
# STOP HERE
with open(config_path) as f:
config = yaml.safe_load(f)
For each identifier, find matches:
def find_matches(identifier: str, config: dict) -> list:
"""
Match priority:
1. Exact Instagram handle (case-insensitive)
2. Exact Web URL (normalized)
3. Exact name match (any type)
"""
matches = []
normalized = identifier.lower().lstrip("@").strip('"\'')
sources = config.get("sources", {})
# Check Instagram handles
for account in sources.get("instagram", {}).get("accounts", []):
if account["handle"].lower() == normalized:
matches.append({"type": "instagram", "item": account, "match": "handle"})
# Check Web aggregators
for source in sources.get("web_aggregators", {}).get("sources", []):
if normalized in source["url"].lower():
matches.append({"type": "web", "item": source, "match": "url"})
# Check names (all types) if no URL/handle matches
if not matches:
for account in sources.get("instagram", {}).get("accounts", []):
if account.get("name", "").lower() == normalized:
matches.append({"type": "instagram", "item": account, "match": "name"})
for source in sources.get("web_aggregators", {}).get("sources", []):
if source.get("name", "").lower() == normalized:
matches.append({"type": "web", "item": source, "match": "name"})
return matches
If an identifier matches multiple sources, ask the user to clarify:
Multiple sources match 'venue':
1. @venue (Instagram) - Local Venue
2. https://venue.com (Web) - Venue Events
Which one(s) to remove? (Enter numbers separated by commas, or 'all'):
If removing 4+ sources, ask for confirmation:
About to remove 5 sources:
- @localvenue (Instagram)
- @oldbar (Instagram)
- @closedgallery (Instagram)
- https://defunctsite.com (Web)
- https://oldsite.com (Web)
This cannot be undone. Continue? (y/n):
import shutil
from datetime import datetime
backup_path = config_path.with_suffix(f".yaml.{datetime.now():%Y%m%d%H%M%S}.backup")
shutil.copy2(config_path, backup_path)
removed = []
not_found = []
for identifier, matches in matched_sources.items():
if not matches:
not_found.append(identifier)
continue
for match in matches:
if match["type"] == "instagram":
config["sources"]["instagram"]["accounts"] = [
a for a in config["sources"]["instagram"]["accounts"]
if a["handle"].lower() != match["item"]["handle"].lower()
]
elif match["type"] == "web":
config["sources"]["web_aggregators"]["sources"] = [
s for s in config["sources"]["web_aggregators"]["sources"]
if s["url"].lower() != match["item"]["url"].lower()
]
removed.append(match)
If removing an Instagram account, also clean up priority_handles:
# Get remaining handles
remaining_handles = {
a["handle"].lower()
for a in config["sources"]["instagram"]["accounts"]
}
# Clean priority_handles
if "priority_handles" in config["sources"]["instagram"]:
original_priority = config["sources"]["instagram"]["priority_handles"]
config["sources"]["instagram"]["priority_handles"] = [
h for h in original_priority
if h.lower() in remaining_handles
]
cleaned_priority = set(original_priority) - set(config["sources"]["instagram"]["priority_handles"])
if cleaned_priority:
print(f"Also removed from priority_handles: {', '.join(cleaned_priority)}")
from config.config_schema import AppConfig
try:
AppConfig.from_yaml(config_path)
except Exception as e:
# Restore backup
shutil.copy2(backup_path, config_path)
print(f"ERROR: Invalid config after removal. Restored backup. Error: {e}")
# STOP HERE
with open(config_path, "w") as f:
yaml.dump(config, f, default_flow_style=False, sort_keys=False, allow_unicode=True)
Display a summary:
Removing sources...
✓ Removed @localvenue (Local Venue) from Instagram accounts
✓ Removed @oldbar (Old Bar) from Instagram accounts
Also removed from priority_handles
✓ Removed https://oldsite.com (Old Site) from web aggregators
✗ Not found: @unknownhandle
Summary: 3 removed, 1 not found
Config backup: sources.yaml.20250120143022.backup
To undo: cp ~/.config/local-media-tools/sources.yaml.20250120143022.backup ~/.config/local-media-tools/sources.yaml
Remaining sources: 4 (run /newsletter-events:list-sources to view)
</process>
<success_criteria>