Remove Instagram accounts, Facebook pages, or web aggregators from sources.yaml configuration
This 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 |
facebook.com/page/events | Facebook page by URL |
https://site.com | Web aggregator by URL |
"Page Name" | Any source by name (asks if ambiguous) |
Examples:
@localvenue - Remove Instagram account@venue1 @venue2 - Remove multiple Instagram accountshttps://facebook.com/venue/events - Remove Facebook page"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 handleFacebook detection:
facebook.com → Facebook page/groupWeb 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 Facebook URL (normalized)
3. Exact Web URL (normalized)
4. 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 Facebook pages
for page in sources.get("facebook", {}).get("pages", []):
if normalized in page["url"].lower():
matches.append({"type": "facebook_page", "item": page, "match": "url"})
# Check Facebook groups
for group in sources.get("facebook", {}).get("groups", []):
if normalized in group["url"].lower():
matches.append({"type": "facebook_group", "item": group, "match": "url"})
# 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 page in sources.get("facebook", {}).get("pages", []):
if page.get("name", "").lower() == normalized:
matches.append({"type": "facebook_page", "item": page, "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. facebook.com/venue/events (Facebook) - The Venue
3. 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)
- facebook.com/shutdownvenue/events (Facebook)
- https://defunctsite.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"] == "facebook_page":
config["sources"]["facebook"]["pages"] = [
p for p in config["sources"]["facebook"]["pages"]
if p["url"].lower() != match["item"]["url"].lower()
]
elif match["type"] == "facebook_group":
config["sources"]["facebook"]["groups"] = [
g for g in config["sources"]["facebook"]["groups"]
if g["url"].lower() != match["item"]["url"].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 facebook.com/closedvenue/events (Closed Venue) from Facebook pages
✗ 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>