sociallinks.dev

ব্লগ / ডেভেলপার গাইড

সোশ্যাল মিডিয়া প্রোফাইল URL কীভাবে পার্স ও নরমালাইজ করবেন (Instagram, TikTok, YouTube, X)

ক্রিয়েটররা প্রোফাইল লিংক পেস্ট করেন যত রকমে ভাবা যায়: www সহ বা ছাড়া, মোবাইল অ্যাপ থেকে ট্র্যাকিং প্যারামিটারসহ, শর্ট লিংক হিসেবে, পুরোনো twitter.com URL হিসেবে, বা প্রোফাইলের বদলে একটি পোস্টের লিংক হিসেবে। আপনার প্রোডাক্ট যদি এই স্ট্রিংগুলো যেমন আসে তেমনই সংরক্ষণ করে, তাহলে একই ক্রিয়েটর তিনবার দেখা যায় আর আপনার join-গুলো চুপচাপ মিস করে। এই গাইডে দেখানো হয়েছে কীভাবে যেকোনো Instagram, TikTok, YouTube বা X প্রোফাইল URL-কে একটি প্ল্যাটফর্ম, একটি হ্যান্ডেল বা চ্যানেল ID আর একটি canonical URL-এ পরিণত করবেন, JavaScript ও Python-এ পরীক্ষিত কোডসহ।

প্রোফাইল URL নরমালাইজ করা কেন জরুরি

প্রোফাইল URL একটি আইডেন্টিফায়ার, আর আইডেন্টিফায়ার তখনই কাজ করে যখন সেটি একভাবেই লেখা হয়। https://www.instagram.com/natgeo/, instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA== আর https://m.instagram.com/natgeo সবগুলো একই অ্যাকাউন্ট নির্দেশ করে, কিন্তু স্ট্রিং হিসেবে এরা তিনটি আলাদা মান।

লক্ষ্য হলো একটি ছোট, কড়া ফাংশন: ইউজাররা আসলে যা পেস্ট করেন তা নেয়, আসল প্রোফাইল URL-এর জন্য নরমালাইজ করা ফলাফল দেয়, আর বাকি সবকিছুর জন্য null দেয়।

যে URL রূপগুলো আপনি দেখবেন

নিচের রূপগুলো ২০২৬ সালের অক্টোবরে লাইভ সাইটে যাচাই করা হয়েছে। প্ল্যাটফর্মগুলো আগাম না জানিয়ে রাউটিং বদলায়, তাই এটিকে একটি মুহূর্তের ছবি হিসেবে দেখুন আর আপনার টেস্ট কেসগুলো হালনাগাদ রাখুন।

Instagram

TikTok

YouTube

X (আগে Twitter)

প্ল্যাটফর্মভেদে হ্যান্ডেলের অক্ষরের নিয়ম

হ্যান্ডেল যাচাই করলে টাইপো আর বেশিরভাগ অ-প্রোফাইল পাথ ধরা পড়ে। প্ল্যাটফর্ম যেখানে নিজের নিয়ম প্রকাশ করে সেখানে সেটি ব্যবহার করুন, আর যেখানে করে না সেখানে যাচাই ঢিলে রাখুন, যাতে কোনো আসল অ্যাকাউন্ট কখনো বাতিল না হয়।

প্ল্যাটফর্মঅনুমোদিত অক্ষরদৈর্ঘ্যবড়-ছোট হাতের অক্ষরউৎস
Instagramঅক্ষর, সংখ্যা, পিরিয়ড, আন্ডারস্কোর৩০ বহুল উল্লিখিত; Instagram-এর হেল্প পেজে পাওয়া যায়নিকেস-ইনসেনসিটিভ ধরুন; ছোট হাতের অক্ষরে সংরক্ষণ করুনInstagram Help Center পিরিয়ড, সংখ্যা আর আন্ডারস্কোরের উল্লেখ করে
TikTokঅক্ষর, সংখ্যা, আন্ডারস্কোর, পিরিয়ড; শেষে পিরিয়ড থাকতে পারবে না২ থেকে ২৪URL-এ কেস-ইনসেনসিটিভ (@TikTok থেকে tiktok আসে)TikTok Support, ইউজারনেম বদলানো
YouTubeসমর্থিত ভাষার অক্ষর বা সংখ্যা, সঙ্গে আন্ডারস্কোর, হাইফেন, পিরিয়ড আর ল্যাটিন মিডল ডট (প্রথমে বা শেষে নয়)বেশিরভাগ লিপিতে ৩ থেকে ৩০; Han, Hangul আর আরও কিছু লিপিতে ছোট সীমাকেস-সেনসিটিভ নয়YouTube Help, হ্যান্ডেলের নির্দেশিকা
Xঅক্ষর, সংখ্যা আর আন্ডারস্কোরসর্বোচ্চ ১৫; নতুন ইউজারনেম ৪-এর বেশি হতে হবে, তবে পুরোনো ছোট হ্যান্ডেলও আছেকেস-সেনসিটিভ নয় (x.com/JACK থেকে canonical হয় x.com/jack)X Help Center, ইউজারনেমের নিয়ম

একটি নরমালাইজেশন অ্যালগরিদম

  1. Step 1ছেঁটে ফেলুন আর স্কিম যোগ করুন

    স্পেস আর অপ্রয়োজনীয় অ্যাঙ্গেল ব্র্যাকেট সরান। ইনপুটে স্কিম না থাকলে শুরুতে https:// জুড়ে দিন, যাতে instagram.com/natgeo পার্স হয়।

  2. Step 2একটি আসল URL পার্সার দিয়ে পার্স করুন

    JavaScript-এ new URL() বা Python-এ urllib.parse.urlsplit ব্যবহার করুন, পুরো স্ট্রিংয়ের ওপর regex কখনো নয়। পার্সার পোর্ট, ইউজার ইনফো আর এনকোড করা অক্ষর সামলায়, আর https://instagram.com@evil.com/natgeo-কে Instagram হিসেবে পার হতে দেয় না।

  3. Step 3হোস্ট নরমালাইজ করুন

    ছোট হাতের অক্ষরে আনুন আর শুরুর একটি www., m. বা mobile. সরান। তারপর হোস্টগুলোর একটি হুবহু অনুমোদিত তালিকায় খুঁজুন। কখনো includes("instagram.com") ব্যবহার করবেন না, যা instagram.com.evil.com-কেও মেলায়।

  4. Step 4কোয়েরি স্ট্রিং আর ফ্র্যাগমেন্ট বাদ দিন

    igsh, s, t আর lang-এর মতো ট্র্যাকিং প্যারামিটার কখনো বদলায় না যে URL কোন প্রোফাইল নির্দেশ করে।

  5. Step 5পাথ ভাগ আর ডিকোড করুন

    / দিয়ে ভাগ করুন, ফাঁকা সেগমেন্ট বাদ দিন (এতে শেষের স্ল্যাশ সরে যায়) আর প্রতিটি পার্সেন্ট-ডিকোড করুন। ভুল এনকোডিংকে অবৈধ ইনপুট হিসেবে ধরুন।

  6. Step 6প্ল্যাটফর্ম অনুযায়ী রাউট করুন

    প্রতিটি প্ল্যাটফর্মের রূপ প্রয়োগ করুন: Instagram আর X-এ একটি সেগমেন্ট, TikTok-এ একটি @ সেগমেন্ট, আর YouTube-এ @handle, channel/UC..., user/name বা c/name। সংরক্ষিত শব্দ বাতিল করুন।

  7. Step 7হ্যান্ডেল যাচাই করে ছোট হাতের অক্ষরে আনুন

    প্ল্যাটফর্মের অক্ষরের নিয়মের সঙ্গে হ্যান্ডেল মিলিয়ে দেখুন, তারপর ছোট হাতের অক্ষরে আনুন। YouTube চ্যানেল ID ছোট হাতের অক্ষরে আনবেন না: এগুলো কেস-সেনসিটিভ।

  8. Step 8canonical URL বানান

    একটি নির্দিষ্ট হোস্টে অংশগুলো থেকে URL আবার বানান, যাতে প্রতিটি সমতুল্য ইনপুট ঠিক একই স্ট্রিং দেয়।

  9. Step 9শর্ট লিংক আলাদাভাবে সামলান

    TikTok শর্ট লিংক শনাক্ত করুন, একটি HTTP রিকোয়েস্ট দিয়ে রিডাইরেক্ট অনুসরণ করুন, আর শেষ URL আবার পার্সারে দিন। এটি বিশুদ্ধ ফাংশনের বাইরে রাখুন, যাতে পার্সিং দ্রুত আর পরীক্ষাযোগ্য থাকে।

JavaScript ও Python-এ কোড

দুটি ফাংশনই একই ইনপুটে একই অবজেক্ট ফেরত দেয়: হ্যান্ডেল URL-এর জন্য { platform, handle, canonicalUrl }, YouTube চ্যানেল ID-র জন্য { platform, channelId, canonicalUrl }, পুরোনো দুই YouTube রূপের জন্য username বা customName, আর প্রোফাইল URL নয় এমন যেকোনো কিছুর জন্য null। কোনোটিরই কোনো ডিপেনডেন্সি লাগে না।

JavaScript (Node 18+)

Node.js

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) true হলে parseProfileUrl(await resolveShortLink(link)) কল করুন। শর্ট লিংক প্রোফাইলের বদলে একটি ভিডিওতেও নিয়ে যেতে পারে, সেক্ষেত্রে পার্সার ঠিকভাবেই null ফেরত দেয়।

Python 3

Python

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 redirect

Python-এর \w আর str.isalnum() Unicode অক্ষর আর সংখ্যা ধরে, কিন্তু দেবনাগরীর মতো লিপিতে ব্যবহৃত combining mark ধরে না, তাই YouTube যাচাইটি Unicode M ক্যাটাগরির অক্ষরও গ্রহণ করে।

এজ কেস আর টেস্ট

নিচের প্রতিটি সারি টেস্ট স্যুটের অংশ, যা দুটি ইমপ্লিমেন্টেশনই পাস করে।

ইনপুটআউটপুটকেন
instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA==instagram, natgeo, https://www.instagram.com/natgeo/স্কিম নেই, মিশ্র কেস, শেয়ার প্যারামিটার
https://m.instagram.com/nat.geo_/#bioinstagram, nat.geo_মোবাইল হোস্ট আর ফ্র্যাগমেন্ট
https://www.instagram.com/p/C9xYzAbCdEf/nullএকটি পোস্ট, প্রোফাইল নয়
https://www.instagram.com/stories/natgeo/1234567890/nullএকটি স্টোরি, যদিও পাথে হ্যান্ডেল আছে
tiktok.com/@Khaby.Lame/tiktok, khaby.lame, https://www.tiktok.com/@khaby.lameশেষের স্ল্যাশ আর কেস
https://www.tiktok.com/@khaby.lame/video/7106594312292453675nullএকটি ভিডিও URL
https://vm.tiktok.com/ZMabc123/null (আগে রিডাইরেক্ট অনুসরণ করুন)শর্ট লিংক, এতে কোনো হ্যান্ডেল নেই
https://m.youtube.com/@GoogleDevelopers/videos?app=desktopyoutube, googledevelopersমোবাইল হোস্ট, চ্যানেল ট্যাব, কোয়েরি
https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw/featuredyoutube, channelId UC_x5XG1OV2P6uZZ5FSM9Ttwচ্যানেল ID তার কেস ধরে রাখে
https://www.youtube.com/c/GoogleDevelopersyoutube, customName GoogleDevelopersপুরোনো কাস্টম URL; ID-র জন্য খোঁজ লাগবে
https://www.youtube.com/@%E3%83%86%E3%82%B9%E3%83%88youtube, হ্যান্ডেল テストপার্সেন্ট-এনকোড করা Unicode হ্যান্ডেল
https://youtu.be/dQw4w9WgXcQnullএকটি ভিডিও, চ্যানেল নয়
https://mobile.twitter.com/jack?s=21&t=abcx, jack, https://x.com/jackপুরোনো ডোমেইন আর শেয়ার প্যারামিটার
https://x.com/i/flow/loginnullঅ্যাপ রাউট
https://x.com/this_handle_is_too_longnull১৫ অক্ষরের বেশি
https://instagram.com.evil.com/natgeonullদেখতে একই রকম হোস্ট
https://instagram.com@evil.com/natgeonullইউজার ইনফোর কৌশল; আসল হোস্ট evil.com
@natgeonullশুধু হ্যান্ডেলের কোনো প্ল্যাটফর্ম নেই

কেসগুলো আপনার রিপোজিটরিতে রাখুন আর CI-তে চালান। কোনো প্ল্যাটফর্ম নতুন রাউট বা শেয়ার প্যারামিটার যোগ করলে আপনি একটি সারি যোগ করবেন, আর সমাধান স্পষ্ট হয়ে যাবে।

Node.js টেস্ট

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`);

Python টেস্ট

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")

আসল ইনপুট আর canonical রূপ দুটোই সংরক্ষণ করুন

নরমালাইজেশন ইচ্ছাকৃতভাবেই কিছু তথ্য হারায়, আর আপনার নিয়ম সময়ের সঙ্গে উন্নত হবে। দুটি মানই সংরক্ষণ করুন:

হ্যান্ডেল স্থায়ী নয়। ক্রিয়েটররা প্রতিটি প্ল্যাটফর্মে অ্যাকাউন্টের নাম বদলান, আর গত বছর সংরক্ষণ করা একটি হ্যান্ডেল এখন অন্য কারও হতে পারে। যেখানে কোনো অফিশিয়াল API একটি স্থির ID দেয়, যেমন YouTube চ্যানেল ID, সেটিকে দীর্ঘমেয়াদি কি হিসেবে সংরক্ষণ করুন আর হ্যান্ডেলকে দেখানোর মান হিসেবে ধরুন, যা আপনি রিফ্রেশ করবেন। হ্যান্ডেল থেকে YouTube চ্যানেল ID পাওয়া নিয়ে সঙ্গী গাইডটি দেখায় কীভাবে।

একটি প্রোফাইল থেকে বাকিগুলোতে

একটি প্রোফাইল URL নরমালাইজ হয়ে গেলে, পরের প্রশ্ন সাধারণত হয় একই ক্রিয়েটরের আর কোন অ্যাকাউন্টগুলো আছে। sociallinks.dev একটি API যা একটি Instagram, TikTok, YouTube বা X প্রোফাইল URL নেয় আর অন্য প্ল্যাটফর্মে ক্রিয়েটরের অ্যাকাউন্টগুলো ফেরত দেয়, প্রতিটি মিলের জন্য কনফিডেন্স স্কোর আর প্রমাণসহ।

প্রায়শই জিজ্ঞাসিত প্রশ্ন

সংরক্ষণের আগে কি হ্যান্ডেল ছোট হাতের অক্ষরে আনা উচিত?

খোঁজার কি-এর জন্য হ্যাঁ। YouTube আর X বলে হ্যান্ডেল কেস-সেনসিটিভ নয়, আর TikTok @TikTok থেকে @tiktok-এর একই অ্যাকাউন্টে যায়। Instagram কেসের কোনো নিয়ম ডকুমেন্ট করে না, তবে ইউজারনেম ছোট হাতের অক্ষরে দেখানো হয়, তাই ছোট হাতের অক্ষরে আনাই নিরাপদ ডিফল্ট। দেখাতে চাইলে আসল কেস raw URL-এ রেখে দিন। YouTube চ্যানেল ID ছোট হাতের অক্ষরে আনবেন না, এগুলো কেস-সেনসিটিভ।

পোস্ট বা ভিডিও URL থেকে কি হ্যান্ডেল বের করা যায়?

TikTok ভিডিও (/@handle/video/id) আর X পোস্টে (/handle/status/id) পাথের হ্যান্ডেলটি লেখকের, তাই সেটিই চাইলে বের করতে পারেন। Instagram পোস্ট আর রিল URL (/p/ আর /reel/)-এ হ্যান্ডেল থাকে না। এই গাইডের ফাংশনগুলো এদের সবার জন্য null দেয়, কারণ এগুলো প্রোফাইল লিংক নয়।

vm.tiktok.com লিংক কীভাবে সামলাব?

শর্ট লিংকে শুধু একটি কোড থাকে। একটি HTTP রিকোয়েস্ট করুন, রিডাইরেক্ট অনুসরণ করুন আর শেষ URL পার্স করুন। এটি একটি আলাদা ধাপে টাইমআউট আর ক্যাশসহ করুন, কারণ এটি নেটওয়ার্ক কল আর কোডের মেয়াদ শেষ হতে পারে।

twitter.com কি এখনো বৈধ প্রোফাইল URL?

হ্যাঁ। twitter.com প্রোফাইল URL x.com-এ রিডাইরেক্ট করে, তাই দুটি ডোমেইনকেই X প্ল্যাটফর্ম হিসেবে ধরুন আর x.com রূপটিকে canonical হিসেবে সংরক্ষণ করুন।

একটি বড় regular expression কেন ব্যবহার করব না?

পুরো স্ট্রিংয়ের ওপর একটি regex পড়তে কঠিন, আর দেখতে একই রকম হোস্ট, ইউজার ইনফো বা এনকোড করা অক্ষর দিয়ে সহজেই বোকা বানানো যায়। আগে স্ট্যান্ডার্ড লাইব্রেরি দিয়ে URL পার্স করুন, তারপর শুধু হ্যান্ডেলের ওপর ছোট regex ব্যবহার করুন।

YouTube-এর /c/ বা /user/ URL থেকে চ্যানেল ID কীভাবে পাব?

/user/<name> URL YouTube Data API-র forUsername ফিল্টারের সঙ্গে মেলে। /c/ কাস্টম নামের জন্য কোনো API ফিল্টার নেই। দুটি ক্ষেত্রের জন্যই হ্যান্ডেল থেকে YouTube চ্যানেল ID পাওয়ার গাইডটি দেখুন।

কোনো ক্রিয়েটরের অ্যাকাউন্ট খুঁজুন