Identyfikatory videoId i channelId na YouTube są pojedynczymi liczbami całkowitymi reprezentowanymi w nieco zmodyfikowanej wersji kodowania Base64 . Jedną różnicą w porównaniu z zaleceniami IETF RFC4648 jest podstawienie dwóch znaków w alfabecie kodującym:
Payload ASCII/Unicode Base64 YouTube
------- ------------- --------- ---------
0...25 \x41 ... \x5A 'A'...'Z' 'A'...'Z'
26...51 \x61 ... \x7A 'a'...'z' 'a'...'z'
52...61 \x30 ... \x39 '0'...'9' '0'...'9'
62 \x2F vs. \x2D → '/' (2F) '-' (2D)
63 \x2B vs. \x5F → '+' (2B) '_' (5F)
Podstawienie prawdopodobnie wynika z faktu, że z jakiegoś powodu RFC4648 wybrał dwa znaki, które miały już znaczące i dobrze ugruntowane funkcje w adresach URL. [uwaga 1.] Oczywiście, w przypadku omawianego tutaj zastosowania najlepiej unikać tej szczególnej komplikacji.
Inną różnicą w stosunku do oficjalnej specyfikacji jest to, że identyfikatory YouTube nie używają =
znaku dopełniającego; nie jest to konieczne, ponieważ zakodowane długości oczekiwane dla każdego zdekodowanego rozmiaru liczby całkowitej są stałe i znane (11 i 22 zakodowanych „cyfr” odpowiednio dla 64 i 128 bitów).
Z jednym drobnym wyjątkiem (omówionym poniżej), pełne szczegóły mapowania Base64 można wywnioskować z publicznie dostępnych danych. Przy minimalnym zgadywaniu prawdopodobne jest, że schemat Base64 użyty w ciągach videoId i channelId wygląda następująco:
——₀————₁————₂————₃————₄————₅————₆————₇————₈————₉———₁₀———₁₁———₁₂———₁₃———₁₄———₁₅—
00ᴴ 01ᴴ 02ᴴ 03ᴴ 04ᴴ 05ᴴ 06ᴴ 07ᴴ 08ᴴ 09ᴴ 0Aᴴ 0Bᴴ 0Cᴴ 0Dᴴ 0Eᴴ 0Fᴴ
00→ 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
A B C D E F G H I J K L M N O P
—₁₆———₁₇———₁₈———₁₉———₂₀———₂₁———₂₂———₂₃———₂₄———₂₅———₂₆———₂₇———₂₈———₂₉———₃₀———₃₁—
10ᴴ 11ᴴ 12ᴴ 13ᴴ 14ᴴ 15ᴴ 16ᴴ 17ᴴ 18ᴴ 19ᴴ 1Aᴴ 1Bᴴ 1Cᴴ 1Dᴴ 1Eᴴ 1Fᴴ
01→ 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
Q R S T U V W X Y Z a b c d e f
—₃₂———₃₃———₃₄———₃₅———₃₆———₃₇———₃₈———₃₉———₄₀———₄₁———₄₂———₄₃———₄₄———₄₅———₄₆———₄₇—
20ᴴ 21ᴴ 22ᴴ 23ᴴ 24ᴴ 25ᴴ 26ᴴ 27ᴴ 28ᴴ 29ᴴ 2Aᴴ 2Bᴴ 2Cᴴ 2Dᴴ 2Eᴴ 2Fᴴ
10→ 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
g h i j k l m n o p q r s t u v
—₄₈———₄₉———₅₀———₅₁———₅₂———₅₃———₅₄———₅₅———₅₆———₅₇———₅₈———₅₉———₆₀———₆₁———₆₂———₆₃—
30ᴴ 31ᴴ 32ᴴ 33ᴴ 34ᴴ 35ᴴ 36ᴴ 37ᴴ 38ᴴ 39ᴴ 3Aᴴ 3Bᴴ 3Cᴴ 3Dᴴ 3Eᴴ 3Fᴴ
11→ 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
w x y z 0 1 2 3 4 5 6 7 8 9 - _
Powodem, aby sądzić, że Base64 jest używany jest to, że gdy przyjmiemy standardowe rozmiary całkowitą od 64 do 128 bitów dla wejścia enkodera, Base64 przewiduje się niezwykłych znaków długości (11 i 22 znaki) YouTube ID kanału i videoID identyfikatory dokładnie. Ponadto, reszty obliczone zgodnie z Base64 doskonale wyjaśniają zaobserwowane zmiany dystrybucyjne znalezione w l̲a̲s̲t̲ c̲h̲a̲r̲a̲c̲t̲e̲r̲ każdego typu łańcucha identyfikacyjnego. Omówienie tych punktów następuje.
W obu przypadkach binarne „dane”, które są kodowane w standardzie Base64, to pojedyncza liczba całkowita, 64 lub 128 bitów, odpowiednio dla videoID i ChannelID . Odpowiednio, za pomocą dekodera Base64 można odzyskać pojedynczą liczbę całkowitą z identyfikatora ciągu i może to być bardzo przydatne, ponieważ chociaż każdy identyfikator liczby całkowitej zawiera dokładnie takie same informacje jak ciąg Base64 - a także pozwala ciągowi na być odtworzone w dowolnym momencie - w porównaniu do ciągów Base64 przechowywanych jako Unicode, reprezentacja binarna jest o 63% mniejsza, ma maksymalną gęstość bitów wynoszącą 100%, lepiej wyrównuje się w pamięci, szybciej sortuje i hashuje, a co najważniejsze, eliminuje fałszywe kolizje między identyfikatorami, które różnią się jedynie wielkością ortograficzną. Ten ostatni problem, choć liczbowo niezwykle nieprawdopodobny, nie można jednak wykluczyć, gdy identyfikatory Base64 są traktowane jako bez rozróżniania wielkości liter, tak jak robią to niektóre systemy plików (np. Windows , pochodzące z DOS ).
Jest to dość ważne: jeśli używasz ciągu videoId / channelId jako części nazwy pliku Windows / NTFS, znikają znikome - ale mimo to niezerowe - prawdopodobieństwo kolizji nazw plików z uwagi na to, że systemy plików wdrażają ścieżkę i nazewnictwo bez rozróżniania wielkości liter .
Jeśli martwisz się tym zdalnie możliwym problemem, jednym ze sposobów matematycznego wyeliminowania byłoby ponowne zakodowanie liczb całkowitych dekodowanych - wciąż uzyskanych zgodnie z opisem w tym artykule - na wartość bazową 10 (dziesiętną) lub (jednolitą - cased) reprezentacja szesnastkowa, do stosowania w ścieżkach lub nazwach plików w takich systemach plików. [uwaga 2.] W tym podejściu 64-bitowy identyfikator wideo wymagałby 20 cyfr dziesiętnych [0-9]
lub 8 cyfr szesnastkowych [0-9,A-F]
(w porównaniu z 11 cyframi Base64). 128-bitowy channelId wymagałby maksymalnie 39 cyfr dziesiętnych lub 16 cyfr szesnastkowych (w porównaniu z 22 cyframi Base64).
Dekodowanie do pliku binarnego jest trywialne w przypadku wersji 64-bitowej, ponieważ można użyć UInt64
( ulong
w języku C # ) do przechowywania natywnej wartości binarnej, która powraca.
/// <summary> Recover the unique 64-bit value from an 11-character videoID </summary>
/// <remarks>
/// The method of padding shown here (i.e. 'b64pad') is provided to demonstrate the
/// full and correct padding requirement for Base64 in general. For our cases:
///
/// videoId → 11 chars → b64pad[11 % 3] → b64pad[2] → "="
/// channelId → 22-chars → b64pad[22 % 3] → b64pad[1] → "=="
///
/// Note however that, because it returns 'ulong', this function only works for videoId
/// values, and the padding will always end up being "=". This is assumed in the revised
/// version of this code given further below, by just hard-coding the value "=".
/// </remarks>
static ulong YtEnc_to_videoId(String ytId)
{
String b64 = ytId.Replace('-', '+').Replace('_', '/') + b64pad[ytId.Length % 3];
return BitConverter.ToUInt64(Convert.FromBase64String(b64), 0);
}
static String[] b64pad = { "", "==", "=" };
W przypadku wartości 128-bitowych jest to nieco trudniejsze, ponieważ jeśli twój kompilator nie ma __int128
reprezentacji, musisz wymyślić sposób na przechowanie całości i utrzymanie jej w kombinacji podczas przekazywania. Prosty typ wartości (lub System.Numerics.Vectors.Vector<T>
, który przejawia się jako 128-bitowy rejestr sprzętowy SIMD, jeśli jest dostępny), sprawdzi się w .NET (nie pokazano).
[ edytuj: ]
Po dalszych przemyśleniach część mojego oryginalnego postu nie została maksymalnie ukończona. Dla zachowania sprawiedliwości oryginalny fragment zostaje zachowany (możesz go pominąć, jeśli chcesz); bezpośrednio poniżej wyjaśniam brakujący wgląd:
[ Oryginalny: ]
Można zauważyć, że wyżej pisałem, że można odzyskać „ jest ” całkowitą. Czy nie byłaby to wartość pierwotnie zakodowana? Niekoniecznie. I nie odnoszę się do podpisanego / niepodpisanego rozróżnienia, którego, prawdą, nie można tutaj ustalić (ponieważ nie zmienia to żadnych faktów na temat obrazu binarnego). To same wartości liczbowe: bez „ Rosetta Stone”„pozwoliłoby nam to sprawdzić z absolutnymi wartościami, o których wiadomo, że są„ prawidłowe ”, mapowanie alfabetu numerycznego, a także endianowość nie mogą być znane, co oznacza, że nie ma gwarancji, że odzyskasz tę samą wartość, co komputery w YouTube zakodowane. Na szczęście, o ile YouTube nigdy publicznie nie ujawnia tak zwanych poprawnych wartości w mniej nieprzejrzystym formacie gdzieś indziej, nie może to mieć znaczenia.
Jest tak, ponieważ zdekodowane 64- lub 128-bitowe wartości nie mają innego zastosowania niż token identyfikacyjny, więc nasze jedyne wymagania dotyczące transformacji to odrębne kodowanie (nie zderzają się dwa unikalne tokeny) i odwracalność (dekodowanie odzyskuje oryginalną tożsamość tokena).
Innymi słowy, wszystko, na czym nam naprawdę zależy, to bezstratne okrążanie oryginalnego ciągu Base64. Ponieważ Base64 jest bezstratny i odwracalny (o ile zawsze trzymasz się tego samego odwzorowania alfabetu i założenia endianness zarówno dla kodowania, jak i dekodowania), spełnia nasze cele. Twoje wartości liczbowe mogą nie zgadzać się z wartościami zarejestrowanymi w głównej przechowalni YouTube, ale nie będziesz w stanie stwierdzić żadnej różnicy.
[ Nowa analiza: ]
Okazuje się, że tam są kilka wskazówek, które mogą nam powiedzieć o „prawdziwej” Base64 mapowania. Tylko niektóre odwzorowania przewidują znaki pozycji końcowej, które obserwujemy, co oznacza, że wartość binarna tylko dla tych znaków musi mieć określoną liczbę zer LSB. Heh
W połączeniu z bardzo prawdopodobnym założeniem, że znaki alfabetu i cyfry są mapowane w kolejności rosnącej, możemy w zasadzie potwierdzić mapowanie tak, jak pokazano w powyższych tabelach. Jedyną pozostałą niepewnością, co do której analiza LSB nie jest jednoznaczna, jest możliwa zamiana znaków -
i _
( 62
/ 63
).
Oryginalny tekst zrobił omówić tę kwestię LSB (patrz poniżej), ale to, co nie w pełni zrealizować w tym czasie był jak LSB informacji działa w celu ograniczenia możliwych Base64 mapowania.
Ostatnim komentarzem na ten temat jest to, że faktycznie możesz celowo wybrać big-endian do interpretacji binarnej, z którą aplikacja współpracuje wewnętrznie (nawet jeśli obecnie jest mniej powszechna niż little-endian, a zatem może nie być to sposób, w jaki YouTube „oficjalnie” robi to). Powodem jest to, że jest to przypadek podwójnego widoku tej samej wartości, tak że rzeczywista kolejność bajtów jest widocznie widoczna w wersji Base64. Utrzymanie zgodności sortowania między wartością binarną a (nieco bardziej) czytelnym dla człowieka łańcuchem Base64 jest pomocne i mniej mylące , ale rodzaj wartości binarnych little-endian jest nietrywialną mieszanką pożądanego sortowania ASCII / leksykalnego .
Nie ma prostej naprawy tego problemu, jeśli zaczniesz od wartości identyfikatora little-endian (tzn. Po prostu odwrócenie ich sortowania nie zadziała). Zamiast tego musisz zaplanować z wyprzedzeniem i odwrócić bajty każdej wartości binarnej w momencie dekodowania . Jeśli więc zależy Ci na wyświetlaniu alfabetycznym zgodnym z sortowaniem wartości binarnych, możesz zmienić funkcję pokazaną powyżej, aby zamiast tego dekodowała się na wartości big-endian ulong
. Oto ten kod:
// Recover the unique 64-bit value (big-endian) from an 11-character videoID
static ulong YtEnc_to_videoId(String ytId)
{
var a = Convert.FromBase64String(ytId.Replace('-', '+').Replace('_', '/') + "=");
if (BitConverter.IsLittleEndian) // true for most computers nowadays
Array.Reverse(a);
return BitConverter.ToUInt64(a, 0);
}
Identyfikatory YouTube
Identyfikator wideo
Dla videoId jest to 8-bajtowa (64-bitowa) liczba całkowita. Zastosowanie kodowania Base64 do 8 bajtów danych wymaga 11 znaków . Ponieważ jednak każdy znak Base64 przenosi dokładnie 6 bitów (tzn. 2⁶ równa się 64), alokacja ta może faktycznie wytrzymać do 11 × 6 = 66
bitów - nadwyżka 2 bitów nad 64 bitami, których potrzebuje nasz ładunek. Nadmiarowe bity są ustawiane na zero, co powoduje, że pewne znaki nigdy nie pojawią się na ostatniej pozycji zakodowanego ciągu. W szczególności na videoId zawsze kończy się jeden z następujących znaków:
{ A, E, I, M, Q, U, Y, c, g, k, o, s, w, 0, 4, 8 }
Zatem maksymalnie ograniczone wyrażenie regularne (RegEx) dla videoId byłoby następujące:
[0-9A-Za-z_-]{10}[048AEIMQUYcgkosw]
Identyfikator kanału lub listy odtwarzania
W ID kanału i playlistId łańcuchy wytwarzane są przez base64 kodujący 128-bitowej (16 bajtów) całkowitą binarną. Daje to 22-znakowy ciąg, który może być poprzedzony albo UC
identyfikacją samego kanału, albo UU
oznaczeniem pełnej listy odtwarzania zawartych w nim filmów. Te 24-znakowe ciągi znaków są używane w adresach URL . Na przykład poniżej pokazano dwa sposoby odwoływania się do tego samego kanału. Zauważ, że wersja listy odtwarzania pokazuje całkowitą liczbę filmów na kanale, [patrz uwaga 3] użyteczna informacja, której strony kanału nie ujawniają.
URL kanałuhttps://www.youtube.com/channel/UC K8sQmJBp8GCxrOtXWBpyEA
URL listy odtwarzaniahttps://www.youtube.com/playlist?list=UU K8sQmJBp8GCxrOtXWBpyEA
Podobnie jak w przypadku 11-znakowego wideoId , obliczenia dla Base64 poprawnie przewidują obserwowaną długość ciągu 22 znaków . W takim przypadku dane wyjściowe mogą kodować 22 × 6 = 132
bity, co stanowi nadwyżkę 4 bitów; te zera ostatecznie ograniczają pojawianie się na ostatniej pozycji 64 znaków alfabetu, przy czym tylko 4 kwalifikują się. Wiemy zatem, że ostatni znak w łańcuchu kanału YouTube musi być jednym z następujących:
{ A, Q, g, w }
To daje nam maksymalnie ograniczone wyrażenie regularne dla channelId :
[0-9A-Za-z_-]{21}[AQgw]
Ostatnia uwaga: wyrażenia regularne pokazane powyżej opisują tylko same wartości identyfikatora, bez prefiksów, ukośników, separatorów itp., Które muszą być obecne w adresach URL i innych różnych zastosowaniach. Wzory RegEx, które przedstawiłem, są tak matematycznie minimalne, jak to możliwe, biorąc pod uwagę właściwości ciągów identyfikatora, ale jeśli zostaną użyte w niezmienionej postaci bez dodatkowego kontekstu, prawdopodobnie wygenerują wiele fałszywych trafień, to znaczy: niepoprawnie dopasują fałszywy tekst. Aby uniknąć tego problemu w rzeczywistym użyciu, należy otoczyć je możliwie dużą ilością oczekiwanego kontekstu sąsiedniego.
Uwagi
[1.]
Jak obiecano powyżej, oto fragment specyfikacji Base64, który omawia ich rozważania przy wyborze symboli alfabetu. Osoby, które chcą zrozumieć, w jaki sposób proces zakończył się przy wyborze znaków z semantyką adresów URL, mogą uznać wyjaśnienia za mało pouczające.
3.4 Wybór alfabetu
Różne aplikacje mają różne wymagania dotyczące znaków alfabetu. Oto kilka wymagań, które określają, którego alfabetu należy użyć:
Obsługiwane przez ludzi. Znaki „0” i „O” można łatwo pomylić, podobnie jak „1”, „l” i „I”. W poniższym alfabecie base32, gdzie 0 (zero) i 1 (jeden) nie występują, dekoder może interpretować 0 jako O, a 1 jako I lub L w zależności od przypadku. (Jednak domyślnie nie powinno; patrz poprzednia sekcja.)
Zakodowane w strukturach, które wymagają innych wymagań. W przypadku podstawy 16 i podstawy 32 określa to użycie wielkich lub małych liter alfabetu. W przypadku bazy 64 znaki niealfanumeryczne (w szczególności „/”) mogą powodować problemy w nazwach plików i adresach URL.
Używany jako identyfikatory. Niektóre znaki, w szczególności „+” i „/” w alfabecie podstawowym 64, są traktowane jako podział na słowa przez starsze narzędzia wyszukiwania / indeksowania tekstu.
Nie ma powszechnie akceptowanego alfabetu, który spełnia wszystkie wymagania. Przykład wysoce wyspecjalizowanego wariantu znajduje się w IMAP [8]. W tym dokumencie dokumentujemy i wymieniamy niektóre obecnie używane alfabety.
[2.]
Alternatywnie, aby rozwiązać problem używania ciągów znaków zakodowanych w Base64 jako „takie, jakie są” składników plików lub ścieżek w systemie plików NTFS, który domyślnie nie rozróżnia wielkości liter (a zatem ryzykuje technicznie splątanie jednego lub więcej niepowiązanych wartości identyfikatora), zdarza się, że NTFS można skonfigurować z rozróżnianiem wielkości liter w ścieżce / nazwach plików dla poszczególnych woluminów. Włączenie działania innego niż domyślne może rozwiązać opisany tutaj problem, ale rzadko jest zalecane, ponieważ zmienia oczekiwania dla dowolnych / wszystkich różnych aplikacji, które sprawdzają lub uzyskują dostęp do woluminu. Jeśli nawet rozważasz tę opcję, przeczytaj ją i najpierw zrozum , a prawdopodobnie zmienisz zdanie.
[3.]
Uważam, że całkowita liczba filmów pokazanych na stronie listy odtwarzania kanału uwzględnia wykluczenie filmów, które są ograniczone zgodnie z regionem geograficznym klienta HTTP. Jest to przyczyną wszelkich rozbieżności między liczbą filmów wymienionych na liście odtwarzania a kanałem.