Les identifiants YouTube videoId et channelId sont des valeurs entières uniques représentées dans une version légèrement modifiée du codage Base64 . Une différence par rapport aux recommandations IETF RFC4648 est la substitution de deux caractères dans l'alphabet de codage:
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 substitution est probablement due au fait que, pour une raison quelconque, le RFC4648 a sélectionné deux caractères qui avaient déjà des fonctions importantes et bien établies dans les URL. [note 1.] De toute évidence, pour l'usage dont il est question ici, il est préférable d'éviter cette complication particulière.
Une autre différence par rapport aux spécifications officielles est que les identifiants YouTube n'utilisent pas le =
caractère de remplissage; ce n'est pas nécessaire parce que les longueurs codées attendues par taille entière décodée respective sont fixes et connues (11 et 22 «chiffres» codés pour 64 et 128 bits, respectivement).
À une exception près (discutée ci-dessous), tous les détails du mappage Base64 peuvent être déduits de données accessibles au public. Avec un minimum de conjectures, il est probable que le schéma Base64 utilisé dans les chaînes videoId et channelId soit le suivant:
——₀————₁————₂————₃————₄————₅————₆————₇————₈————₉———₁₀———₁₁———₁₂———₁₃———₁₄———₁₅—
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 raison de croire que Base64 est utilisée est que, lorsque nous supposons des tailles entières standard de 64 et 128 bits pour l'entrée du codeur, Base64 prédit les longueurs de caractères inhabituelles (11 et 22 caractères) des identifiants YouTube channelId et videoId exactement. De plus, les restes calculés selon Base64 expliquent parfaitement la variation de distribution observée dans les l̲a̲s̲t̲ c̲h̲a̲r̲a̲c̲t̲e̲r̲ de chaque type de chaîne d'identifiant. La discussion de ces points suit.
Dans les deux cas, les "données" binaires qui sont encodées en Base64 sont un entier unique, soit 64 ou 128 bits, pour (respectivement) videoId contre channelId . Par conséquent, en utilisant un décodeur Base64, un seul entier peut être récupéré à partir de l'identificateur de chaîne, et il peut être très utile de le faire car, tandis que chaque identifiant entier contient exactement les mêmes informations que la chaîne Base64 - et permet également à la chaîne de être recréé à tout moment: par rapport aux chaînes Base64 stockées en Unicode, la représentation binaire est 63% plus petite, a la densité de bits maximale de 100%, s'aligne mieux en mémoire, trie et hache plus rapidement et, peut-être le plus important, élimine fausses collisions entre identifiants qui ne diffèrent que dans le cas orthographique. Ce dernier problème, bien qu'extrêmement improbable numériquement, ne peut néanmoins pas être exclu lorsque les ID Base64 sont traités comme insensibles à la casse, comme le font certains systèmes de fichiers (par exemple Windows , remontant à DOS ).
C'est un peu important: si vous utilisez une chaîne videoId / channelId dans le cadre d'un nom de fichier Windows / NTFS, il y a une minuscule disparition - mais néanmoins non nulle - la possibilité de collisions de noms de fichiers en raison de ces systèmes de fichiers qui déploient un chemin insensible à la casse et un nom de fichier .
Si vous êtes préoccupé par ce problème possible à distance, une façon de l'éliminer mathématiquement serait de ré-encoder les entiers décodés - toujours obtenus comme décrit dans cet article - en base-10 (décimal) ou (uniforme- casé) représentation hexadécimale, à utiliser dans les noms de chemin ou de fichier sur ces systèmes de fichiers. [note 2.] Dans cette approche, le videoId 64 bits aurait besoin de 20 chiffres décimaux [0-9]
ou 8 chiffres hexadécimaux [0-9,A-F]
( contre 11 chiffres Base64). Le channelId de 128 bits nécessiterait un maximum de 39 chiffres décimaux ou 16 chiffres hexadécimaux ( contre 22 chiffres Base64).
Le décodage en binaire est trivial pour le cas 64 bits car vous pouvez utiliser un UInt64
( ulong
en C # ) pour contenir la valeur binaire native qui revient.
/// <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 = { "", "==", "=" };
Pour le cas des valeurs 128 bits , c'est un peu plus compliqué car, à moins que votre compilateur n'ait une __int128
représentation, vous devrez trouver un moyen de stocker le tout et de le garder combobulé lorsque vous le passerez. Un type de valeur simple (ou System.Numerics.Vectors.Vector<T>
, qui se manifeste sous la forme d'un registre matériel SIMD 128 bits, lorsqu'il est disponible) fera l'affaire dans .NET (non illustré).
[ edit: ]
Après mûre réflexion, une partie de mon message d'origine n'était pas complète au maximum. Par souci d'équité, l'extrait d'origine est conservé (vous pouvez le sauter si vous le souhaitez); juste en dessous, j'explique la perspicacité manquante:
[ original: ]
Vous avez peut-être remarqué ci-dessus que j'ai écrit que vous pouvez récupérer " un " entier. Ne serait-ce pas la valeur qui a été encodée à l'origine? Pas nécessairement. Et je ne fais pas allusion à la distinction signée / non signée qui, il est vrai, ne peut pas être vérifiée ici (car elle ne change aucun fait sur l'image binaire). Ce sont les valeurs numériques elles-mêmes: sans certains " Pierre de Rosette"cela nous permettrait de recouper avec des valeurs absolues connues pour être" correctes ", le mappage de l'alphabet numérique et l'endian-ness ne peuvent pas être connus positivement, ce qui signifie qu'il n'y a aucune garantie que vous récupérez la même valeur que Heureusement, tant que YouTube n'expose pas publiquement les valeurs dites correctes dans un format moins opaque ailleurs, cela ne peut pas avoir d'importance.
En effet, les valeurs décodées 64 ou 128 bits n'ont de toute façon aucune utilité, sauf en tant que jeton d'identification, de sorte que nos seules exigences pour la transformation sont un codage distinct (aucun deux jetons uniques n'entrent en collision) et la réversibilité (le décodage récupère l'identité du jeton d'origine).
En d'autres termes, tout ce qui nous tient vraiment à cœur, c'est le déclenchement sans perte de la chaîne Base64 d'origine. Étant donné que Base64 est sans perte et réversible (tant que vous respectez toujours le même mappage alphabétique et la même hypothèse d' endianité pour le codage et le décodage), il répond à nos objectifs. Vos valeurs numériques peuvent ne pas correspondre à celles enregistrées dans le coffre-fort principal de YouTube, mais vous ne pourrez pas faire de différence.
[ nouvelle analyse: ]
Il s'avère qu'il existe quelques indices qui peuvent nous renseigner sur le "vrai" mappage Base64 . Seuls certains mappages prédisent les caractères de position finale que nous observons, ce qui signifie que la valeur binaire pour ces caractères uniquement doit avoir un certain nombre de zéros LSB. Il h.
Pris ensemble avec l'hypothèse extrêmement probable que les caractères de l'alphabet et du chiffre sont mappés dans l'ordre croissant, nous pouvons essentiellement confirmer que le mappage est ce qui est indiqué dans les tableaux ci-dessus. La seule incertitude restante sur laquelle l'analyse LSB n'est pas concluante est le possible échange des caractères -
et _
( 62
/ 63
).
Le texte original a discuter question LSB (voir plus loin), mais ce que je ne réalise pas pleinement à l'époque était la façon dont l' information agit pour LSB limiter les possibles base64 correspondances.
Un dernier commentaire à ce sujet est que vous pourriez en fait vouloir choisir intentionnellement big-endian pour l'interprétation binaire avec laquelle votre application fonctionne en interne (même si c'est moins courant que little-endian de nos jours et que ce n'est peut-être pas ainsi que YouTube le fait officiellement) il). La raison en est qu'il s'agit d'un double affichage sur la même valeur, de sorte que l'ordre d'octets réel est visiblement exposé dans le rendu Base64. Il est utile et moins déroutant de garder l' ordre de tri cohérent entre la valeur binaire et la chaîne Base64 (un peu plus) lisible par l'homme, mais le type des valeurs binaires little-endian est un brouillage non trivial du tri ASCII / lexical souhaité .
Il n'y a pas de solution simple à ce problème si vous commencez avec des valeurs d'ID petit-endian (c'est-à-dire que simplement inverser leur tri ne fonctionnera pas). Au lieu de cela, vous devez planifier à l'avance et inverser les octets de chaque valeur binaire au moment du décodage . Donc, si vous vous souciez de l'affichage alphabétique correspondant au tri des valeurs binaires, vous voudrez peut-être modifier la fonction indiquée ci-dessus pour qu'elle se décode en valeurs big-endian à la ulong
place. Voici ce code:
// 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);
}
Identifiants YouTube
Identifiant vidéo
Pour le videoId , il s'agit d'un entier de 8 octets (64 bits). L'application du codage Base64 à 8 octets de données nécessite 11 caractères . Cependant, puisque chaque caractère Base64 transmet exactement 6 bits (à savoir, 2⁶ est égal à 64), cette allocation pourrait en fait contenir jusqu'à 11 × 6 = 66
bits - un surplus de 2 bits sur les 64 bits dont notre charge utile a besoin. Les bits en excès sont mis à zéro, ce qui a pour effet d'empêcher certains caractères d'apparaître à la dernière position de la chaîne codée. En particulier, le videoId est garanti de toujours se terminer par l'un des caractères suivants:
{ A, E, I, M, Q, U, Y, c, g, k, o, s, w, 0, 4, 8 }
Ainsi, l'expression régulière à contrainte maximale (RegEx) pour le videoId serait la suivante:
[0-9A-Za-z_-]{10}[048AEIMQUYcgkosw]
Identifiant de chaîne ou de liste de lecture
Les chaînes channelId et playlistId sont produites en codant en Base64 un entier binaire de 128 bits (16 octets). Cela donne une chaîne de 22 caractères qui peut être préfixée soit UC
pour identifier la chaîne elle-même, soit UU
pour identifier une liste de lecture complète des vidéos qu'elle contient. Ces chaînes préfixées de 24 caractères sont utilisées dans les URL . Par exemple, ce qui suit montre deux façons de faire référence au même canal. Notez que la version de la liste de lecture affiche le nombre total de vidéos dans la chaîne, [voir note 3.] une information utile que les pages de la chaîne ne dévoilent pas.
URL de la chaînehttps://www.youtube.com/channel/UC K8sQmJBp8GCxrOtXWBpyEA
URL de la playlisthttps://www.youtube.com/playlist?list=UU K8sQmJBp8GCxrOtXWBpyEA
Comme pour le videoId à 11 caractères , le calcul par Base64 prédit correctement la longueur de chaîne observée de 22 caractères . Dans ce cas, la sortie est capable de coder des 22 × 6 = 132
bits, un surplus de 4 bits; ces zéros finissent par empêcher la m̲o̲s̲t̲ des 64 symboles de l'alphabet d'apparaître en dernière position, avec seulement 4 éligibles restants. Nous savons donc que le dernier caractère d'une chaîne YouTube channelId doit être l'un des suivants:
{ A, Q, g, w }
Cela nous donne l'expression régulière contrainte au maximum pour un channelId :
[0-9A-Za-z_-]{21}[AQgw]
En guise de note finale, les expressions régulières indiquées ci-dessus décrivent uniquement les valeurs d'ID nues, sans les préfixes, les barres obliques, les séparateurs, etc., qui doivent être présentes dans les URL et les autres utilisations diverses. Les modèles RegEx que j'ai présentés sont aussi mathématiquement minimaux que possible étant donné les propriétés des chaînes d'identifiants, mais s'ils sont utilisés tels quels sans contexte supplémentaire, ils généreront probablement beaucoup de faux positifs, c'est-à-dire qu'ils correspondent incorrectement au texte parasite. Pour éviter ce problème lors de l'utilisation réelle, entourez-les autant que possible du contexte adjacent attendu.
Notes
[1.]
Comme promis ci-dessus, voici un extrait de la spécification Base64 qui discute de leurs considérations dans la sélection des symboles de l'alphabet. Les personnes cherchant à comprendre comment le processus s'est terminé dans la sélection des caractères avec la sémantique des URL peuvent trouver les explications quelque peu non édifiantes.
3.4. Choisir l'alphabet
Différentes applications ont des exigences différentes sur les caractères de l'alphabet. Voici quelques exigences qui déterminent quel alphabet doit être utilisé:
Géré par les humains. Les caractères "0" et "O" sont facilement confondus, tout comme "1", "l" et "I". Dans l'alphabet base32 ci-dessous, où 0 (zéro) et 1 (un) ne sont pas présents, un décodeur peut interpréter 0 comme O et 1 comme I ou L selon le cas. (Cependant, par défaut, cela ne devrait pas; voir la section précédente.)
Encodé dans des structures qui imposent d'autres exigences. Pour la base 16 et la base 32, cela détermine l'utilisation des alphabets majuscules ou minuscules. Pour la base 64, les caractères non alphanumériques (en particulier, "/") peuvent être problématiques dans les noms de fichiers et les URL.
Utilisé comme identifiant. Certains caractères, notamment "+" et "/" dans l'alphabet de base 64, sont traités comme des sauts de mots par les outils de recherche / index de texte hérités.
Il n'y a pas d'alphabet universellement accepté qui réponde à toutes les exigences. Pour un exemple d'une variante hautement spécialisée, voir IMAP [8]. Dans ce document, nous documentons et nommons certains alphabets actuellement utilisés.
[2.]
Alternativement, pour résoudre le problème de l'utilisation de chaînes d'ID codées en Base64 en tant que composants "tels quels" des noms de fichier ou de chemin sur le système de fichiers NTFS, qui est insensible à la casse par défaut (et donc risque techniquement de confondre une ou plusieurs valeurs ID non liées), il se trouve que NTFS peut être configuré avec un nom de chemin / fichier sensible à la casse sur une base par volume. L'activation du comportement non par défaut peut résoudre le problème décrit ici, mais est rarement recommandée car elle modifie les attentes pour toutes / toutes les applications disparates qui inspectent ou accèdent au volume. Si vous envisagez même cette option, lisez-la et comprenez-la d' abord, et vous changerez probablement d'avis.
[3.]
Je crois que le nombre total de vidéos affichées sur la page de liste de lecture de la chaîne prend en compte une exclusion pour les vidéos qui sont limitées en fonction de la région géographique du client HTTP. Cela explique toute différence entre le nombre de vidéos répertoriées pour la playlist par rapport à la chaîne.