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
|
/* 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. */
|
* olmayabiliyor; orada son çare videonun kendi ucundan sorulur. */
|
||||||
function channelIdOf(card, videoId) {
|
function channelIdOf(card, videoId) {
|
||||||
var found = handleOf(card) || pageChannel();
|
var found = handleOf(card) || pageChannel();
|
||||||
if (found && found.channelId) return Promise.resolve(found.channelId);
|
if (found && found.channelId) return Promise.resolve(found.channelId);
|
||||||
if (found && found.handle) {
|
if (found && found.handle) return resolveHandle(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;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var key = "v:" + videoId;
|
var key = "v:" + videoId;
|
||||||
return OBStore.readChannelId(key).then(function (cached) {
|
return OBStore.readChannelId(key).then(function (cached) {
|
||||||
if (cached) return cached;
|
if (cached) return cached;
|
||||||
|
|||||||
+32
-17
@@ -268,32 +268,47 @@ var OBTube = (function () {
|
|||||||
return post("browse", { browseId: channelId, params: params }).then(round);
|
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. */
|
/* @handle veya kanal adresini UC... kimliğine çevirir. */
|
||||||
function resolveChannel(raw) {
|
function resolveChannel(raw) {
|
||||||
raw = (raw || "").trim();
|
raw = (raw || "").trim();
|
||||||
if (!raw) return Promise.reject(new Error("boş kanal adresi"));
|
if (!raw) return Promise.reject(new Error("boş kanal adresi"));
|
||||||
if (/^UC[\w-]{22}$/.test(raw)) return Promise.resolve(raw);
|
if (/^UC[\w-]{22}$/.test(raw)) return Promise.resolve(raw);
|
||||||
if (raw.indexOf("/channel/") >= 0) {
|
var direct = channelIdIn(raw);
|
||||||
var tail = raw.split("/channel/")[1].split("/")[0].split("?")[0];
|
if (direct) return Promise.resolve(direct);
|
||||||
if (tail.indexOf("UC") === 0) return Promise.resolve(tail);
|
|
||||||
}
|
|
||||||
var url = raw;
|
var url = raw;
|
||||||
if (url.indexOf("http") !== 0) {
|
if (url.indexOf("http") !== 0) {
|
||||||
url = "https://www.youtube.com/" + (url.charAt(0) === "@" ? url : "@" + url.replace(/^\/+/, ""));
|
url = "https://www.youtube.com/" + (url.charAt(0) === "@" ? url : "@" + url.replace(/^\/+/, ""));
|
||||||
}
|
}
|
||||||
return post("navigation/resolve_url", { url: url }).then(function (data) {
|
return resolveStep(url, raw, 0);
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Videonun kanal kimliği ve tam izlenme sayısı. Kartta kanal bağlantısı
|
/* 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");
|
return OBTube.resolveChannel("@LinusTechTips");
|
||||||
}).then((id) => {
|
}).then((id) => {
|
||||||
eq(id, CHANNEL, "handle -> kanal kimliği");
|
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")
|
/* 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
|
* YouTube tarafında ayrıcalıklı davranıp uç bozulduğunda bile yanıt
|
||||||
* verebiliyor ve testi yanlış yere yeşil gösteriyordu. */
|
* verebiliyor ve testi yanlış yere yeşil gösteriyordu. */
|
||||||
|
|||||||
Reference in New Issue
Block a user