Gli identificatori YouTube videoId e channelId sono valori interi singoli rappresentati in una versione leggermente modificata della codifica Base64 . Una differenza rispetto alle raccomandazioni IETF RFC4648 è la sostituzione di due caratteri nell'alfabeto di codifica:
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 sostituzione è probabilmente dovuta al fatto che, per qualche motivo, RFC4648 ha selezionato due caratteri che avevano già funzioni prominenti e ben definite negli URL. [nota 1.] Ovviamente, per l'uso in discussione qui, quella particolare complicazione è stata meglio evitata.
Un'altra differenza rispetto alle specifiche ufficiali è che gli identificatori di YouTube non usano il =
carattere di riempimento; non è necessario perché le lunghezze codificate previste per le rispettive dimensioni intere decodificate sono fisse e note (rispettivamente 11 e 22 "cifre" codificate per 64 e 128 bit).
Con un'eccezione minore (discussa di seguito), i dettagli completi della mappatura Base64 possono essere dedotti da dati accessibili al pubblico. Con un minimo di congetture, è probabile che lo schema Base64 utilizzato nelle stringhe videoId e channelId sia il seguente:
——₀————₁————₂————₃————₄————₅————₆————₇————₈————₉———₁₀———₁₁———₁₂———₁₃———₁₄———₁₅—
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 - _
Il motivo per credere che Base64 sia utilizzato è che, quando assumiamo dimensioni intere standard di 64 e 128 bit per l'ingresso dell'encoder, Base64 prevede esattamente le lunghezze insolite dei caratteri (11 e 22 caratteri) degli identificatori ID e videoId di YouTube . Inoltre, i resti calcolati secondo Base64 spiegano perfettamente la variazione distributiva osservata trovata nel l̲a̲s̲t̲ c̲h̲a̲r̲a̲c̲t̲e̲r̲ di ciascun tipo di stringa identificativa. Segue la discussione di questi punti.
In entrambi i casi, i "dati" binari che vengono codificati in Base64 sono un singolo intero, 64 o 128 bit, per (rispettivamente) videoId vs. channelId . Di conseguenza, usando un decodificatore Base64, un singolo intero può essere recuperato dall'identificatore di stringa e può essere molto utile farlo perché, mentre ogni ID intero contiene esattamente le stesse informazioni della stringa Base64 e consente anche alla stringa di ricreabile in qualsiasi momento: rispetto alle stringhe Base64 memorizzate come Unicode, la rappresentazione binaria è più piccola del 63%, ha la massima densità di bit del 100%, si allinea meglio nella memoria, ordina e hash più velocemente e, forse soprattutto, elimina false collisioni tra identificatori che differiscono solo nel caso ortografico. Quest'ultimo problema, sebbene estremamente improbabile numericamente, non può tuttavia essere escluso quando gli ID Base64 sono considerati insensibili al maiuscolo / minuscolo, come fanno alcuni file system (ad esempio Windows , risalenti a DOS ).
È un po 'importante: se stai usando una stringa videoId / channelId come parte di un nome di file Windows / NTFS, c'è una minuscola minuscola - ma comunque diversa da zero - la possibilità di collisioni di nomi di file dovute a quei filesystem che distribuiscono percorsi e nomi dei file senza distinzione tra maiuscole e minuscole .
Se sei preoccupato per questo possibile problema remoto, un modo per eliminarlo matematicamente sarebbe ricodificare gli interi decodificati - ancora ottenuti come descritto in questo articolo - in base-10 (decimale) o (uniforme- cased) rappresentazione esadecimale, per l'uso in percorsi o nomi di file su tali filesystem. [nota 2.] In questo approccio, l' Id video a 64 bit avrebbe bisogno di 20 cifre decimali [0-9]
o 8 cifre esadecimali [0-9,A-F]
( rispetto a 11 cifre Base64). L' ID canale a 128 bit richiederebbe un massimo di 39 cifre decimali o 16 cifre esadecimali ( rispetto a 22 cifre Base64).
La decodifica in binario è banale per il caso a 64 bit perché è possibile utilizzare un UInt64
( ulong
in C # ) per contenere il valore binario nativo che ritorna.
/// <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 = { "", "==", "=" };
Nel caso dei valori a 128 bit , è leggermente più complicato perché, a meno che il compilatore non abbia una __int128
rappresentazione, dovrai trovare un modo per archiviare tutto e mantenerlo combinato mentre lo fai passare. Un tipo di valore semplice (o System.Numerics.Vectors.Vector<T>
, che si manifesta come un registro hardware SIMD a 128 bit, quando disponibile) farà il trucco in .NET (non mostrato).
[ modifica: ]
Dopo ulteriori riflessioni, una parte del mio post originale non è stata completata al massimo. Per correttezza, viene mantenuto il brano originale (è possibile saltarlo se lo si desidera); immediatamente sotto spiego l'intuizione mancante:
[ original: ]
Avrai notato in precedenza che ho scritto che puoi recuperare un "intero". Non sarebbe questo il valore originariamente codificato? Non necessariamente. E non sto alludendo alla distinzione firmata / non firmata che, è vero, non può essere accertata qui (perché non cambia alcun dato sull'immagine binaria). Sono i valori numerici stessi: senza un po 'di " Rosetta Stone"che ci permetterebbe di fare un controllo incrociato con valori assoluti noti come" corretti ", la mappatura alfabetica numerica e anche l'endianità non possono essere conosciute positivamente, il che significa che non c'è garanzia che tu stia recuperando lo stesso valore che codificato dai computer di YouTube. Fortunatamente, fintanto che YouTube non espone pubblicamente i cosiddetti valori corretti in un formato meno opaco da qualche altra parte, questo non può avere importanza.
Questo perché i valori decodificati a 64 o 128 bit non sono utili se non come token identificativo, quindi i nostri unici requisiti per la trasformazione sono la codifica distinta (non si scontrano due token univoci) e la reversibilità (la decodifica recupera l'identità del token originale).
In altre parole, tutto ciò che ci interessa davvero è il round-tripless lossless della stringa Base64 originale. Poiché Base64 è senza perdita di dati e reversibile (purché si attenga sempre alla stessa mappatura alfabetica e presupposto di endianness sia per la codifica che per la decodifica), soddisfa i nostri scopi. I tuoi valori numerici potrebbero non corrispondere a quelli registrati nel master vault di YouTube, ma non sarai in grado di dire alcuna differenza.
[ nuova analisi: ]
Si scopre che ci sono alcuni indizi che possono parlarci della "vera" mappatura Base64 . Solo alcune mappature prevedono i caratteri della posizione finale che osserviamo, il che significa che il valore binario solo per quei caratteri deve avere un certo numero di zeri LSB. Eh.
Considerato il presupposto estremamente probabile che i caratteri alfabetici e numerici siano mappati in ordine crescente, possiamo sostanzialmente confermare che la mappatura è quella mostrata nelle tabelle sopra. L'unica incertezza residua su cui l'analisi LSB è inconcludente è il possibile scambio dei caratteri -
e _
( 62
/ 63
).
Il testo originale ha fatto discutere di questo problema LSB (vedi più avanti), ma quello che non mi rendo perfettamente conto, al momento è stato come LSB informazioni atti a limitare le possibili Base64 mappature.
Un ultimo commento su questo è che potresti effettivamente voler intenzionalmente scegliere il big-endian per l'interpretazione binaria con cui la tua app lavora internamente (anche se è meno comune del little-endian al giorno d'oggi e quindi potrebbe non essere il modo in cui YouTube "ufficialmente" fa esso). Il motivo è che questo è un caso di doppia vista sullo stesso valore, in modo tale che l'ordine di byte effettivo sia visibilmente esposto nella rappresentazione Base64. È utile e meno confuso mantenere l' ordinamento coerente tra il valore binario e la stringa Base64 (un po 'più) leggibile dall'uomo, ma il tipo di valori binari little-endian è una confusione non banale dell'ordinamento ASCII / lessicale desiderato .
Non esiste una soluzione semplice per questo problema se inizi con valori ID little-endian (vale a dire che semplicemente invertire il loro ordinamento non funzionerà). Invece, devi pianificare in anticipo e invertire i byte di ciascun valore binario al momento della decodifica . Quindi, se ti preoccupi della visualizzazione alfabetica corrispondente all'ordinamento dei valori binari, potresti voler modificare la funzione mostrata sopra in modo che decodifichi in valori big-endian ulong
. Ecco quel codice:
// 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 YouTube
ID video
Per il videoId , è un numero intero a 8 byte (64 bit). L'applicazione della codifica Base64 a 8 byte di dati richiede 11 caratteri . Tuttavia, poiché ogni carattere Base64 trasmette esattamente 6 bit (vale a dire, 2⁶ equivale a 64), questa allocazione potrebbe effettivamente contenere fino a 11 × 6 = 66
bit, un surplus di 2 bit rispetto ai 64 bit necessari per il nostro payload. I bit in eccesso sono impostati su zero, il che ha l'effetto di escludere alcuni caratteri dall'apparire mai nell'ultima posizione della stringa codificata. In particolare, il videoId è garantito per finire sempre con uno dei seguenti caratteri:
{ A, E, I, M, Q, U, Y, c, g, k, o, s, w, 0, 4, 8 }
Pertanto, l'espressione regolare con il limite massimo (RegEx) per il videoId sarebbe la seguente:
[0-9A-Za-z_-]{10}[048AEIMQUYcgkosw]
ID canale o playlist
Le stringhe channelId e playlistId sono prodotte dalla codifica Base64 di un intero binario a 128 bit (16 byte). Ciò fornisce una stringa di 22 caratteri che può essere preceduta o UC
per identificare il canale stesso o UU
per identificare una playlist completa dei video che contiene. Queste stringhe con prefisso di 24 caratteri vengono utilizzate negli URL . Ad esempio, quanto segue mostra due modi per fare riferimento allo stesso canale. Si noti che la versione della playlist mostra il numero totale di video nel canale, [vedi nota 3.] un'informazione utile che le pagine del canale non espongono.
URL del canalehttps://www.youtube.com/channel/UC K8sQmJBp8GCxrOtXWBpyEA
URL playlisthttps://www.youtube.com/playlist?list=UU K8sQmJBp8GCxrOtXWBpyEA
Come nel caso dell'Id video a 11 caratteri , il calcolo per Base64 prevede correttamente la lunghezza della stringa osservata di 22 caratteri . In questo caso, l'output è in grado di codificare 22 × 6 = 132
bit, un surplus di 4 bit; quegli zeri finiscono per limitare la visualizzazione di m̲o̲s̲t̲ dei 64 simboli alfabetici nell'ultima posizione, con solo 4 rimanenti idonei. Pertanto, sappiamo che l'ultimo carattere in una stringa ID canale YouTube deve essere uno dei seguenti:
{ A, Q, g, w }
Questo ci dà l'espressione regolare strettamente vincolata per un channelId :
[0-9A-Za-z_-]{21}[AQgw]
Come nota finale, le espressioni regolari mostrate sopra descrivono solo i valori di ID nudo, senza prefissi, barre, separatori, ecc., Che devono essere presenti negli URL e negli altri vari usi. I pattern RegEx che ho presentato sono matematicamente il più minimali possibile date le proprietà delle stringhe degli identificatori, ma se usati così come sono senza contesto aggiuntivo probabilmente genereranno molti falsi positivi, cioè: abbinano erroneamente il testo spurio. Per evitare questo problema nell'uso effettivo, circondali con il maggior numero possibile di contesti adiacenti previsti.
Note
[1.]
Come promesso sopra, ecco un estratto dalla specifica Base64 che discute le loro considerazioni nella selezione dei simboli alfabetici. Le persone che cercano di capire come il processo si è concluso nella selezione dei caratteri con la semantica dell'URL possono trovare le spiegazioni in qualche modo non edificanti.
3.4. La scelta dell'alfabeto
Applicazioni diverse hanno requisiti diversi sui caratteri dell'alfabeto. Ecco alcuni requisiti che determinano quale alfabeto deve essere usato:
Gestito dagli umani. I caratteri "0" e "O" sono facilmente confusi, così come "1", "l" e "I". Nell'alfabeto base32 di seguito, dove 0 (zero) e 1 (uno) non sono presenti, un decodificatore può interpretare 0 come O e 1 come I o L a seconda del caso. (Tuttavia, per impostazione predefinita non dovrebbe; vedere la sezione precedente.)
Codificato in strutture che impongono altri requisiti. Per la base 16 e la base 32, questo determina l'uso di alfabeti maiuscoli o minuscoli. Per la base 64, i caratteri non alfanumerici (in particolare "/") possono essere problematici nei nomi di file e negli URL.
Utilizzato come identificatore. Alcuni caratteri, in particolare "+" e "/" nell'alfabeto base 64, sono trattati come interruzioni di parole dagli strumenti di ricerca / indice del testo legacy.
Non esiste un alfabeto universalmente accettato che soddisfi tutti i requisiti. Per un esempio di variante altamente specializzata, vedi IMAP [8]. In questo documento, documentiamo e denominiamo alcuni alfabeti attualmente utilizzati.
[2.]
In alternativa, per risolvere il problema dell'uso di stringhe di ID con codifica Base64 come componenti "così come sono" di nomi di file o percorsi sul filesystem NTFS, che non distingue tra maiuscole e minuscole per impostazione predefinita (e quindi tecnicamente rischia di confondere uno o più valori ID non correlati), è possibile che NTFS possa essere configurato con nomi di file / percorsi con distinzione tra maiuscole e minuscole in base al volume. L'abilitazione del comportamento non predefinito può risolvere il problema qui descritto, ma raramente è raccomandato poiché altera le aspettative per qualsiasi / tutte le diverse applicazioni che ispezionano o accedono al volume. Se stai anche considerando questa opzione, leggi e capisci prima questo , e probabilmente cambierai idea.
[3.]
Credo che il numero totale di video mostrati nella pagina della playlist del canale tenga conto di un'esclusione per i video che sono limitati in base alla regione geografica del client HTTP. Ciò spiega eventuali discrepanze tra il numero di video elencati per la playlist e il canale.