mirror of
https://github.com/yusufipk/YouTubeOutlierBadge.git
synced 2026-09-11 10:56:14 +00:00
Merge pull request #2 from yusufipk/claude/vanity-handle-resolve
Follow the redirect when a handle resolves to a legacy vanity address
This commit is contained in:
+21
-10
@@ -107,20 +107,31 @@
|
||||
}
|
||||
|
||||
/* Handle'dan kanal kimliğine çözüm kalıcıdır (değişmez), o yüzden TTL'siz
|
||||
* saklanır. İzleme sayfasının yan listesinde kartta kanal bağlantısı hiç
|
||||
* saklanır. Arama sonuçlarında aynı kanaldan onlarca kart aynı anda ekrana
|
||||
* giriyor ve depo okuması asenkron olduğu için hepsi önbelleği ıskalayıp
|
||||
* aynı çözümü ayrı ayrı isterdi; devam eden istek paylaşılıyor. */
|
||||
var resolving = {};
|
||||
|
||||
function resolveHandle(handle) {
|
||||
if (resolving[handle]) return resolving[handle];
|
||||
var promise = OBStore.readChannelId(handle).then(function (cached) {
|
||||
if (cached) return cached;
|
||||
return OBTube.resolveChannel(handle).then(function (id) {
|
||||
OBStore.writeChannelId(handle, id);
|
||||
return id;
|
||||
});
|
||||
});
|
||||
resolving[handle] = promise;
|
||||
promise.catch(function () {}).then(function () { delete resolving[handle]; });
|
||||
return promise;
|
||||
}
|
||||
|
||||
/* İzleme sayfasının yan listesinde kartta kanal bağlantısı hiç
|
||||
* olmayabiliyor; orada son çare videonun kendi ucundan sorulur. */
|
||||
function channelIdOf(card, videoId) {
|
||||
var found = handleOf(card) || pageChannel();
|
||||
if (found && found.channelId) return Promise.resolve(found.channelId);
|
||||
if (found && found.handle) {
|
||||
return OBStore.readChannelId(found.handle).then(function (cached) {
|
||||
if (cached) return cached;
|
||||
return OBTube.resolveChannel(found.handle).then(function (id) {
|
||||
OBStore.writeChannelId(found.handle, id);
|
||||
return id;
|
||||
});
|
||||
});
|
||||
}
|
||||
if (found && found.handle) return resolveHandle(found.handle);
|
||||
var key = "v:" + videoId;
|
||||
return OBStore.readChannelId(key).then(function (cached) {
|
||||
if (cached) return cached;
|
||||
|
||||
+32
-17
@@ -268,32 +268,47 @@ var OBTube = (function () {
|
||||
return post("browse", { browseId: channelId, params: params }).then(round);
|
||||
}
|
||||
|
||||
function channelIdIn(url) {
|
||||
if (!url || url.indexOf("/channel/") < 0) return null;
|
||||
var tail = url.split("/channel/")[1].split("/")[0].split("?")[0];
|
||||
return /^UC[\w-]{22}$/.test(tail) ? tail : null;
|
||||
}
|
||||
|
||||
/* Tek istekte bitmeyebilir: eski özel adresi olan kanallarda YouTube
|
||||
* @handle'ı önce youtube.com/eskiad adresine yolluyor, kanal kimliği ancak
|
||||
* bir sonraki adımda geliyor. Zincir kısa, sıçrama sayısı sınırlı: hem
|
||||
* döngüye girmeyelim hem de tek kart için istek yağdırmayalım. */
|
||||
var MAX_RESOLVE_HOPS = 3;
|
||||
|
||||
function resolveStep(url, raw, hops) {
|
||||
return post("navigation/resolve_url", { url: url }).then(function (data) {
|
||||
var endpoint = P.findFirst(data, "browseEndpoint") || {};
|
||||
var id = endpoint.browseId || "";
|
||||
if (/^UC[\w-]{22}$/.test(id)) return id;
|
||||
var next = (P.findFirst(data, "urlEndpoint") || {}).url || "";
|
||||
var direct = channelIdIn(next);
|
||||
if (direct) return direct;
|
||||
/* Sadece YouTube içinde kalan yönlendirmeler izlenir. */
|
||||
var internal = /^https?:\/\/(www\.)?youtube\.com\//.test(next);
|
||||
if (internal && next !== url && hops < MAX_RESOLVE_HOPS) {
|
||||
return resolveStep(next, raw, hops + 1);
|
||||
}
|
||||
throw new Error("kanal çözülemedi: " + raw);
|
||||
});
|
||||
}
|
||||
|
||||
/* @handle veya kanal adresini UC... kimliğine çevirir. */
|
||||
function resolveChannel(raw) {
|
||||
raw = (raw || "").trim();
|
||||
if (!raw) return Promise.reject(new Error("boş kanal adresi"));
|
||||
if (/^UC[\w-]{22}$/.test(raw)) return Promise.resolve(raw);
|
||||
if (raw.indexOf("/channel/") >= 0) {
|
||||
var tail = raw.split("/channel/")[1].split("/")[0].split("?")[0];
|
||||
if (tail.indexOf("UC") === 0) return Promise.resolve(tail);
|
||||
}
|
||||
var direct = channelIdIn(raw);
|
||||
if (direct) return Promise.resolve(direct);
|
||||
var url = raw;
|
||||
if (url.indexOf("http") !== 0) {
|
||||
url = "https://www.youtube.com/" + (url.charAt(0) === "@" ? url : "@" + url.replace(/^\/+/, ""));
|
||||
}
|
||||
return post("navigation/resolve_url", { url: url }).then(function (data) {
|
||||
var endpoint = P.findFirst(data, "browseEndpoint") || {};
|
||||
var id = endpoint.browseId || "";
|
||||
if (id.indexOf("UC") === 0) return id;
|
||||
/* Eski /user/ adresi olan kanallarda YouTube browseEndpoint yerine
|
||||
* urlEndpoint ile başka bir adrese yolluyor. */
|
||||
var next = (P.findFirst(data, "urlEndpoint") || {}).url || "";
|
||||
if (next.indexOf("/channel/") >= 0) {
|
||||
var t = next.split("/channel/")[1].split("/")[0].split("?")[0];
|
||||
if (t.indexOf("UC") === 0) return t;
|
||||
}
|
||||
throw new Error("kanal çözülemedi: " + raw);
|
||||
});
|
||||
return resolveStep(url, raw, 0);
|
||||
}
|
||||
|
||||
/* Videonun kanal kimliği ve tam izlenme sayısı. Kartta kanal bağlantısı
|
||||
|
||||
@@ -120,6 +120,13 @@ OBTube.channelTab(CHANNEL, "videos", 30).then((items) => {
|
||||
return OBTube.resolveChannel("@LinusTechTips");
|
||||
}).then((id) => {
|
||||
eq(id, CHANNEL, "handle -> kanal kimliği");
|
||||
return OBTube.resolveChannel("@MesutCevik");
|
||||
}).then((id) => {
|
||||
/* Eski özel adresi olan bir kanal: YouTube @handle'ı önce
|
||||
* youtube.com/mesutcevik adresine yolluyor, kimlik ancak ikinci adımda
|
||||
* geliyor. Tek adımda çözen kod bu kanallarda "kanal çözülemedi" veriyor ve
|
||||
* o kanalın hiçbir kartı puanlanmıyordu. */
|
||||
eq(id, "UCOFafpmI_dt8SxisbKniN4A", "yönlendirmeli handle -> kanal kimliği");
|
||||
/* Bilerek kanalın güncel bir videosu: sabit bir klasik ("dQw4w9WgXcQ")
|
||||
* YouTube tarafında ayrıcalıklı davranıp uç bozulduğunda bile yanıt
|
||||
* verebiliyor ve testi yanlış yere yeşil gösteriyordu. */
|
||||
|
||||
Reference in New Issue
Block a user