Spaces:
Sleeping
Sleeping
File size: 1,414 Bytes
9209fc6 a9a360b 2dea10d a9a360b 9209fc6 2dea10d a9a360b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import re
from typing import Optional
def normalize_instagram_url(url: str) -> str:
"""Strip query strings and normalize Instagram Reel/Post URLs to canonical form."""
if not url:
return ""
match = re.search(r"instagram\.com/(reel|reels|p)/([A-Za-z0-9_\-]+)", url.strip())
if match:
kind = "reel" if match.group(1) in ("reel", "reels") else "p"
return f"https://www.instagram.com/{kind}/{match.group(2)}/"
return url.strip().split("?")[0]
def parse_saved_posts(data: list) -> list:
"""Return [{url, caption, title}] for every /reel/ URL in the export.
Drops photo (/p/) posts because they lack audio.
"""
items = []
seen = set()
for entry in data:
url = caption = title = ""
for lv in entry.get("label_values", []):
label = lv.get("label")
if label == "URL":
url = lv.get("value", "")
elif label == "Caption":
caption = lv.get("value", "")
elif label == "Title":
title = lv.get("value", "")
if url and ("/reel/" in url or "/reels/" in url):
clean_url = normalize_instagram_url(url)
if clean_url not in seen: # a reel saved to two collections is listed twice
seen.add(clean_url)
items.append({"url": clean_url, "caption": caption, "title": title})
return items
|