@@ -66,6 +66,27 @@ public int getValue() {
6666 }
6767}
6868
69+ // Reference https://github.com/coletdjnz/yt-dlp-dev/blob/5c0c2963396009a92101bc6e038b61844368409d/yt_dlp/extractor/youtube/_streaming/sabr/part.py
70+ enum PoTokenStatus {
71+ UNKNOWN (-1 ),
72+ OK (1 ), // PO Token is provided and valid
73+ MISSING (3 ), // PO Token is not provided, and is required. A PO Token should be provided ASAP
74+ INVALID (3 ), // PO Token is provided, but is invalid. A new one should be generated ASAP
75+ PENDING (2 ), // PO Token is provided, but probably only a cold start token. A full PO Token should be provided ASAP
76+ NOT_REQUIRED (1 ), // PO Token is not provided, and is not required
77+ PENDING_MISSING (2 ); // PO Token is not provided, but is pending. A full PO Token should be (probably) provided ASAP
78+
79+ private final int value ;
80+
81+ PoTokenStatus (int value ) {
82+ this .value = value ;
83+ }
84+
85+ public int getValue () {
86+ return value ;
87+ }
88+ }
89+
6990public class ServerAbrStream {
7091 private final Stream stream ;
7192 private final BiConsumer <byte [], Long > writeChunk ;
@@ -82,6 +103,7 @@ public class ServerAbrStream {
82103 private final Map <String , List <Integer >> previousSequences ;
83104 private boolean RELOAD ;
84105 private int maximumReloadAttempt ;
106+ private String streamProtectionStatus = PoTokenStatus .UNKNOWN .name ();
85107 private List <Integer > sabrContextsToSend ;
86108 private HashMap <Integer , StreamerContext .StreamerContextUpdate > sabrContextUpdates ;
87109
@@ -209,7 +231,7 @@ public void start() throws Exception {
209231 RELOAD = false ;
210232 continue ;
211233 } else if (maximumReloadAttempt <= 0 ) {
212- throw new SABRError ("SABR Maximum reload attempts reached" );
234+ throw new SABRError ("SABR Maximum reload attempts reached. Stream protection status: PoToken " + streamProtectionStatus );
213235 }
214236
215237 if (mainFormat == null || ((Number ) mainFormat .get ("sequenceCount" )).intValue () == ((Number ) ((List <Map <String , Object >>) mainFormat .get ("sequenceList" )).get (((List ) mainFormat .get ("sequenceList" )).size () - 1 ).get ("sequenceNumber" )).intValue ()) {
@@ -390,7 +412,7 @@ private Map<String, Object> parseUmpResponse(byte[] response) {
390412 sabrRedirect [0 ] = processSabrRedirect (data .get (0 ));
391413
392414 } else if (partType == PART .STREAM_PROTECTION_STATUS .getValue ()) {
393- StreamProtectionStatus . decode (data .get (0 ));
415+ processStreamProtectionStatus (data .get (0 ));
394416
395417 } else if (partType == PART .RELOAD_PLAYER_RESPONSE .getValue ()) {
396418 RELOAD = true ;
@@ -520,6 +542,27 @@ private SabrRedirect processSabrRedirect(byte[] data) {
520542 return sabrRedirect ;
521543 }
522544
545+ private void processStreamProtectionStatus (byte [] data ){
546+ int protectionStatus = StreamProtectionStatus .decode (data ).status ;
547+
548+ String resultStatus ;
549+
550+ if (protectionStatus == StreamProtectionStatus .Status .OK .getValue ()){
551+ resultStatus = poToken != null ? PoTokenStatus .OK .name () : PoTokenStatus .NOT_REQUIRED .name ();
552+
553+ }else if (protectionStatus == StreamProtectionStatus .Status .ATTESTATION_PENDING .getValue ()){
554+ resultStatus = poToken != null ? PoTokenStatus .PENDING .name () : PoTokenStatus .PENDING_MISSING .name ();
555+
556+ }else if (protectionStatus == StreamProtectionStatus .Status .ATTESTATION_REQUIRED .getValue ()){
557+ resultStatus = poToken != null ? PoTokenStatus .INVALID .name () : PoTokenStatus .MISSING .name ();
558+ }else {
559+ resultStatus = PoTokenStatus .UNKNOWN .name ();
560+ }
561+
562+ streamProtectionStatus = resultStatus ;
563+
564+ }
565+
523566 private void processSnackbarMessage () {
524567 int skip = sabrContextUpdates .get (sabrContextsToSend .get (sabrContextsToSend .size () - 1 )).value .field1 .skip ;
525568 if (skip >= 60000 ){
0 commit comments