بلاگ / ڈویلپر گائیڈ
سوشل میڈیا پروفائل URLs کو پارس اور نارملائز کیسے کریں (Instagram، TikTok، YouTube، X)
کریئیٹرز اپنے پروفائل لنکس ہر ممکن شکل میں پیسٹ کرتے ہیں: www کے ساتھ اور بغیر، موبائل ایپ سے ٹریکنگ پیرامیٹرز کے ساتھ، شارٹ لنکس کی صورت میں، پرانے twitter.com URLs کی صورت میں، یا پروفائل کی بجائے کسی پوسٹ کا لنک۔ اگر آپ کی پروڈکٹ یہ strings جیسی آئیں ویسی ہی محفوظ کرے تو ایک ہی کریئیٹر تین بار نظر آتا ہے اور آپ کے joins خاموشی سے چوک جاتے ہیں۔ یہ گائیڈ بتاتی ہے کہ کسی بھی Instagram، TikTok، YouTube یا X پروفائل URL کو پلیٹ فارم، ہینڈل یا چینل ID، اور ایک معیاری URL میں کیسے بدلیں، JavaScript اور Python کے جانچے ہوئے کوڈ کے ساتھ۔
پروفائل URLs کو نارملائز کرنا کیوں ضروری ہے
پروفائل URL ایک شناخت کنندہ ہے، اور شناخت کنندہ تبھی کام کرتے ہیں جب وہ ایک ہی طرح لکھے جائیں۔ https://www.instagram.com/natgeo/، instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA== اور https://m.instagram.com/natgeo سب ایک ہی اکاؤنٹ کی طرف اشارہ کرتے ہیں، لیکن strings کے طور پر یہ تین الگ قدریں ہیں۔
- دہرائی ہٹانا (deduplication)۔ جب کوئی کریئیٹر دو بار سائن اپ کرے، یا ٹیم کے دو لوگ ایک ہی انفلوئنسر کو کیمپین میں شامل کریں، تو آپ کو ایک ریکارڈ چاہیے، دو نہیں۔
- Joins۔ اپنے CRM کو کسی اور ٹول کی ایکسپورٹ سے ملانا تبھی کام کرتا ہے جب دونوں طرف ایک ہی کلید ہو۔
- غلط ان پٹ کو شروع میں روکنا۔ reel، سرچ صفحے یا لاگ ان اسکرین کا لنک پروفائل نہیں۔ اسے ان پٹ کے وقت پکڑنا بعد میں صفائی سے سستا ہے۔
- APIs کو کال کرنا۔ سرکاری APIs کو ہینڈل یا ID چاہیے، ٹریکنگ پیرامیٹرز والا URL نہیں۔
مقصد ایک چھوٹا، سخت فنکشن ہے: یہ وہ سب قبول کرے جو صارفین واقعی پیسٹ کرتے ہیں، اصل پروفائل URLs کے لیے نارملائز نتیجہ لوٹائے، اور باقی ہر چیز کے لیے null۔
URLs کی وہ شکلیں جو آپ کو ملیں گی
نیچے دی گئی شکلیں اکتوبر 2026 میں لائیو سائٹس پر جانچی گئیں۔ پلیٹ فارمز بغیر اطلاع اپنی روٹنگ بدل دیتے ہیں، اس لیے اسے ایک وقتی تصویر سمجھیں اور اپنے ٹیسٹ کیسز تازہ رکھیں۔
- پروفائلز
https://www.instagram.com/<handle>/پر ہوتے ہیں۔ سادہinstagram.comاورm.instagram.comہوسٹسwww.instagram.comپر ری ڈائریکٹ ہوتے ہیں۔ - ایپ سے شیئر کیے گئے لنکس میں اکثر
?igsh=پیرامیٹر ہوتا ہے۔ پوری query string اور fragment ہٹا دیں۔ - پوسٹس
/p/<code>/، reels/reel/<code>/اور stories/stories/<handle>/<id>/ہیں۔ ان میں سے کوئی بھی پروفائل URL نہیں، چاہے path میں ہینڈل ہو۔ /explore/،/accounts/اور/direct/جیسے ایپ روٹس path کا پہلا حصہ ہینڈلز کے ساتھ شیئر کرتے ہیں، اس لیے آپ کو مخصوص الفاظ کی فہرست چاہیے۔ نیچے کوڈ والی فہرست مکمل نہیں۔
TikTok
- پروفائلز
https://www.tiktok.com/@<handle>ہیں۔ سادہtiktok.comہوسٹwwwپر ری ڈائریکٹ ہوتا ہے۔ - ویڈیوز
/@<handle>/video/<id>ہیں۔ ہینڈل مصنف کا ہے، لیکن URL ویڈیو کا لنک ہے، اس لیے نیچے والا پارسر اسے رد کرتا ہے۔ vm.tiktok.com،vt.tiktok.comاورwww.tiktok.com/t/<code>/والے شارٹ لنکس میں کوئی ہینڈل نہیں ہوتا۔ یہ کہاں لے جاتے ہیں دیکھنے کے لیے HTTP ری ڈائریکٹ فالو کرنا پڑتا ہے، پھر آخری URL پارس کریں۔@کے بغیر path (مثلاًtiktok.com/khaby.lame) پروفائل URL نہیں۔
YouTube
- ہینڈل URLs:
https://www.youtube.com/@<handle>۔ YouTube کے Help Center کے مطابق ہینڈل خود بخود چینل کا URL بن جاتا ہے۔ - چینل ID URLs:
https://www.youtube.com/channel/UC...۔ یہی مستقل شکل ہے۔ عملاً چینل IDs 24 حروف کی ہوتی ہیں اورUCسے شروع ہوتی ہیں۔ Google اس شکل کو دستاویزی نہیں کرتا، اس لیے نیچے والی جانچ ایک معقول حد ہے، اصول نہیں۔ - پرانی شکلیں:
/user/<username>اور/c/<customname>۔ دونوں آج بھی کھلتی ہیں، اور Help Center کے مطابق پرانے ذاتی URLs کام کرتے رہیں گے۔ دونوں میں سے کوئی بھی تلاش کے بغیر چینل ID نہیں بتاتا۔ - کچھ چینلز کے لیے سادہ
youtube.com/<name>بھی ابھی کھلتا ہے، لیکن یہ سائٹ کے روٹس کے ساتھ namespace شیئر کرتا ہے، اس لیے نیچے والا پارسر اسے قبول نہیں کرتا۔ /@handle/videosاور/channel/UC.../featuredجیسے ٹیبز چینل کا حصہ ہیں اور انہیں قبول کرنا محفوظ ہے۔m.youtube.com،www.youtube.comپر ری ڈائریکٹ ہوتا ہے۔ ویڈیو لنکس (/watch?v=،/shorts/،youtu.be/<id>) چینلز نہیں۔
X (پہلے Twitter)
- پروفائلز
https://x.com/<handle>ہیں۔twitter.com،www.twitter.com،www.x.com،mobile.twitter.comاورmobile.x.comسبx.comیاtwitter.comپر کسی پروفائل کی طرف ری ڈائریکٹ ہوتے ہیں، اس لیے انہیں ایک ہی پلیٹ فارم سمجھیں۔ - پوسٹس
/<handle>/status/<id>ہیں۔ TikTok ویڈیوز کی طرح ان میں مصنف کا نام ہوتا ہے لیکن یہ پروفائل URLs نہیں۔ /home،/explore،/search،/settings،/notifications،/messagesجیسے ایپ روٹس اور/i/کے نیچے کی ہر چیز ہینڈل نہیں۔- شیئر کیے گئے لنکس میں اکثر
?s=اور?t=پیرامیٹرز ہوتے ہیں۔ انہیں ہٹا دیں۔
ہر پلیٹ فارم پر ہینڈل کے حروف کے اصول
ہینڈل کی جانچ ٹائپنگ کی غلطیاں اور زیادہ تر غیر پروفائل paths پکڑ لیتی ہے۔ جہاں پلیٹ فارمز اپنے اصول شائع کرتے ہیں وہاں انہی کو استعمال کریں، اور جہاں نہیں کرتے وہاں جانچ ڈھیلی رکھیں، تاکہ کوئی اصل اکاؤنٹ رد نہ ہو۔
| پلیٹ فارم | اجازت یافتہ حروف | لمبائی | چھوٹے بڑے حروف | ماخذ |
|---|---|---|---|---|
| حروف، اعداد، پیریڈ، انڈر اسکور | 30 عام طور پر بتایا جاتا ہے؛ Instagram کے ہیلپ صفحات میں نہیں ملا | فرق نہ ہونے والا سمجھیں؛ چھوٹے حروف میں محفوظ کریں | Instagram Help Center پیریڈ، اعداد اور انڈر اسکور کا ذکر کرتا ہے | |
| TikTok | حروف، اعداد، انڈر اسکور، پیریڈ؛ آخر میں پیریڈ نہیں ہو سکتا | 2 سے 24 | URLs میں فرق نہیں پڑتا (@TikTok، tiktok پر کھلتا ہے) | TikTok Support، یوزرنیم بدلنا |
| YouTube | سپورٹ شدہ زبانوں کے حروف یا اعداد، ساتھ انڈر اسکور، ہائفن، پیریڈ اور لاطینی درمیانی نقطے (پہلے یا آخر میں نہیں) | زیادہ تر رسم الخط کے لیے 3 سے 30؛ Han، Hangul اور کچھ دوسرے رسم الخط کے لیے کم حد | فرق نہیں پڑتا | YouTube Help، ہینڈل کی ہدایات |
| X | حروف، اعداد اور انڈر اسکور | 15 تک؛ نئے یوزرنیمز 4 سے لمبے ہونے چاہییں، لیکن پرانے چھوٹے ہینڈل موجود ہیں | فرق نہیں پڑتا (x.com/JACK، x.com/jack بن جاتا ہے) | X Help Center، یوزرنیم کے اصول |
نارملائزیشن کا الگورتھم
- Step 1تراشیں اور scheme لگائیں
اسپیس اور فالتو angle brackets ہٹائیں۔ اگر ان پٹ میں scheme نہیں تو شروع میں
https://لگائیں تاکہinstagram.com/natgeoپارس ہو جائے۔ - Step 2اصل URL پارسر سے پارس کریں
JavaScript میں
new URL()یا Python میںurllib.parse.urlsplitاستعمال کریں، پوری string پر regex کبھی نہیں۔ پارسر ports، user info اور encoded حروف سنبھالتا ہے، اورhttps://instagram.com@evil.com/natgeoکو Instagram بن کر گزرنے سے روکتا ہے۔ - Step 3ہوسٹ کو نارملائز کریں
اسے چھوٹے حروف میں بدلیں اور شروع کا ایک
www.،m.یاmobile.ہٹا دیں۔ پھر اسے ہوسٹس کی ایک درست allow-list میں دیکھیں۔includes("instagram.com")کبھی استعمال نہ کریں، یہinstagram.com.evil.comسے بھی میچ کرتا ہے۔ - Step 4query string اور fragment ہٹائیں
igsh،s،tاورlangجیسے ٹریکنگ پیرامیٹرز کبھی نہیں بدلتے کہ URL کس پروفائل کی طرف ہے۔ - Step 5path کو تقسیم اور ڈی کوڈ کریں
/پر تقسیم کریں، خالی حصے ہٹائیں (اس سے آخری slashes ہٹ جاتے ہیں) اور ہر حصے کو percent-decode کریں۔ خراب encoding کو غلط ان پٹ سمجھیں۔ - Step 6پلیٹ فارم کے حساب سے راستہ چنیں
ہر پلیٹ فارم کی شکل لاگو کریں: Instagram اور X پر ایک حصہ، TikTok پر
@والا حصہ، اور YouTube پر@handle،channel/UC...،user/nameیاc/name۔ مخصوص الفاظ رد کریں۔ - Step 7ہینڈل جانچیں اور چھوٹے حروف میں بدلیں
ہینڈل کو پلیٹ فارم کے حروف کے اصولوں پر جانچیں، پھر چھوٹے حروف میں بدلیں۔ YouTube چینل IDs کو چھوٹے حروف میں نہ بدلیں: ان میں چھوٹے بڑے حروف کا فرق اہم ہے۔
- Step 8معیاری URL بنائیں
حصوں سے ایک مقررہ ہوسٹ پر URL دوبارہ بنائیں، تاکہ ہر مساوی ان پٹ بالکل ایک ہی string دے۔
- Step 9شارٹ لنکس الگ سنبھالیں
TikTok شارٹ لنکس پہچانیں، HTTP درخواست سے ری ڈائریکٹ فالو کریں، اور آخری URL دوبارہ پارسر سے گزاریں۔ اسے خالص فنکشن سے باہر رکھیں تاکہ پارسنگ تیز اور قابلِ ٹیسٹ رہے۔
JavaScript اور Python میں کوڈ
دونوں فنکشن ایک ہی ان پٹ پر ایک جیسے objects لوٹاتے ہیں: ہینڈل URLs کے لیے { platform, handle, canonicalUrl }، YouTube چینل IDs کے لیے { platform, channelId, canonicalUrl }، YouTube کی دو پرانی شکلوں کے لیے username یا customName، اور جو کچھ پروفائل URL نہیں اس کے لیے null۔ کسی کو کوئی dependency نہیں چاہیے۔
JavaScript (Node 18+)
const HOSTS = {
"instagram.com": "instagram",
"tiktok.com": "tiktok",
"youtube.com": "youtube",
"x.com": "x",
"twitter.com": "x",
};
const IG_RESERVED = new Set(["p", "reel", "reels", "tv", "stories", "explore", "accounts", "direct"]);
const X_RESERVED = new Set([
"home", "explore", "search", "i", "settings", "notifications", "messages",
"compose", "intent", "hashtag", "login", "signup", "logout", "tos", "privacy",
]);
const IG_HANDLE = /^[a-z0-9._]{1,30}$/;
const TIKTOK_HANDLE = /^[a-z0-9._]{2,24}$/;
const X_HANDLE = /^[a-z0-9_]{1,15}$/;
const YT_HANDLE = /^[\p{L}\p{M}\p{N}._\-·]{1,30}$/u;
const YT_CHANNEL_ID = /^UC[A-Za-z0-9_-]{22}$/;
const YT_LEGACY_NAME = /^[A-Za-z0-9._-]{1,100}$/;
export function parseProfileUrl(input) {
if (typeof input !== "string") return null;
let raw = input.trim().replace(/^<|>$/g, "");
if (!raw) return null;
if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) raw = "https://" + raw;
let url;
try {
url = new URL(raw);
} catch {
return null;
}
if (url.protocol !== "https:" && url.protocol !== "http:") return null;
const host = url.hostname.toLowerCase().replace(/^(www|m|mobile)\./, "");
const platform = HOSTS[host];
if (!platform) return null;
let segments;
try {
segments = url.pathname.split("/").filter(Boolean).map(decodeURIComponent);
} catch {
return null; // malformed percent-encoding
}
const [first = "", second] = segments;
if (platform === "instagram") {
const handle = first.toLowerCase();
if (segments.length !== 1 || IG_RESERVED.has(handle) || !IG_HANDLE.test(handle)) return null;
return { platform, handle, canonicalUrl: `https://www.instagram.com/${handle}/` };
}
if (platform === "tiktok") {
if (segments.length !== 1 || !first.startsWith("@")) return null;
const handle = first.slice(1).toLowerCase();
if (!TIKTOK_HANDLE.test(handle) || handle.endsWith(".")) return null;
return { platform, handle, canonicalUrl: `https://www.tiktok.com/@${handle}` };
}
if (platform === "x") {
const handle = first.toLowerCase();
if (segments.length !== 1 || X_RESERVED.has(handle) || !X_HANDLE.test(handle)) return null;
return { platform, handle, canonicalUrl: `https://x.com/${handle}` };
}
// YouTube: /@handle[/tab], /channel/UC...[/tab], /user/name, /c/name
if (first.startsWith("@")) {
const handle = first.slice(1).toLowerCase();
if (!YT_HANDLE.test(handle) || /^[._\-·]|[._\-·]$/.test(handle)) return null;
return { platform, handle, canonicalUrl: `https://www.youtube.com/@${encodeURIComponent(handle)}` };
}
if (first === "channel" && second && YT_CHANNEL_ID.test(second)) {
return { platform, channelId: second, canonicalUrl: `https://www.youtube.com/channel/${second}` };
}
if ((first === "user" || first === "c") && second && segments.length === 2 && YT_LEGACY_NAME.test(second)) {
const key = first === "user" ? "username" : "customName";
return { platform, [key]: second, canonicalUrl: `https://www.youtube.com/${first}/${second}` };
}
return null; // videos, shorts, playlists, search and anything else
}
const SHORT_HOSTS = new Set(["vm.tiktok.com", "vt.tiktok.com"]);
export function isShortLink(input) {
try {
const url = new URL(/^https?:\/\//i.test(input) ? input : "https://" + input);
const host = url.hostname.toLowerCase();
return SHORT_HOSTS.has(host) || (host.replace(/^www\./, "") === "tiktok.com" && url.pathname.startsWith("/t/"));
} catch {
return false;
}
}
export async function resolveShortLink(input) {
const res = await fetch(/^https?:\/\//i.test(input) ? input : "https://" + input, {
redirect: "follow",
signal: AbortSignal.timeout(10_000),
});
await res.body?.cancel();
return res.url; // the final URL after every redirect
}resolveShortLink بلٹ ان fetch استعمال کرتا ہے، جو ری ڈائریکٹس فالو کرتا ہے اور آخری پتا res.url میں دیتا ہے۔ جب isShortLink(link) درست ہو تو parseProfileUrl(await resolveShortLink(link)) کال کریں۔ شارٹ لنک پروفائل کی بجائے ویڈیو تک بھی لے جا سکتا ہے، اس صورت میں پارسر درست طور پر null لوٹاتا ہے۔
Python 3
import re
import unicodedata
import urllib.request
from urllib.parse import quote, unquote, urlsplit
HOSTS = {
"instagram.com": "instagram",
"tiktok.com": "tiktok",
"youtube.com": "youtube",
"x.com": "x",
"twitter.com": "x",
}
IG_RESERVED = {"p", "reel", "reels", "tv", "stories", "explore", "accounts", "direct"}
X_RESERVED = {
"home", "explore", "search", "i", "settings", "notifications", "messages",
"compose", "intent", "hashtag", "login", "signup", "logout", "tos", "privacy",
}
IG_HANDLE = re.compile(r"[a-z0-9._]{1,30}")
TIKTOK_HANDLE = re.compile(r"[a-z0-9._]{2,24}")
X_HANDLE = re.compile(r"[a-z0-9_]{1,15}")
YT_CHANNEL_ID = re.compile(r"UC[A-Za-z0-9_-]{22}")
YT_LEGACY_NAME = re.compile(r"[A-Za-z0-9._-]{1,100}")
YT_PUNCT = "._-·"
def _is_youtube_handle(handle):
if not 1 <= len(handle) <= 30 or handle[0] in YT_PUNCT or handle[-1] in YT_PUNCT:
return False
return all(
ch.isalnum() or ch in YT_PUNCT or unicodedata.category(ch).startswith("M")
for ch in handle
)
def parse_profile_url(value):
if not isinstance(value, str):
return None
raw = value.strip().strip("<>")
if not raw:
return None
if not re.match(r"^[a-z][a-z0-9+.-]*://", raw, re.I):
raw = "https://" + raw
try:
url = urlsplit(raw)
host = (url.hostname or "").lower()
except ValueError:
return None
if url.scheme.lower() not in ("http", "https"):
return None
host = re.sub(r"^(www|m|mobile)\.", "", host)
platform = HOSTS.get(host)
if not platform:
return None
try:
segments = [unquote(s, errors="strict") for s in url.path.split("/") if s]
except UnicodeDecodeError:
return None # malformed percent-encoding
first = segments[0] if segments else ""
second = segments[1] if len(segments) > 1 else None
if platform == "instagram":
handle = first.lower()
if len(segments) != 1 or handle in IG_RESERVED or not IG_HANDLE.fullmatch(handle):
return None
return {"platform": platform, "handle": handle,
"canonicalUrl": f"https://www.instagram.com/{handle}/"}
if platform == "tiktok":
if len(segments) != 1 or not first.startswith("@"):
return None
handle = first[1:].lower()
if not TIKTOK_HANDLE.fullmatch(handle) or handle.endswith("."):
return None
return {"platform": platform, "handle": handle,
"canonicalUrl": f"https://www.tiktok.com/@{handle}"}
if platform == "x":
handle = first.lower()
if len(segments) != 1 or handle in X_RESERVED or not X_HANDLE.fullmatch(handle):
return None
return {"platform": platform, "handle": handle, "canonicalUrl": f"https://x.com/{handle}"}
# YouTube: /@handle[/tab], /channel/UC...[/tab], /user/name, /c/name
if first.startswith("@"):
handle = first[1:].lower()
if not _is_youtube_handle(handle):
return None
return {"platform": platform, "handle": handle,
"canonicalUrl": f"https://www.youtube.com/@{quote(handle, safe='._-')}"}
if first == "channel" and second and YT_CHANNEL_ID.fullmatch(second):
return {"platform": platform, "channelId": second,
"canonicalUrl": f"https://www.youtube.com/channel/{second}"}
if first in ("user", "c") and second and len(segments) == 2 and YT_LEGACY_NAME.fullmatch(second):
key = "username" if first == "user" else "customName"
return {"platform": platform, key: second,
"canonicalUrl": f"https://www.youtube.com/{first}/{second}"}
return None # videos, shorts, playlists, search and anything else
SHORT_HOSTS = {"vm.tiktok.com", "vt.tiktok.com"}
def is_short_link(value):
url = urlsplit(value if re.match(r"^https?://", value, re.I) else "https://" + value)
host = (url.hostname or "").lower()
return host in SHORT_HOSTS or (
re.sub(r"^www\.", "", host) == "tiktok.com" and url.path.startswith("/t/")
)
def resolve_short_link(value, timeout=10):
if not re.match(r"^https?://", value, re.I):
value = "https://" + value
request = urllib.request.Request(value, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(request, timeout=timeout) as response:
return response.geturl() # the final URL after every redirectPython کے \w اور str.isalnum() Unicode حروف اور اعداد کا احاطہ کرتے ہیں لیکن Devanagari جیسے رسم الخط میں استعمال ہونے والے combining marks کا نہیں، اسی لیے YouTube والی جانچ Unicode کی M کیٹیگریز کے حروف بھی قبول کرتی ہے۔
خاص صورتیں اور ٹیسٹ
نیچے کی ہر قطار اس ٹیسٹ سوٹ کا حصہ ہے جسے دونوں implementations پاس کرتی ہیں۔
| ان پٹ | آؤٹ پٹ | وجہ |
|---|---|---|
instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA== | instagram، natgeo، https://www.instagram.com/natgeo/ | scheme نہیں، ملے جلے حروف، شیئر پیرامیٹر |
https://m.instagram.com/nat.geo_/#bio | instagram، nat.geo_ | موبائل ہوسٹ اور fragment |
https://www.instagram.com/p/C9xYzAbCdEf/ | null | پوسٹ ہے، پروفائل نہیں |
https://www.instagram.com/stories/natgeo/1234567890/ | null | story ہے، چاہے path میں ہینڈل ہو |
tiktok.com/@Khaby.Lame/ | tiktok، khaby.lame، https://www.tiktok.com/@khaby.lame | آخری slash اور حروف کی شکل |
https://www.tiktok.com/@khaby.lame/video/7106594312292453675 | null | ویڈیو URL |
https://vm.tiktok.com/ZMabc123/ | null (پہلے ری ڈائریکٹ فالو کریں) | شارٹ لنک جس میں ہینڈل نہیں |
https://m.youtube.com/@GoogleDevelopers/videos?app=desktop | youtube، googledevelopers | موبائل ہوسٹ، چینل ٹیب، query |
https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw/featured | youtube، channelId UC_x5XG1OV2P6uZZ5FSM9Ttw | چینل ID اپنے حروف کی شکل برقرار رکھتی ہے |
https://www.youtube.com/c/GoogleDevelopers | youtube، customName GoogleDevelopers | پرانا کسٹم URL؛ ID کے لیے تلاش چاہیے |
https://www.youtube.com/@%E3%83%86%E3%82%B9%E3%83%88 | youtube، ہینڈل テスト | percent-encoded Unicode ہینڈل |
https://youtu.be/dQw4w9WgXcQ | null | ویڈیو ہے، چینل نہیں |
https://mobile.twitter.com/jack?s=21&t=abc | x، jack، https://x.com/jack | پرانا ڈومین اور شیئر پیرامیٹرز |
https://x.com/i/flow/login | null | ایپ روٹ |
https://x.com/this_handle_is_too_long | null | 15 سے زیادہ حروف |
https://instagram.com.evil.com/natgeo | null | ملتا جلتا ہوسٹ |
https://instagram.com@evil.com/natgeo | null | user info کی چال؛ اصل ہوسٹ evil.com ہے |
@natgeo | null | اکیلے ہینڈل کا کوئی پلیٹ فارم نہیں |
یہ کیسز اپنی ریپوزٹری میں رکھیں اور CI میں چلائیں۔ جب کوئی پلیٹ فارم نیا روٹ یا شیئر پیرامیٹر شامل کرے تو آپ ایک قطار بڑھاتے ہیں اور حل صاف نظر آتا ہے۔
import assert from "node:assert/strict";
import { parseProfileUrl } from "./parse.mjs";
const cases = [
["instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA==", { platform: "instagram", handle: "natgeo", canonicalUrl: "https://www.instagram.com/natgeo/" }],
["https://www.instagram.com/reel/C9xYzAbCdEf/", null],
["https://www.instagram.com/explore/", null],
["tiktok.com/@Khaby.Lame/", { platform: "tiktok", handle: "khaby.lame", canonicalUrl: "https://www.tiktok.com/@khaby.lame" }],
["https://www.tiktok.com/@khaby.lame/video/7106594312292453675", null],
["https://vm.tiktok.com/ZMabc123/", null],
["https://m.youtube.com/@GoogleDevelopers/videos", { platform: "youtube", handle: "googledevelopers", canonicalUrl: "https://www.youtube.com/@googledevelopers" }],
["https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw/featured", { platform: "youtube", channelId: "UC_x5XG1OV2P6uZZ5FSM9Ttw", canonicalUrl: "https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw" }],
["https://www.youtube.com/user/GoogleDevelopers", { platform: "youtube", username: "GoogleDevelopers", canonicalUrl: "https://www.youtube.com/user/GoogleDevelopers" }],
["https://youtu.be/dQw4w9WgXcQ", null],
["https://twitter.com/Jack/", { platform: "x", handle: "jack", canonicalUrl: "https://x.com/jack" }],
["https://mobile.twitter.com/jack?s=21", { platform: "x", handle: "jack", canonicalUrl: "https://x.com/jack" }],
["https://x.com/jack/status/20", null],
["https://x.com/i/flow/login", null],
["https://instagram.com.evil.com/natgeo", null],
];
for (const [input, expected] of cases) {
assert.deepEqual(parseProfileUrl(input), expected, input);
}
console.log(`${cases.length} cases passed`);from parse_profile import parse_profile_url
CASES = [
("instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA==", {"platform": "instagram", "handle": "natgeo", "canonicalUrl": "https://www.instagram.com/natgeo/"}),
("https://www.instagram.com/reel/C9xYzAbCdEf/", None),
("tiktok.com/@Khaby.Lame/", {"platform": "tiktok", "handle": "khaby.lame", "canonicalUrl": "https://www.tiktok.com/@khaby.lame"}),
("https://vm.tiktok.com/ZMabc123/", None),
("https://m.youtube.com/@GoogleDevelopers/videos", {"platform": "youtube", "handle": "googledevelopers", "canonicalUrl": "https://www.youtube.com/@googledevelopers"}),
("https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw/featured", {"platform": "youtube", "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw", "canonicalUrl": "https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw"}),
("https://youtu.be/dQw4w9WgXcQ", None),
("https://twitter.com/Jack/", {"platform": "x", "handle": "jack", "canonicalUrl": "https://x.com/jack"}),
("https://x.com/i/flow/login", None),
("https://instagram.com.evil.com/natgeo", None),
]
for value, expected in CASES:
assert parse_profile_url(value) == expected, value
print(f"{len(CASES)} cases passed")اصل ان پٹ اور معیاری شکل دونوں محفوظ کریں
نارملائزیشن جان بوجھ کر کچھ معلومات کھو دیتی ہے، اور آپ کے اصول وقت کے ساتھ بہتر ہوں گے۔ دونوں قدریں محفوظ کریں:
- `raw_url`: بالکل وہی جو صارف یا امپورٹ نے دیا۔ اس سے آپ بعد میں بہتر پارسر دوبارہ چلا سکتے ہیں، اور جب صارف اپنا پروفائل ایڈٹ کرے تو اسے یہی واپس دکھایا جاتا ہے۔
- `platform` اور `handle` یا `channel_id`: الگ الگ حصے،
(platform, handle)پر unique index کے ساتھ۔ یہی آپ کی dedupe اور join کلید ہے۔ - `canonical_url`: دوبارہ بنایا گیا URL، دکھانے اور پلیٹ فارم کو کال کرنے کے لیے۔
- `parsed_at` اور پارسر کا ورژن: تاکہ آپ وہ قطاریں ڈھونڈ سکیں جو آپ کے اصولوں کے پرانے ورژن سے نارملائز ہوئیں۔
ہینڈل مستقل نہیں ہوتے۔ کریئیٹرز ہر پلیٹ فارم پر اکاؤنٹس کے نام بدلتے ہیں، اور جو ہینڈل آپ نے پچھلے سال محفوظ کیا وہ اب کسی اور کا ہو سکتا ہے۔ جہاں سرکاری API مستقل ID دیتا ہے، جیسے YouTube چینل ID، وہاں اسے طویل مدتی کلید بنائیں اور ہینڈل کو دکھانے والی قدر سمجھیں جسے آپ تازہ کرتے ہیں۔ ہینڈل سے YouTube چینل ID حاصل کرنے والی ساتھی گائیڈ طریقہ بتاتی ہے۔
ایک پروفائل سے باقی تک
پروفائل URL نارملائز ہونے کے بعد اگلا سوال عموماً یہ ہوتا ہے کہ اسی کریئیٹر کے اور کون سے اکاؤنٹس ہیں۔ sociallinks.dev ایک API ہے جو ایک Instagram، TikTok، YouTube یا X پروفائل URL لیتا ہے اور دوسرے پلیٹ فارمز پر کریئیٹر کے اکاؤنٹس لوٹاتا ہے، ہر میچ کے ساتھ اعتماد کا اسکور اور ثبوت۔
عام سوالات
کیا ہینڈل محفوظ کرنے سے پہلے انہیں چھوٹے حروف میں بدلنا چاہیے؟
تلاش کی کلید کے لیے ہاں۔ YouTube اور X کہتے ہیں کہ ہینڈلز میں چھوٹے بڑے حروف سے فرق نہیں پڑتا، اور TikTok @TikTok کو @tiktok والے اکاؤنٹ پر ہی کھولتا ہے۔ Instagram اس بارے میں کوئی اصول دستاویزی نہیں کرتا، لیکن یوزرنیمز چھوٹے حروف میں دکھائے جاتے ہیں، اس لیے چھوٹے حروف محفوظ ڈیفالٹ ہیں۔ اصل شکل دکھانی ہو تو اسے raw URL میں رکھیں۔ YouTube چینل IDs کو چھوٹے حروف میں نہ بدلیں، ان میں فرق اہم ہے۔
کیا پوسٹ یا ویڈیو URL سے ہینڈل نکالا جا سکتا ہے؟
TikTok ویڈیوز (/@handle/video/id) اور X پوسٹس (/handle/status/id) میں path والا ہینڈل مصنف کا ہوتا ہے، اس لیے اگر یہی چاہیے تو نکال سکتے ہیں۔ Instagram پوسٹ اور reel URLs (/p/ اور /reel/) میں ہینڈل نہیں ہوتا۔ اس گائیڈ کے فنکشن ان سب کے لیے null لوٹاتے ہیں کیونکہ یہ پروفائل لنکس نہیں۔
vm.tiktok.com لنکس کا کیا کروں؟
شارٹ لنکس میں صرف ایک کوڈ ہوتا ہے۔ HTTP درخواست بھیجیں، ری ڈائریکٹس فالو کریں اور آخری URL پارس کریں۔ یہ timeout اور کیش کے ساتھ الگ قدم میں کریں، کیونکہ یہ نیٹ ورک کال ہے اور کوڈ کی میعاد ختم ہو سکتی ہے۔
کیا twitter.com اب بھی درست پروفائل URL ہے؟
ہاں۔ twitter.com پروفائل URLs، x.com پر ری ڈائریکٹ ہوتے ہیں، اس لیے دونوں ڈومینز کو X پلیٹ فارم سمجھیں اور x.com والی شکل کو معیاری کے طور پر محفوظ کریں۔
ایک بڑا regular expression کیوں نہیں؟
پوری string پر ایک regex پڑھنے میں مشکل ہے اور ملتے جلتے ہوسٹس، user info یا encoded حروف سے آسانی سے دھوکا کھا جاتا ہے۔ پہلے standard library سے URL پارس کریں، پھر صرف ہینڈل پر چھوٹے regex استعمال کریں۔
YouTube کے /c/ یا /user/ URL کو چینل ID میں کیسے بدلوں؟
/user/<name> URLs، YouTube Data API کے forUsername فلٹر سے ملتے ہیں۔ /c/ کسٹم ناموں کے لیے کوئی API فلٹر نہیں۔ دونوں صورتوں کے لیے ہینڈل سے YouTube چینل ID حاصل کرنے والی گائیڈ دیکھیں۔