sociallinks.dev

المدونة / دليل المطوّرين

كيف تحلل روابط الملفات الشخصية على وسائل التواصل وتوحّدها (Instagram وTikTok وYouTube وX)

يلصق صنّاع المحتوى روابط ملفاتهم الشخصية بكل شكل يمكن تخيله: مع www ودونها، ومن تطبيق الهاتف مع معاملات تتبع، وكروابط مختصرة، وكروابط twitter.com القديمة، أو كرابط إلى منشور بدلًا من الملف الشخصي. إذا كان منتجك يحفظ هذه النصوص كما تصل، فسيظهر صانع المحتوى نفسه ثلاث مرات وستفشل عمليات الربط بين الجداول دون أن تلاحظ. يوضح هذا الدليل كيف تحوّل أي رابط ملف شخصي على Instagram أو TikTok أو YouTube أو X إلى منصة، واسم مستخدم أو معرّف قناة، ورابط موحّد واحد، مع كود مختبر بلغتي JavaScript وPython.

لماذا يهم توحيد روابط الملفات الشخصية

رابط الملف الشخصي معرّف، والمعرّفات لا تعمل إلا إذا كُتبت بطريقة واحدة. https://www.instagram.com/natgeo/ وinstagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA== وhttps://m.instagram.com/natgeo كلها تشير إلى الحساب نفسه، لكنها كنصوص ثلاث قيم مختلفة.

الهدف دالة صغيرة وصارمة: تقبل ما يلصقه المستخدمون فعلًا، وتعيد نتيجة موحّدة لروابط الملفات الشخصية الحقيقية، وتعيد null لكل ما عدا ذلك.

أشكال الروابط التي ستراها

تم التحقق من الأشكال أدناه على المواقع الحية في أكتوبر 2026. المنصات تغيّر توجيه الروابط دون إشعار، لذلك تعامل مع هذا كلقطة في وقت محدد وأبقِ حالات الاختبار محدّثة.

Instagram

TikTok

YouTube

X (كانت Twitter سابقًا)

قواعد أحرف اسم المستخدم في كل منصة

التحقق من اسم المستخدم يكتشف الأخطاء الإملائية ومعظم المسارات التي ليست ملفات شخصية. استخدم قواعد المنصات نفسها حيث تنشرها، وأبقِ الفحوص مرنة حيث لا تنشرها، حتى لا ترفض حسابًا حقيقيًا أبدًا.

المنصةالأحرف المسموحةالطولحالة الأحرفالمصدر
Instagramحروف، وأرقام، ونقاط، وشرطات سفلية30 هو الرقم المتداول، ولم نجده في صفحات مساعدة Instagramتعامل معه كغير مميز لحالة الأحرف، واحفظه بأحرف صغيرةيذكر مركز مساعدة Instagram النقاط والأرقام والشرطات السفلية
TikTokحروف، وأرقام، وشرطات سفلية، ونقاط، ولا ينتهي بنقطةمن 2 إلى 24غير مميز لحالة الأحرف في الروابط (@TikTok يقود إلى tiktok)دعم TikTok، صفحة تغيير اسم المستخدم
YouTubeحروف أو أرقام من اللغات المدعومة، إضافة إلى الشرطات السفلية والواصلات والنقاط والنقاط الوسطى اللاتينية (ليست في البداية أو النهاية)من 3 إلى 30 لمعظم أنظمة الكتابة، وحدود أقصر للهانية والهانغول وبعض الأنظمة الأخرىغير مميز لحالة الأحرفمساعدة YouTube، إرشادات اسم المستخدم
Xحروف وأرقام وشرطات سفليةحتى 15، ويجب أن تكون أسماء المستخدمين الجديدة أطول من 4، لكن توجد أسماء قصيرة أقدمغير مميز لحالة الأحرف (x.com/JACK يتحول إلى x.com/jack)مركز مساعدة X، قواعد اسم المستخدم

خوارزمية للتوحيد

  1. Step 1احذف المسافات وأضف البروتوكول

    احذف المسافات والأقواس الزاوية الزائدة. إذا لم يكن للمدخل بروتوكول، فأضف https:// في بدايته حتى يُحلَّل instagram.com/natgeo.

  2. Step 2حلّل بمحلل روابط حقيقي

    استخدم new URL() في JavaScript أو urllib.parse.urlsplit في Python، ولا تستخدم أبدًا تعبيرًا نمطيًا على النص كله. المحلل يتعامل مع المنافذ ومعلومات المستخدم والأحرف المرمّزة، ويمنع 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 لا تغيّر أبدًا الملف الشخصي الذي يشير إليه الرابط.

  5. Step 5قسّم المسار وفك ترميزه

    قسّم عند /، واحذف الأجزاء الفارغة (هذا يزيل الشرطات المائلة في النهاية)، وفك ترميز النسبة المئوية لكل جزء. وتعامل مع الترميز المشوّه كمدخل غير صالح.

  6. Step 6وجّه حسب المنصة

    طبّق شكل كل منصة: جزء واحد على Instagram وX، وجزء يبدأ بـ @ على TikTok، و@handle أو channel/UC... أو user/name أو c/name على YouTube. وارفض الكلمات المحجوزة.

  7. Step 7تحقق من اسم المستخدم وحوّله إلى أحرف صغيرة

    افحص اسم المستخدم وفق قواعد أحرف المنصة، ثم حوّله إلى أحرف صغيرة. لا تحوّل معرّفات قنوات YouTube إلى أحرف صغيرة: فهي تميز بين الأحرف الكبيرة والصغيرة.

  8. Step 8ابنِ الرابط الموحّد

    أعد بناء الرابط من أجزائه على نطاق ثابت واحد، حتى ينتج كل مدخل مكافئ النص نفسه تمامًا.

  9. Step 9تعامل مع الروابط المختصرة منفصلة

    اكتشف روابط TikTok المختصرة، وتتبع إعادة التوجيه بطلب HTTP، وأعد الرابط النهائي إلى المحلل. أبقِ هذا خارج الدالة الخالصة حتى يبقى التحليل سريعًا وقابلًا للاختبار.

الكود بلغتي JavaScript وPython

تعيد الدالتان الكائنات نفسها للمدخل نفسه: { platform, handle, canonicalUrl } لروابط أسماء المستخدمين، و{ platform, channelId, canonicalUrl } لمعرّفات قنوات YouTube، وusername أو customName لصيغتي YouTube القديمتين، و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. استدعِ parseProfileUrl(await resolveShortLink(link)) حين تكون isShortLink(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 وأرقامها لكن لا يغطيان العلامات المركّبة التي تستخدمها أنظمة كتابة مثل الديفاناغارية، ولهذا يقبل فحص 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رابط فيديو
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معرّف القناة يحتفظ بحالة أحرفه
https://www.youtube.com/c/GoogleDevelopersyoutube، customName GoogleDevelopersرابط مخصص قديم، يحتاج إلى بحث للحصول على المعرّف
https://www.youtube.com/@%E3%83%86%E3%82%B9%E3%83%88youtube، handle テストاسم مستخدم 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أكثر من 15 حرفًا
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")

احفظ المدخل الخام والصيغة الموحّدة

التوحيد يفقد بعض المعلومات بطبيعته، وقواعدك ستتحسن مع الوقت. احفظ القيمتين:

أسماء المستخدمين ليست دائمة. صنّاع المحتوى يغيرون أسماء حساباتهم على كل منصة، واسم المستخدم الذي حفظته العام الماضي قد يخص شخصًا آخر الآن. حيث تمنحك API رسمية معرّفًا ثابتًا، مثل معرّف قناة YouTube، احفظه كمفتاح طويل الأمد وتعامل مع اسم المستخدم كقيمة عرض تحدّثها. يوضح الدليل المرافق عن الحصول على معرّف قناة YouTube من اسم المستخدم الطريقة.

من ملف شخصي واحد إلى البقية

بعد توحيد رابط الملف الشخصي، السؤال التالي عادة هو: ما الحسابات الأخرى التي تخص صانع المحتوى نفسه؟ sociallinks.dev واجهة API تأخذ رابط ملف شخصي واحد على Instagram أو TikTok أو YouTube أو X وتعيد حسابات صانع المحتوى على المنصات الأخرى، مع درجة ثقة ودليل لكل تطابق.

الأسئلة الشائعة

هل أحوّل أسماء المستخدمين إلى أحرف صغيرة قبل حفظها؟

نعم لمفتاح البحث. يقول YouTube وX إن أسماء المستخدمين لا تميز بين الأحرف الكبيرة والصغيرة، وTikTok يقود @TikTok إلى الحساب نفسه مثل @tiktok. لا يوثّق Instagram قاعدة لحالة الأحرف، لكن أسماء المستخدمين تُعرض بأحرف صغيرة، لذلك التحويل إلى أحرف صغيرة هو الخيار الآمن. احتفظ بالحالة الأصلية في الرابط الخام إذا أردت عرضها. ولا تحوّل معرّفات قنوات YouTube إلى أحرف صغيرة، فهي تميز بين الأحرف.

هل يمكنني استخراج اسم المستخدم من رابط منشور أو فيديو؟

في فيديوهات TikTok (/@handle/video/id) ومنشورات X (/handle/status/id) اسم المستخدم في المسار هو صاحب المحتوى، لذلك يمكنك استخراجه إذا كان هذا ما تريده. أما روابط منشورات Instagram وReels (/p/ و/reel/) فلا تتضمن اسم المستخدم. والدوال في هذا الدليل تعيد null لها جميعًا لأنها ليست روابط ملفات شخصية.

كيف أتعامل مع روابط vm.tiktok.com؟

الروابط المختصرة لا تحتوي إلا على كود. أرسل طلب HTTP، وتتبع إعادة التوجيه، وحلّل الرابط النهائي. افعل ذلك في خطوة منفصلة مع مهلة زمنية وذاكرة مؤقتة، لأنه استدعاء شبكة وقد تنتهي صلاحية الكود.

هل ما زال twitter.com رابط ملف شخصي صالحًا؟

نعم. روابط الملفات الشخصية على twitter.com تعيد التوجيه إلى x.com، لذلك تعامل مع النطاقين كمنصة X واحفظ صيغة x.com كصيغة موحّدة.

لماذا لا أستخدم تعبيرًا نمطيًا واحدًا كبيرًا؟

التعبير النمطي الواحد على النص كاملًا صعب القراءة وسهل الخداع بالنطاقات الشبيهة أو معلومات المستخدم أو الأحرف المرمّزة. حلّل الرابط بالمكتبة القياسية أولًا، ثم استخدم تعبيرات نمطية صغيرة على اسم المستخدم فقط.

كيف أحوّل رابط YouTube من نوع /c/ أو /user/ إلى معرّف قناة؟

روابط /user/<name> تقابل فلتر forUsername في YouTube Data API. ولا يوجد فلتر في API لأسماء /c/ المخصصة. راجع الدليل عن الحصول على معرّف قناة YouTube من اسم المستخدم للحالتين.

اعثر على حسابات صانع محتوى