Los identificadores videoId y channelId de YouTube son valores enteros individuales representados en una versión ligeramente modificada de la codificación Base64 . Una diferencia frente a las recomendaciones IETF RFC4648 es la sustitución de dos caracteres en el alfabeto de codificación:
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)
La sustitución probablemente se deba al hecho de que, por alguna razón, RFC4648 seleccionó dos caracteres que ya tenían funciones prominentes y bien establecidas en las URL. [nota 1.] Obviamente, para el uso en discusión aquí, es mejor evitar esa complicación particular.
Otra diferencia de la especificación oficial es que los identificadores de YouTube no usan el =
carácter de relleno; no es necesario porque las longitudes codificadas esperadas por cada tamaño entero descodificado respectivo son fijas y conocidas (11 y 22 'dígitos' codificados para 64 y 128 bits, respectivamente).
Con una excepción menor (discutida más abajo), los detalles completos de la asignación de Base64 se pueden inferir de los datos de acceso público. Con un mínimo de conjeturas, es probable que el esquema Base64 utilizado en las cadenas videoId y channelId sea el siguiente:
——₀————₁————₂————₃————₄————₅————₆————₇————₈————₉———₁₀———₁₁———₁₂———₁₃———₁₄———₁₅—
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 - _
La razón para creer que se está utilizando Base64 es que, cuando asumimos tamaños enteros estándar de 64 y 128 bits para la entrada del codificador, Base64 predice las longitudes de caracteres inusuales (11 y 22 caracteres) de los identificadores channelId y videoId de YouTube exactamente. Además, los residuos calculados según Base64 explican perfectamente la variación distribucional observada que se encuentra en l̲a̲s̲t̲ c̲h̲a̲r̲a̲c̲t̲e̲r̲ de cada tipo de cadena de identificación. La discusión de estos puntos sigue.
En ambos casos, los "datos" binarios que se codifican en Base64 son un solo número entero, ya sea 64 o 128 bits, para (respectivamente) videoId versus channelId . En consecuencia, mediante el uso de un decodificador Base64, se puede recuperar un solo entero del identificador de cadena, y puede ser bastante útil hacerlo porque, mientras que cada ID de entero contiene exactamente la misma información que la cadena Base64, y también permite que la cadena volver a crearse en cualquier momento: en comparación con las cadenas Base64 almacenadas como Unicode, la representación binaria es un 63% más pequeña, tiene una densidad de bits máxima del 100%, se alinea mejor en la memoria, ordena y pica más rápido y, quizás lo más importante, elimina falsas colisiones entre identificadores que difieren solo en caso ortográfico. Este último problema, aunque extremadamente improbable numéricamente, no se puede descartar cuando las ID de Base64 se tratan como mayúsculas y minúsculas, como lo hacen algunos sistemas de archivos (por ejemplo , Windows , que se remonta a DOS ).
Eso es un poco importante: si está utilizando una cadena videoId / channelId como parte de un nombre de archivo de Windows / NTFS, existe una posibilidad minúscula, pero no distinta de cero, de colisiones de nombres de archivo debido a que los sistemas de archivos implementan una ruta sin distinción entre mayúsculas y minúsculas y nombres de archivos .
Si le preocupa este problema remotamente posible, una forma de eliminarlo matemáticamente sería volver a codificar los enteros decodificados, que todavía se obtienen como se describe en este artículo, en una base 10 (decimal) o (uniforme) representación hexadecimal, para usar en rutas o nombres de archivos en dichos sistemas de archivos. [nota 2.] En este enfoque, el videoId de 64 bits necesitaría 20 dígitos decimales [0-9]
u 8 dígitos hexadecimales [0-9,A-F]
( frente a 11 dígitos Base64). El channelId de 128 bits requeriría un máximo de 39 dígitos decimales o 16 dígitos hexadecimales ( frente a 22 dígitos Base64).
La decodificación en binario es trivial para el caso de 64 bits porque puede usar un UInt64
( ulong
en C # ) para mantener el valor binario nativo que regresa.
/// <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 = { "", "==", "=" };
Para el caso de los valores de 128 bits , es un poco más complicado porque, a menos que su compilador tenga una __int128
representación, tendrá que encontrar una manera de almacenar todo y mantenerlo combinado mientras lo pasa. Un tipo de valor simple (o System.Numerics.Vectors.Vector<T>
, que se manifiesta como un registro de hardware SIMD de 128 bits, cuando esté disponible) hará el truco en .NET (no se muestra).
[ editar: ]
Después de pensarlo más, una parte de mi publicación original no estaba completa al máximo. Para ser justos, se conserva el extracto original (puede omitirlo si lo desea); Inmediatamente a continuación explico la información faltante:
[ original: ]
Puede que hayas notado anteriormente que escribí que puedes recuperar " un " número entero. ¿No sería este el valor codificado originalmente? No necesariamente. Y no estoy aludiendo a la distinción con signo / sin signo que, es cierto, no se puede determinar aquí (porque no cambia ningún hecho sobre la imagen binaria). Son los valores numéricos mismos: sin algo de " Rosetta Stone"eso nos permitiría realizar una verificación cruzada con valores absolutos que se sabe que son" correctos ", el mapeo alfabético numérico y también la endianidad no se pueden conocer positivamente, lo que significa que no hay garantía de que esté recuperando el mismo valor que las computadoras en YouTube codificaron. Afortunadamente, mientras YouTube nunca exponga públicamente los llamados valores correctos en un formato menos opaco en otro lugar, esto no puede importar.
Esto se debe a que los valores decodificados de 64 o 128 bits no tienen uso, excepto como un token de identificación de todos modos, por lo que nuestros únicos requisitos para la transformación son la codificación distinta (no chocan dos tokens únicos) y la reversibilidad (la decodificación recupera la identidad del token original).
En otras palabras, todo lo que realmente nos importa es el disparo redondo sin pérdidas de la cadena Base64 original. Dado que Base64 no tiene pérdidas y es reversible (siempre y cuando siempre cumpla con el mismo mapeo alfabético y la suposición de endianness tanto para la codificación como para la decodificación) satisface nuestros propósitos. Es posible que sus valores numéricos no coincidan con los registrados en la bóveda maestra de YouTube, pero no podrá notar ninguna diferencia.
[ Nuevo análisis: ]
Resulta que hay son algunas pistas que pueden decirnos acerca de la "verdadera" base 64 de mapeo. Solo ciertas asignaciones predicen los caracteres de posición final que observamos, lo que significa que el valor binario de solo esos caracteres debe tener un cierto número de ceros LSB. Je
En conjunto con la suposición abrumadoramente probable de que los caracteres del alfabeto y los dígitos están mapeados en orden ascendente, básicamente podemos confirmar que el mapeo es lo que se muestra en las tablas anteriores. La única incertidumbre restante sobre la cual el análisis LSB no es concluyente es el posible intercambio de los caracteres -
y _
( 62
/ 63
).
El texto original hizo discutir este tema LSB (véase más adelante), pero lo que no me había dado cuenta plenamente en el momento era cómo LSB información actúa para restringir los posibles base 64 asignaciones.
Un último comentario sobre esto es que, de hecho, es posible que desee elegir intencionalmente big-endian para la interpretación binaria con la que trabaja internamente su aplicación (a pesar de que hoy en día es menos común que little-endian y, por lo tanto, podría no ser la forma en que YouTube 'oficialmente' lo hace eso). La razón es que este es un caso de vistas duales en el mismo valor, de modo que el orden de bytes real está visiblemente expuesto en la representación de Base64. Es útil y menos confuso mantener el orden de clasificación coherente entre el valor binario y la cadena Base64 legible por humanos (algo más), pero el tipo de valores binarios little endian es una mezcla no trivial del tipo ASCII / léxico deseado. .
No hay una solución simple para este problema si comienzas con valores de ID little-endian (es decir, simplemente revertir su clasificación no funcionará). En su lugar, debe planificar con anticipación e invertir los bytes de cada valor binario en el momento de la decodificación . Entonces, si le importa que la visualización alfabética coincida con la clasificación de los valores binarios, es posible que desee alterar la función que se muestra arriba para que decodifique en valores big-endian ulong
. Aquí está ese código:
// 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);
}
ID de YouTube
ID del video
Para el videoId , es un entero de 8 bytes (64 bits). La aplicación de codificación Base64 a 8 bytes de datos requiere 11 caracteres . Sin embargo, dado que cada carácter Base64 transmite exactamente 6 bits (es decir, 2⁶ es igual a 64), esta asignación podría contener hasta 11 × 6 = 66
bits, un excedente de 2 bits sobre los 64 bits que necesita nuestra carga útil. El exceso de bits se establece en cero, lo que tiene el efecto de excluir que ciertos caracteres aparezcan en la última posición de la cadena codificada. En particular, se garantiza que el videoId siempre terminará con uno de los siguientes caracteres:
{ A, E, I, M, Q, U, Y, c, g, k, o, s, w, 0, 4, 8 }
Por lo tanto, la expresión regular (RegEx) con restricciones máximas para el videoId sería la siguiente:
[0-9A-Za-z_-]{10}[048AEIMQUYcgkosw]
ID de canal o lista de reproducción
Las cadenas channelId y playlistId se producen codificando Base64 en un entero binario de 128 bits (16 bytes). Esto proporciona una cadena de 22 caracteres que puede tener el prefijo UC
para identificar el canal en sí o UU
para identificar una lista de reproducción completa de los videos que contiene. Estas cadenas prefijadas de 24 caracteres se usan en las URL . Por ejemplo, a continuación se muestran dos formas de referirse al mismo canal. Observe que la versión de la lista de reproducción muestra el número total de videos en el canal, [vea la nota 3.] una información útil que las páginas del canal no exponen.
URL del canalhttps://www.youtube.com/channel/UC K8sQmJBp8GCxrOtXWBpyEA
URL de lista de reproducciónhttps://www.youtube.com/playlist?list=UU K8sQmJBp8GCxrOtXWBpyEA
Como fue el caso con el videoId de 11 caracteres , el cálculo por Base64 predice correctamente la longitud de cadena observada de 22 caracteres . En este caso, la salida es capaz de codificar 22 × 6 = 132
bits, un excedente de 4 bits; esos ceros terminan restringiendo que m̲o̲s̲t̲ de los 64 símbolos del alfabeto aparezcan en la última posición, con solo 4 restantes elegibles. Por lo tanto, sabemos que el último carácter en una cadena channelId de YouTube debe ser uno de los siguientes:
{ A, Q, g, w }
Esto nos da la expresión regular con restricciones máximas para un channelId :
[0-9A-Za-z_-]{21}[AQgw]
Como nota final, las expresiones regulares que se muestran arriba describen solo los valores de ID desnudos, sin los prefijos, barras, separadores, etc., que deben estar presentes en las URL y los otros usos. Los patrones RegEx que presenté son matemáticamente mínimos, dadas las propiedades de las cadenas de identificación, pero si se usan tal cual sin contexto adicional, probablemente generarán muchos falsos positivos, es decir: coinciden incorrectamente el texto falso. Para evitar este problema en el uso real, enciérrelos con la mayor cantidad de contexto adyacente posible.
Notas
[1.]
Como se prometió anteriormente, aquí hay un extracto de la especificación Base64 que analiza sus consideraciones al seleccionar los símbolos del alfabeto. Las personas que buscan entender cómo concluyó el proceso en la selección de caracteres con semántica de URL pueden encontrar las explicaciones algo poco edificantes.
3.4. Elegir el alfabeto
Las diferentes aplicaciones tienen diferentes requisitos sobre los caracteres del alfabeto. Aquí hay algunos requisitos que determinan qué alfabeto se debe usar:
Manejado por humanos. Los caracteres "0" y "O" se confunden fácilmente, al igual que "1", "l" e "I". En el siguiente alfabeto base32, donde 0 (cero) y 1 (uno) no están presentes, un decodificador puede interpretar 0 como O y 1 como I o L, según el caso. (Sin embargo, por defecto no debería; consulte la sección anterior).
Codificado en estructuras que exigen otros requisitos. Para la base 16 y la base 32, esto determina el uso de alfabetos en mayúsculas o minúsculas. Para la base 64, los caracteres no alfanuméricos (en particular, "/") pueden ser problemáticos en los nombres de archivos y URL.
Usado como identificadores. Ciertos caracteres, especialmente "+" y "/" en el alfabeto de base 64, son tratados como saltos de palabras por las herramientas de búsqueda / índice de texto heredado.
No existe un alfabeto universalmente aceptado que cumpla con todos los requisitos. Para ver un ejemplo de una variante altamente especializada, consulte IMAP [8]. En este documento, documentamos y nombramos algunos alfabetos utilizados actualmente.
[2.]
Alternativamente, para resolver el problema del uso de cadenas de identificación codificadas en Base64 como componentes "tal cual" de los nombres de archivo o ruta en el sistema de archivos NTFS, que no distingue entre mayúsculas y minúsculas por defecto (y por lo tanto técnicamente corre el riesgo de combinar uno o más valores de ID no relacionados), sucede que NTFS se puede configurar con nombres de ruta / archivo sensibles a mayúsculas y minúsculas por volumen. Habilitar el comportamiento no predeterminado puede solucionar el problema descrito aquí, pero rara vez se recomienda, ya que altera las expectativas para cualquiera / todas las aplicaciones dispares que inspeccionan o acceden al volumen. Si incluso está considerando esta opción, lea y comprenda esto primero, y probablemente cambiará de opinión.
[3.]
Creo que el número total de videos que se muestran en la página de la lista de reproducción del canal tiene en cuenta la exclusión de videos que están restringidos de acuerdo con la región geográfica del cliente HTTP. Esto explica cualquier discrepancia entre la cantidad de videos enumerados para la lista de reproducción frente al canal.