YouTube- ідентифікатори videoId та channelId - це єдині цілі значення, представлені у дещо зміненій версії кодування Base64 . Одна відмінність від рекомендацій IETF RFC4648 - це заміна двох символів в алфавіті кодування:
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)
Заміна, ймовірно, пов'язана з тим, що з якоїсь причини RFC4648 вибрав два символи, які вже мали чіткі та добре налагоджені функції в URL-адресах. [Примітка 1.] Очевидно, що для використання тут, про яке йде мова, найкраще уникати конкретного ускладнення.
Ще одна відмінність від офіційної специфікації полягає в тому, що ідентифікатори YouTube не використовують =
символ прокладки; це не обов'язково, оскільки кодовані довжини, що очікуються на відповідний розшифрований цілий розмір, є фіксованими та відомими (11 та 22 закодовані 'цифри' для 64 та 128 біт відповідно).
За одним незначним винятком (обговорюється нижче), повні деталі відображення Base64 можна отримати з загальнодоступних даних. З мінімумом здогадок, ймовірно, що схема Base64 , що використовується у рядках videoId та channelId, є наступною:
——₀————₁————₂————₃————₄————₅————₆————₇————₈————₉———₁₀———₁₁———₁₂———₁₃———₁₄———₁₅—
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 - _
Причина вважати, що Base64 використовується в тому, що, коли ми приймаємо стандартні цілі розміри 64 та 128 біт для введення кодера, Base64 точно прогнозує незвичайні довжини символів (11 та 22 символи) для YouTube- ідентифікаторів YouTubeId та videoId . Крім того, залишки, розраховані за Base64, прекрасно пояснюють спостережувані зміни розподілу, знайдені в l̲a̲s̲t̲ c̲h̲a̲r̲a̲c̲t̲e̲r̲ кожного типу ідентифікаційного рядка. Далі йде обговорення цих питань.
В обох випадках двійкові «дані», які отримують кодовані Base64, є єдиним цілим числом, або 64, або 128 бітами, для (відповідно) videoId проти channelId . Відповідно, за допомогою декодера Base64, одне ціле число може бути відновлено з ідентифікатора рядка, і це може бути досить корисно, оскільки, хоча кожен цілий ідентифікатор містить точно таку ж інформацію, як і рядок Base64, а також дозволяє рядку відтворювати в будь-який час - у порівнянні з рядками Base64, що зберігаються як Unicode, бінарне представлення на 63% менше, має максимальну щільність бітів 100%, краще вирівнює пам’ять, сортує та зберігає швидше, і, що, головне, усуває помилкові зіткнення між ідентифікаторами, які відрізняються лише в ортографічному випадку. Ця остання проблема, хоча чисельно вкрай неможлива, проте не може бути виключена, коли ідентифікатори Base64 трактуються як нечутливі до регістру, як це роблять деякі файлові системи (наприклад, Windows , починаючи з DOS ).
Це якось важливо: якщо ви використовуєте рядок videoId / channelId як частину імені файлів Windows / NTFS, існує суттєва мінливість, але, тим не менш, нульова - зміна зіткнень імен файлів завдяки тим файловим системам, що розгортають шлях, нечутливий до регістру і іменування файлів. .
Якщо ви турбуєтесь про цю віддалену можливу проблему, одним із способів математичного усунення було б перекодування декодованих цілих чисел - як і раніше отриманих, як описано в цій статті - або в базову-10 (десяткову), або (рівномірну- cased) шістнадцяткове представлення, для використання у назвах шляхів або файлів у таких файлових системах. [Примітка 2.] У такому підході 64-розрядному videoId потрібно 20 знаків після коми [0-9]
або 8 шістнадцяткових цифр [0-9,A-F]
( проти 11 цифр Base64). Для 128-розрядного каналу IDI потрібно максимум 39 десяткових чи 16-ти шістнадцяткових цифр ( проти 22-х цифр Base64).
Розшифровка до двійкового файлу є тривіальною для 64-розрядного випадку, оскільки ви можете використовувати UInt64
( ulong
у C # ) для утримання нативного бінарного значення, яке повертається.
/// <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 = { "", "==", "=" };
Що стосується 128-бітових значень, це трохи складніше, оскільки, якщо ваш компілятор не має __int128
представлення, вам доведеться розібратися в способі зберігання всієї речі і тримати її у комбінованому вигляді, коли ви передаєте її навколо. Простий тип значення (або System.Numerics.Vectors.Vector<T>
, який проявляється як 128-розрядний реєстр апаратних засобів SIMD, коли він доступний), зробить трюк у .NET (не показано).
[ ред .: ]
Після подальшої думки частина моєї оригінальної публікації була не максимально повною. Для справедливості зберігається оригінальний уривок (ви можете пропустити його за бажанням); одразу нижче я пояснюю пропущене розуміння:
[ Оригінал: ]
Ви , можливо, помітили вище , що я написав , що ви можете відновити « в » загалом. Чи не це було б значення, яке було спочатку закодовано? Не обов'язково. І я не натякаю на підписане / непідписане розрізнення, яке, правда, тут неможливо встановити (оскільки це не змінює жодних фактів про двійкове зображення). Це самі числові значення: Без якогось " Розетт-каменю""це дозволило б перехресно перевірити абсолютні значення, відомі як" правильні ", чисельне відображення алфавіту, а також ендіанство не може бути позитивно відомим, це означає, що немає гарантії, що ви відновите те саме значення, яке на щастя, доки YouTube ніколи не публічно не виставляє так званих правильних значень у менш непрозорому форматі десь в іншому місці, це, можливо, не має значення.
Це тому, що декодовані 64- або 128-бітні значення в будь-якому разі не використовуються, окрім як маркер ідентифікації, тому єдиними нашими вимогами до перетворення є чітке кодування (не стикаються два унікальних лексеми) та оборотність (декодування відновлює оригінальну тотожність токена).
Іншими словами, все, що нас насправді хвилює, - це збиток без втрат оригінального рядка Base64. Оскільки Base64 без втрат і оборотності (якщо ви завжди дотримуєтесь одного і того ж відображення алфавіту та припущення про витривалість як для кодування, так і для декодування), це відповідає нашим цілям. Ваші числові значення можуть не збігатися з тими, які записані в основній сховищі YouTube, але ви не зможете визначити різницю.
[ новий аналіз: ]
Виявляється, є кілька підказок, які можуть розповісти нам про "справжнє" відображення Base64 . Лише певні відображення передбачають символи кінцевої позиції, які ми спостерігаємо, тобто бінарне значення лише для цих символів повинно мати певну кількість нулів LSB. Хе.
У сукупності з надзвичайно ймовірним припущенням, що алфавіт і цифри символи відображаються у порядку зростання, ми можемо в основному підтвердити відображення таким, як показано в таблицях вище. Єдина невизначеність, щодо якої LSB-аналіз не є переконливою, - це можливий підміна символів -
та _
( 62
/ 63
).
Оригінальний текст зробив обговорити це питання LSB (див нижче), але то , що я не в повній мірі реалізувати в той час було як LSB інформація діє , щоб обмежити можливе Base64 відображення.
Останній коментар з цього приводу полягає в тому, що ви насправді можете навмисно вибрати big-endian для бінарної інтерпретації, з якою працює ваш додаток всередині (хоча це є менш поширеним, ніж сьогодні мало-ендіанський, і, таким чином, може бути не так, як YouTube "офіційно" робить це). Причина полягає в тому, що це випадок подвійних поглядів на одне і те ж значення, таким чином, що фактичний порядок байт помітно піддається викладу Base64. Це корисно і менш заплутано для того, щоб дотримуватися порядку сортування між бінарним значенням та (дещо більше) читаною людиною рядком Base64, але такий тип бінарних значень маленького ендіану - це нетривіальна кодифікація потрібного ASCII / лексичного сорту .
Виправити цю проблему не існує простого виправлення, якщо ви почнете зі значень ідентифікаторів малої кількості (тобто просто змінити їх вид не буде працювати). Натомість вам потрібно планувати заздалегідь і повертати байти кожного бінарного значення під час декодування . Тож якщо ви дбаєте про те, щоб алфавітний дисплей відповідав сортуванням двійкових значень, ви можете змінити функцію, показану вище, щоб вона замість цього була розшифрована у великі-ендіанські ulong
значення. Ось цей код:
// 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);
}
Ідентифікатори YouTube
Ідентифікатор відео
Для videoId це 8-байтове (64-бітове) ціле число. Застосування кодування Base64 до 8 байт даних вимагає 11 символів . Однак, оскільки кожен символ Base64 передає рівно 6 біт (а саме 2⁶ дорівнює 64), це розподіл може насправді містити до 11 × 6 = 66
бітів - надлишок у 2 біти над 64 бітами, що потребує нашого корисного навантаження. Зайві біти встановлені в нуль, що призводить до того, що певні символи ніколи не з'являться в останньому положенні закодованого рядка. Зокрема, відеоідентифікатор гарантовано завжди закінчується одним із наступних символів:
{ A, E, I, M, Q, U, Y, c, g, k, o, s, w, 0, 4, 8 }
Таким чином, максимально обмежений регулярний вираз (RegEx) для videoId буде таким:
[0-9A-Za-z_-]{10}[048AEIMQUYcgkosw]
Ідентифікатор каналу чи списку відтворення
Рядок ChannelId та playlistId виробляються Base64-кодуванням 128-бітового (16-байтового) двійкового цілого числа. Це дає 22-символьний рядок, який можна встановити як UC
для ідентифікації самого каналу, так і UU
для ідентифікації повного списку відтворення відео, який він містить. Ці строчки з 24 символами використовуються в URL-адресах . Наприклад, нижче показано два способи посилання на один і той же канал. Зауважте, що версія списку відтворення показує загальну кількість відео на каналі [див. Примітку 3.] корисну інформацію, яку сторінки каналу не відкривають.
URL-адреса каналуhttps://www.youtube.com/channel/UC K8sQmJBp8GCxrOtXWBpyEA
URL-адреса списку відтворенняhttps://www.youtube.com/playlist?list=UU K8sQmJBp8GCxrOtXWBpyEA
Як і у випадку з 11-символьним videoId , обчислення на Base64 правильно прогнозує спостережувану довжину рядка в 22 символи . У цьому випадку вихід здатний кодувати 22 × 6 = 132
біти, надлишок 4 біт; ці нулі в кінцевому підсумку обмежують показ m̲o̲s̲t̲ з 64 символів алфавіту в останньому місці, при цьому залишаються лише 4. Тому ми знаємо, що останній символ у рядку каналуId YouTube повинен бути одним із наступних:
{ A, Q, g, w }
Це дає нам максимально обмежений регулярний вираз для channelId :
[0-9A-Za-z_-]{21}[AQgw]
На завершення, регулярні вирази, показані вище, описують лише голові значення ідентифікатора, без префіксів, косої риси, роздільника тощо, які повинні бути присутніми в URL-адресах та інших різних цілях. Представлені мною шаблони RegEx є максимально математично з урахуванням властивостей рядків ідентифікатора, але якщо вони використовуються як-є без додаткового контексту, вони, ймовірно, генерують багато помилкових позитивних результатів, тобто: неправильно збігаються на помилковий текст. Щоб уникнути цієї проблеми в реальному використанні, оточіть їх якомога більшою кількістю очікуваного суміжного контексту.
Примітки
[1.]
Як було обіцяно вище, ось уривок із специфікації Base64, який обговорює їх міркування щодо вибору символів алфавіту. Особи, які прагнуть зрозуміти, як процес, який завершився підбором символів із семантикою URL, може вважати пояснення дещо неоднозначними.
3.4. Вибір алфавіту
У різних програмах різні вимоги до символів в алфавіті. Ось кілька вимог, які визначають, який алфавіт слід використовувати:
Обробляються людиною. Символи "0" і "O" легко плутати, як і "1", "l" і "I". У алфавіті base32 нижче, де 0 (нуль) та 1 (один) немає, декодер може інтерпретувати 0 як O, а 1 як I або L залежно від випадку. (Однак за замовчуванням це не повинно; див. Попередній розділ.)
Зашифровані в структури, що передбачають інші вимоги. Для бази 16 та бази 32 це визначає використання алфавітів верхнього або нижнього регістру. Для бази 64 нелітерно-цифрові символи (зокрема, "/") можуть бути проблематичними у назвах файлів та URL-адресах.
Використовується як ідентифікатори. Деякі символи, зокрема "+" та "/" в алфавіті базової 64, розглядаються як розриви слів за допомогою застарілих інструментів пошуку тексту / покажчика тексту.
Не існує загальновизнаного алфавіту, який би відповідав усім вимогам. Для прикладу вузькоспеціалізованого варіанту див. IMAP [8]. У цьому документі ми документуємо та називаємо деякі використовувані в даний час алфавіти.
[2.]
Крім того, вирішити проблему використання рядків ідентифікованих ідентифікаторами Base64 як "як є" компоненти імен файлів або шляхів у файловій системі NTFS, яка за замовчуванням нечутлива до регістру (і, таким чином, технічно ризикує збити один чи більше непов'язані значення ідентифікатора), так буває, що NTFS можна налаштувати з урахуванням регістру іменування шляху / файлу на основі томів. Увімкнення поведінки, що не використовується за замовчуванням, може виправити описану тут проблему, але її рідко рекомендується, оскільки вона змінює очікування для будь-яких / всіх розрізнених програм, які перевіряють або отримують доступ до тома. Якщо ви навіть розглядаєте цей варіант, прочитайте і зрозумійте це спочатку, і ви, мабуть, передумаєте.
[3.]
Я вважаю, що загальна кількість відео, показаних на сторінці відтворення каналу, враховує виключення для відео, які обмежені відповідно до географічного регіону клієнта HTTP. Це пояснює будь-яку невідповідність між кількістю перелічених відео для списку відтворення та каналу.