Watch It? Track It.

Arama da statik bir dizindir: her dizinin, filmin ve kişinin her dildeki her adını birlikte kapsayan yaklaşık 7.000 küçük dosya. Bir sorgu için bunlardan biri yeterlidir.

Dosyalar

  • https://api.watchittrackit.com/v1/search/manifest.json
  • https://api.watchittrackit.com/v1/search/{build}/tree.json
  • https://api.watchittrackit.com/v1/search/{build}/l/{hex}.json
  • https://api.watchittrackit.com/v1/search/{build}/s/{hex}.json
  • https://api.watchittrackit.com/v1/search/recent.json

Bir sorguyu arama

  1. Güncel derleme kimliği için v1/search/manifest.json dosyasını okuyun.
  2. v1/search/{build}/tree.json dosyasını okuyun. Bir derleme için hiç değişmez, bu yüzden bir kez indirin.
  3. Sorguyu normalleştirin: küçük harfe çevirin, aksanları ve noktalama işaretlerini kaldırın. Etkisiz sözcük olmayan en uzun sözcüğüyle arayın.
  4. Dosyasını bulmak için ağacı bu sözcükle dolaşın: l/ içinde bir kova ya da sözcük tam olarak bir bölme önekinde bitiyorsa s/ içinde bir özet. Dosya adları, önekin UTF-8 baytlarının onaltılık gösterimidir.
  5. Sorgudaki her sözcüğün adın bir sözcüğünün başlangıcı olduğu girdileri tutun. Sorgunun tamamıyla başlayan adları öne alın, ardından popülerliğe göre sıralayın.
  6. v1/search/recent.json dosyasını uygulayın: derlemeden sonra değişen kayıtları listeler. Dizindeki bu kayıtlara ait girdileri çıkarın ve onların yerine bunları kullanın. Kayıtlar düzenlendikçe değiştiği için güncel bir kopya almak üzere birkaç dakikada bir değişen bir sorgu dizesi ekleyin (?w= ve ardından geçerli 5 dakikalık aralık).

Girdiler

Her girdi bir dizidir (array):

KonumTürAçıklama
0stringKayıt türü.
1numberKayıt kimliği.
2stringEşleşen ad, hangi dilde olursa olsun.
3numberTür içindeki sıra: 1.000.000 en popüleridir.
4stringKayıt slug'ı.
5number | nullYapımlar için yıl.
6string | nullKüçük resim yolu.

Örnek (JavaScript)

const BASE = "https://api.watchittrackit.com/v1/search"
const STOPWORDS = new Set(["a", "an", "and", "the", "of", "in", "on", "to", "for", "at", "by", "with", "or",
  "de", "del", "la", "le", "les", "el", "los", "las", "lo", "un", "une", "et", "du", "des", "da", "do", "dos",
  "der", "die", "das", "und", "ein", "eine", "den", "dem", "von", "zu", "il", "i", "e", "di", "y", "en", "het", "een", "van"])

const normalize = (s) => s.normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase()
  .replace(/[^\p{L}\p{N}]+/gu, " ").trim()
const hex = (s) => [...new TextEncoder().encode(s)].map((b) => b.toString(16).padStart(2, "0")).join("")

async function search(query) {
  const { build } = await fetch(`${BASE}/manifest.json`).then((r) => r.json())
  const tree = await fetch(`${BASE}/${build}/tree.json`).then((r) => r.json())

  const q = normalize(query)
  const words = q.split(" ").filter(Boolean)
  const real = words.filter((w) => !STOPWORDS.has(w))
  const word = (real.length ? real : words).sort((a, b) => [...b].length - [...a].length)[0]

  // Walk the tree: descend while the prefix is split; stop at a bucket or a summary.
  let key = "", file
  for (const c of word) {
    if (tree[key + c]) { key += c; continue }
    const starts = tree[key] ?? []
    const start = starts.filter((s) => s <= c).pop() ?? starts[0] ?? c
    file = `l/${hex(key + start)}.json`
    break
  }
  file ??= `s/${hex(key)}.json`

  const res = await fetch(`${BASE}/${build}/${file}`)
  let entries = res.ok ? await res.json() : []

  // Records changed since the build replace the index's entries for them.
  // The query string changes every 5 minutes, so caches don't serve an old copy.
  const recent = await fetch(`${BASE}/recent.json?w=${Math.floor(Date.now() / 300000)}`).then((r) => r.json())
  entries = entries.filter(([type, id]) => !(`${type}:${id}` in recent.records))
  entries.push(...Object.values(recent.records).flat())

  const seen = new Set()
  return entries
    .filter((e) => { const n = normalize(e[2]).split(" "); return words.every((w) => n.some((x) => x.startsWith(w))) })
    .sort((a, b) => Number(normalize(b[2]).startsWith(q)) - Number(normalize(a[2]).startsWith(q)) || b[3] - a[3])
    .filter(([type, id]) => !seen.has(`${type}:${id}`) && seen.add(`${type}:${id}`))
    .slice(0, 30)
}

// [["tv", 81189, "Breaking Bad", 999998, "breaking-bad", 2008, "/images/tv/81189/….t.jpg"], …]
console.log(await search("breaking bad"))

Dizin her gün yeniden oluşturulur. Bir derlemenin dosyaları hiç değişmez, bu yüzden onları istediğiniz kadar önbelleğe alın; yalnızca manifest ve recent.json değişir.