sociallinks.dev

بلاگ / ڈویلپر گائیڈ

ہینڈل سے YouTube چینل ID کیسے حاصل کریں (اور ID سے ہینڈل)

کریئیٹرز اپنا YouTube چینل @handle کی صورت میں شیئر کرتے ہیں، لیکن YouTube Data API میں تقریباً ہر چیز چینل ID پر چلتی ہے۔ اگر آپ صرف ہینڈل محفوظ کریں تو نام بدلتے ہی آپ کا ریکارڈ ٹوٹ جاتا ہے؛ اگر صرف ID محفوظ کریں تو آپ صارفین کو وہ نام نہیں دکھا سکتے جسے وہ پہچانتے ہیں۔ یہ گائیڈ بتاتی ہے کہ ایک API کال سے ہینڈل کو چینل ID میں کیسے بدلیں، ایک وقت میں 50 ID سے واپس ہینڈل کیسے لیں، پرانے /user/ اور /c/ URLs کا کیا کریں، اور ڈیفالٹ کوٹا کے اندر کیسے رہیں۔

ہینڈل، چینل ID اور پرانے نام

ایک YouTube چینل تک زیادہ سے زیادہ چار قسم کے شناخت کنندہ (identifier) سے پہنچا جا سکتا ہے۔ ان میں سے صرف ایک کے مستقل رہنے کی ضمانت ہے۔

شناخت کنندہمثالURL کی شکلنوٹس
چینل IDUC_x5XG1OV2P6uZZ5FSM9Ttwyoutube.com/channel/UC...وہ ID جس سے YouTube چینل کی شناخت کرتا ہے۔ چھوٹے بڑے حروف کا فرق اہم ہے۔ اسے اپنی بنیادی کلید (primary key) بنائیں۔
ہینڈل@GoogleDevelopersyoutube.com/@GoogleDevelopersمنفرد، چھوٹے بڑے حروف سے فرق نہیں پڑتا، اور مالک اسے YouTube Studio میں بدل سکتا ہے۔
پرانا یوزرنیمGoogleDevelopersyoutube.com/user/GoogleDevelopersپرانے یوزرنیم سسٹم سے۔ API کے forUsername فلٹر سے حل ہو جاتا ہے۔
پرانا کسٹم URLGoogleDevelopersyoutube.com/c/GoogleDevelopersپرانے ذاتی URLs، جن کے بارے میں YouTube کہتا ہے کہ یہ کام کرتے رہیں گے۔ کوئی API فلٹر انہیں حل نہیں کرتا۔

چینل ID کو کلید کے طور پر محفوظ کریں اور ہینڈل کو دکھانے والی قدر کے طور پر رکھیں جسے آپ تازہ کرتے رہیں۔ باقی گائیڈ اسی بارے میں ہے کہ صارف نے جو کچھ دیا، اس سے اس ID تک کیسے پہنچیں۔

API key بنائیں اور کوٹا سمجھیں

  1. Step 1Google Cloud پروجیکٹ بنائیں

    Google Cloud console میں نیا پروجیکٹ بنائیں یا موجودہ پروجیکٹ چنیں۔

  2. Step 2YouTube Data API v3 فعال کریں

    APIs and services کھولیں، لائبریری میں YouTube Data API v3 تلاش کریں اور اسے پروجیکٹ کے لیے فعال کریں۔

  3. Step 3API key بنائیں

    Credentials میں جا کر API key بنائیں۔ عوامی چینل ڈیٹا، جیسے ہینڈل یا ID سے channels.list، کے لیے صرف key کافی ہے، OAuth کی ضرورت نہیں۔ key کو YouTube Data API تک محدود کر دیں۔

  4. Step 4key کو کوڈ سے باہر رکھیں

    اسے کسی environment variable میں رکھیں، مثلاً YOUTUBE_API_KEY، اور رن ٹائم پر پڑھیں۔ نیچے کی مثالیں یہی کرتی ہیں۔

  5. Step 5اپنا کوٹا چیک کریں

    console میں اس API کا Quotas صفحہ آپ کی روزانہ حد اور استعمال دکھاتا ہے۔

Google کی دستاویزات کے مطابق اہم اعداد:

یعنی ڈیفالٹ کوٹا میں روزانہ تقریباً 10,000 ہینڈل تلاش ہو سکتے ہیں، اور ID سے تلاش اس سے 50 گنا تک زیادہ، کیونکہ ایک کال اسی ایک یونٹ میں ID کے ذریعے 50 چینلز لا سکتی ہے۔

forHandle سے ہینڈل کو چینل ID میں بدلیں

channels.list بالکل ایک فلٹر لیتا ہے۔ forHandle فلٹر YouTube ہینڈل لیتا ہے، اور ریفرنس کے مطابق قدر کے شروع میں @ لگایا جا سکتا ہے، اس لیے GoogleDevelopers اور @GoogleDevelopers دونوں چلتے ہیں۔ اگر صرف ID چاہیے تو part=id مانگیں؛ جواب چھوٹا ہوتا ہے اور قیمت وہی رہتی ہے۔

cURL

curl -s "https://www.googleapis.com/youtube/v3/channels?part=id&forHandle=@GoogleDevelopers&key=$YOUTUBE_API_KEY"

نیچے کی Node مثال درخواست کو ایک ہیلپر listChannels میں لپیٹتی ہے جو باقی گائیڈ میں بار بار استعمال ہوتا ہے۔ کچھ نہ ملے تو یہ خالی فہرست لوٹاتا ہے اور اصل غلطیوں پر، جیسے غلط key یا ختم شدہ کوٹا، error پھینکتا ہے۔

Node.js

const API = "https://www.googleapis.com/youtube/v3/channels";
async function listChannels(params) {
  const key = process.env.YOUTUBE_API_KEY;
  if (!key) throw new Error("Set YOUTUBE_API_KEY");
  const url = new URL(API);
  url.search = new URLSearchParams({ ...params, key }).toString();
  const res = await fetch(url, { signal: AbortSignal.timeout(10_000) });
  const data = await res.json();
  if (!res.ok) {
    const reason = data.error?.errors?.[0]?.reason;
    if (reason === "channelNotFound") return [];
    throw new Error(`YouTube API ${res.status} ${reason ?? ""}: ${data.error?.message}`);
  }
  return data.items ?? []; // no match: items is empty or missing
}

/** "@GoogleDevelopers" or "GoogleDevelopers" -> "UC_x5XG1OV2P6uZZ5FSM9Ttw" or null */
export async function channelIdFromHandle(handle) {
  const items = await listChannels({ part: "id", forHandle: handle.trim() });
  return items[0]?.id ?? null;
}

/** Legacy username from a youtube.com/user/<name> URL -> channel ID or null */
export async function channelIdFromUsername(username) {
  const items = await listChannels({ part: "id", forUsername: username.trim() });
  return items[0]?.id ?? null;
}

/** Any number of channel IDs -> Map(id -> { title, customUrl }) */
export async function channelsById(ids) {
  const unique = [...new Set(ids)];
  const found = new Map();
  for (let i = 0; i < unique.length; i += 50) {
    const batch = unique.slice(i, i + 50);
    const items = await listChannels({ part: "snippet", id: batch.join(","), maxResults: "50" });
    for (const ch of items) {
      found.set(ch.id, { title: ch.snippet.title, customUrl: ch.snippet.customUrl ?? null });
    }
  }
  return found; // IDs missing from the map were not found
}

Python

import os

import requests

API = "https://www.googleapis.com/youtube/v3/channels"


def list_channels(**params):
    key = os.environ.get("YOUTUBE_API_KEY")
    if not key:
        raise RuntimeError("Set YOUTUBE_API_KEY")
    response = requests.get(API, params={**params, "key": key}, timeout=10)
    data = response.json()
    if not response.ok:
        errors = data.get("error", {}).get("errors") or [{}]
        reason = errors[0].get("reason")
        if reason == "channelNotFound":
            return []
        raise RuntimeError(f"YouTube API {response.status_code} {reason}: {data.get('error', {}).get('message')}")
    return data.get("items", [])  # no match: items is empty or missing


def channel_id_from_handle(handle):
    """'@GoogleDevelopers' or 'GoogleDevelopers' -> 'UC_x5XG1OV2P6uZZ5FSM9Ttw' or None"""
    items = list_channels(part="id", forHandle=handle.strip())
    return items[0]["id"] if items else None


def channel_id_from_username(username):
    """Legacy username from a youtube.com/user/<name> URL -> channel ID or None"""
    items = list_channels(part="id", forUsername=username.strip())
    return items[0]["id"] if items else None


def channels_by_id(ids):
    """Any number of channel IDs -> {id: {"title", "customUrl"}}; missing IDs were not found"""
    unique = list(dict.fromkeys(ids))
    found = {}
    for i in range(0, len(unique), 50):
        batch = unique[i:i + 50]
        for ch in list_channels(part="snippet", id=",".join(batch), maxResults=50):
            found[ch["id"]] = {
                "title": ch["snippet"]["title"],
                "customUrl": ch["snippet"].get("customUrl"),
            }
    return found

ہینڈل ویسے ہی بھیجیں جیسے صارف نے لکھا، البتہ URL کی percent-encoding پہلے ڈی کوڈ کر لیں۔ ہینڈل میں صرف ASCII نہیں بلکہ کئی رسم الخط کے حروف ہو سکتے ہیں، اور URLSearchParams اور requests دونوں پیرامیٹر کو خود encode کر دیتے ہیں۔

پرانے یوزرنیم اور /c/ کسٹم URLs

کریئیٹرز کے بائیو اور اسپریڈشیٹس میں پرانے لنکس اکثر ہینڈل سے پہلے والی کسی شکل میں ہوتے ہیں۔

چینل ID سے ہینڈل، ایک وقت میں 50

الٹی سمت میں id فلٹر استعمال ہوتا ہے، جو کاما سے الگ چینل IDs کی فہرست لیتا ہے۔ part=snippet مانگیں اور snippet.customUrl پڑھیں۔ اوپر والا channelsById دہرائی گئی IDs ہٹاتا ہے، انہیں 50 کے حصوں میں بھیجتا ہے، اور ID کے حساب سے ایک map لوٹاتا ہے۔ جو IDs map میں نہیں، وہ نہیں ملیں، حذف ہو چکی ہیں یا API کو نظر نہیں آتیں۔

نہ ملنا، غلطیاں اور کیشنگ

جس تلاش سے کچھ نہ ملے وہ غلطی نہیں۔ forHandle اور forUsername کے لیے جواب میں بس کوئی items نہیں ہوتے، اس لیے خالی یا غائب items array چیک کریں۔ channels.list کی دستاویزی غلطیاں یہ ہیں:

غلطی کی وجہHTTPکب ہوتی ہےکیا کریں
200 جواب میں کوئی items نہیں200ہینڈل یا یوزرنیم موجود نہیںnull لوٹائیں؛ نہ ملنے کو تھوڑی دیر کے لیے کیش کریں
channelNotFound404id پیرامیٹر میں کوئی چینل نہیں مل سکااسے نہ ملا سمجھیں، جیسے اوپر کے ہیلپرز کرتے ہیں
invalidCriteria400درخواست میں ایک سے زیادہ فلٹرforHandle، forUsername یا id میں سے بالکل ایک بھیجیں
channelForbidden403چینل اس درخواست کو سپورٹ نہیں کرتا یا درست اجازت نہیںلاگ کریں اور چینل چھوڑ دیں
quotaExceeded403آپ کے پروجیکٹ نے روزانہ کوٹا استعمال کر لیارک جائیں اور Pacific Time کی آدھی رات کے بعد دوبارہ کوشش کریں، یا زیادہ کوٹا مانگیں
badRequest (API key درست نہیں)400key غائب یا غلطکنفیگریشن ٹھیک کریں؛ دوبارہ کوشش نہ کریں

کوٹا اور وقت بچانے کے لیے نتائج کیش کریں، لیکن ڈیٹا محفوظ کرنے کے بارے میں YouTube کے اصولوں کا خیال رکھیں۔ YouTube API Services Developer Policies (سیکشن III.E.4) کے مطابق آپ غیر مجاز API ڈیٹا زیادہ سے زیادہ 30 کیلنڈر دن محفوظ رکھ سکتے ہیں، اس کے بعد اسے حذف یا تازہ کرنا ضروری ہے۔ چھوٹے حروف والے ہینڈل کو کلید بنا کر 30 دن سے کافی کم TTL والا کیش زیادہ تر فائدہ دے دیتا ہے:

Node.js کیش

import { channelIdFromHandle } from "./youtube.mjs";

const TTL_MS = 7 * 24 * 60 * 60 * 1000; // refresh well inside YouTube's 30-day limit
const cache = new Map(); // lowercase handle -> { id, at }

export async function cachedChannelId(handle) {
  const key = handle.trim().replace(/^@/, "").toLowerCase();
  const hit = cache.get(key);
  if (hit && Date.now() - hit.at < TTL_MS) return hit.id;
  const id = await channelIdFromHandle(handle);
  cache.set(key, { id, at: Date.now() }); // caches misses (null) too
  return id;
}

پروڈکشن میں یہی منطق Redis یا expires_at کالم والی ڈیٹا بیس ٹیبل میں رکھیں، اور نہ ملنے والے نتائج کا TTL ملنے والوں سے کم رکھیں تاکہ نیا بنا ہینڈل جلد پکڑا جائے۔

API key کے بغیر متبادل: چینل کا صفحہ پڑھنا

عوامی چینل صفحات کے HTML میں چینل ID موجود ہوتی ہے۔ https://www.youtube.com/@GoogleDevelopers کی درخواست اس وقت ایسا صفحہ لوٹاتی ہے جس کا <link rel="canonical"> https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw کی طرف اشارہ کرتا ہے، اور /c/ اور /user/ صفحات کا بھی یہی حال ہے، اس لیے اندازے کے بغیر /c/ نام حل کرنے کا یہی ایک طریقہ ہے۔

Node.js

// Unofficial fallback: reads the public channel page. Fragile, prefer the API.
export async function channelIdFromPage(handle) {
  const url = `https://www.youtube.com/@${encodeURIComponent(handle.replace(/^@/, ""))}`;
  const res = await fetch(url, {
    headers: { "Accept-Language": "en-US" },
    signal: AbortSignal.timeout(10_000),
  });
  if (!res.ok) return null;
  const html = await res.text();
  const match = html.match(/<link rel="canonical" href="https:\/\/www\.youtube\.com\/channel\/(UC[A-Za-z0-9_-]{22})"/);
  return match?.[1] ?? null;
}

Python

import re
from urllib.parse import quote

import requests

CANONICAL = re.compile(r'<link rel="canonical" href="https://www\.youtube\.com/channel/(UC[A-Za-z0-9_-]{22})"')


def channel_id_from_page(handle):
    """Unofficial fallback: reads the public channel page. Fragile, prefer the API."""
    url = "https://www.youtube.com/@" + quote(handle.lstrip("@"), safe="._-")
    response = requests.get(url, headers={"Accept-Language": "en-US"}, timeout=10)
    if not response.ok:
        return None
    match = CANONICAL.search(response.text)
    return match.group(1) if match else None

اسے کم سے کم اور صرف وہاں استعمال کریں جہاں API مدد نہ کر سکے۔ یہ غیر سرکاری اور نازک طریقہ ہے:

طریقوں کا موازنہ

طریقہان پٹقیمتفائدےنقصانات
channels.list مع forHandleہینڈل، @ کے ساتھ یا بغیرفی ہینڈل 1 یونٹسرکاری، بالکل درست، ہر ہینڈل پر کام کرتا ہےہر کال میں ایک ہینڈل
channels.list مع forUsernameپرانا /user/ نامفی نام 1 یونٹسرکاری، بالکل درستصرف پرانے یوزرنیمز کے لیے
channels.list مع id50 تک چینل IDsہر 50 IDs پر 1 یونٹسرکاری، بیچ میں، عنوان اور customUrl دیتا ہےcustomUrl غائب ہو سکتا ہے
search.listآزاد متنالگ حد، ڈیفالٹ روزانہ 100 کالزنام سے چینل ڈھونڈتا ہےدرجہ بند اندازے، درست نہیں؛ کم گنجائش
چینل صفحے کا canonical لنککوئی بھی چینل URL، /c/ سمیتکوئی API کوٹا نہیںkey کے بغیر چلتا ہے؛ /c/ نام حل کرتا ہےغیر سرکاری، نازک، بلاک ہو سکتا ہے، شرائط سے ٹکرا سکتا ہے

زیادہ تر پروڈکٹس کے لیے درست ترتیب سادہ ہے: forHandle سے ہینڈل حل کریں، چینل ID محفوظ کریں، id فلٹر سے 50 کے بیچ میں ہینڈل تازہ کریں، اور کبھی کبھار آنے والے /c/ لنک کے لیے صفحے والا متبادل ایک فلیگ کے پیچھے رکھیں۔ اگر آپ کو دوسرے پلیٹ فارمز پر کریئیٹر کے اکاؤنٹس بھی چاہییں تو sociallinks.dev ایک API ہے جو ایک Instagram، TikTok، YouTube یا X پروفائل URL لیتا ہے اور دوسرے پلیٹ فارمز پر کریئیٹر کے اکاؤنٹس لوٹاتا ہے، ہر میچ کے ساتھ اعتماد کا اسکور اور ثبوت۔

عام سوالات

کیا forHandle میں ہینڈل بھیجتے وقت @ ضروری ہے؟

نہیں۔ channels.list ریفرنس کہتا ہے کہ forHandle کی قدر کے شروع میں @ لگایا جا سکتا ہے، اور مثال میں GoogleDevelopers اور @GoogleDevelopers دونوں دیتا ہے۔

ہینڈل کی ایک تلاش پر کتنا کوٹا لگتا ہے؟

ایک یونٹ۔ ہر channels.list کال پر 1 یونٹ لگتا ہے، اور ڈیفالٹ حد روزانہ 10,000 یونٹ ہے جو Pacific Time کی آدھی رات کو ری سیٹ ہوتی ہے۔ غلط درخواستوں پر بھی کم از کم 1 یونٹ لگتا ہے۔

کیا ایک کال میں کئی ہینڈل تلاش ہو سکتے ہیں؟

نہیں۔ forHandle ایک ہی ہینڈل لیتا ہے۔ صرف id فلٹر کاما سے الگ فہرست قبول کرتا ہے، اس لیے الٹی سمت (IDs سے ہینڈل) کو بیچ میں کریں اور سیدھی سمت کو کیش کریں۔

کیا چینل ID کبھی بدلتی ہے؟

چینل ID وہ شناخت کنندہ ہے جس سے YouTube چینل کی منفرد شناخت کرتا ہے۔ ہینڈل یا عنوان بدلنے سے یہ نہیں بدلتی۔ اسی لیے یہ درست بنیادی کلید ہے۔ ہینڈل، عنوان اور کسٹم URLs سب بدل سکتے ہیں۔

snippet.customUrl خالی کیوں آتا ہے؟

ہر چینل کے پاس کسٹم URL نہیں ہوتا، جیسا کہ YouTube کی اپنی ریویژن ہسٹری میں لکھا ہے۔ اس فیلڈ کو اختیاری سمجھیں اور اس کی جگہ /channel/UC... URL دکھائیں۔

نتائج کتنی دیر کیش کر سکتا ہوں؟

YouTube کی Developer Policies محفوظ API ڈیٹا کو حذف یا تازہ کرنے سے پہلے 30 کیلنڈر دن تک محدود کرتی ہیں۔ ملنے والے نتائج کے لیے ایک ہفتہ یا کم اور نہ ملنے والوں کے لیے اس سے کم TTL آپ کو اس حد کے اندر رکھتا ہے۔

کسی کریئیٹر کے اکاؤنٹس تلاش کریں