@@ -1495,4 +1495,90 @@ public static AudioTrackType extractAudioTrackType(final String streamUrl) {
14951495 return null ;
14961496 }
14971497 }
1498+
1499+ public static String getVisitorDataFromInnertube (
1500+ @ Nonnull final InnertubeClientRequestInfo innertubeClientRequestInfo ,
1501+ @ Nonnull final Localization localization ,
1502+ @ Nonnull final ContentCountry contentCountry ,
1503+ @ Nonnull final Map <String , List <String >> httpHeaders ,
1504+ @ Nonnull final String innerTubeDomain ,
1505+ @ Nullable final String embedUrl ) throws IOException , ExtractionException {
1506+ final JsonBuilder <JsonObject > builder = prepareJsonBuilder (
1507+ localization , contentCountry , innertubeClientRequestInfo , embedUrl );
1508+
1509+ final byte [] body = JsonWriter .string (builder .done ())
1510+ .getBytes (StandardCharsets .UTF_8 );
1511+
1512+ final String visitorData = JsonUtils .toJsonObject (getValidJsonResponseBody (getDownloader ()
1513+ .postWithContentTypeJson (innerTubeDomain + "visitor_id" , httpHeaders , body )))
1514+ .getObject ("responseContext" )
1515+ .getString ("visitorData" );
1516+
1517+ if (isNullOrEmpty (visitorData )) {
1518+ throw new ParsingException ("Could not get visitorData" );
1519+ }
1520+
1521+ return visitorData ;
1522+ }
1523+
1524+ @ Nonnull
1525+ static JsonBuilder <JsonObject > prepareJsonBuilder (
1526+ @ Nonnull final Localization localization ,
1527+ @ Nonnull final ContentCountry contentCountry ,
1528+ @ Nonnull final InnertubeClientRequestInfo innertubeClientRequestInfo ,
1529+ @ Nullable final String embedUrl ) {
1530+ final JsonBuilder <JsonObject > builder = JsonObject .builder ()
1531+ .object ("context" )
1532+ .object ("client" )
1533+ .value ("clientName" , innertubeClientRequestInfo .clientInfo .clientName )
1534+ .value ("clientVersion" , innertubeClientRequestInfo .clientInfo .clientVersion )
1535+ .value ("clientScreen" , innertubeClientRequestInfo .clientInfo .clientScreen )
1536+ .value ("platform" , innertubeClientRequestInfo .deviceInfo .platform );
1537+
1538+ if (innertubeClientRequestInfo .clientInfo .visitorData != null ) {
1539+ builder .value ("visitorData" , innertubeClientRequestInfo .clientInfo .visitorData );
1540+ }
1541+
1542+ if (innertubeClientRequestInfo .deviceInfo .deviceMake != null ) {
1543+ builder .value ("deviceMake" , innertubeClientRequestInfo .deviceInfo .deviceMake );
1544+ }
1545+ if (innertubeClientRequestInfo .deviceInfo .deviceModel != null ) {
1546+ builder .value ("deviceModel" , innertubeClientRequestInfo .deviceInfo .deviceModel );
1547+ }
1548+ if (innertubeClientRequestInfo .deviceInfo .osName != null ) {
1549+ builder .value ("osName" , innertubeClientRequestInfo .deviceInfo .osName );
1550+ }
1551+ if (innertubeClientRequestInfo .deviceInfo .osVersion != null ) {
1552+ builder .value ("osVersion" , innertubeClientRequestInfo .deviceInfo .osVersion );
1553+ }
1554+ if (innertubeClientRequestInfo .deviceInfo .androidSdkVersion > 0 ) {
1555+ builder .value ("androidSdkVersion" ,
1556+ innertubeClientRequestInfo .deviceInfo .androidSdkVersion );
1557+ }
1558+
1559+ builder .value ("hl" , localization .getLocalizationCode ())
1560+ .value ("gl" , contentCountry .getCountryCode ())
1561+ .value ("utcOffsetMinutes" , 0 )
1562+ .end ();
1563+
1564+ if (embedUrl != null ) {
1565+ builder .object ("thirdParty" )
1566+ .value ("embedUrl" , embedUrl )
1567+ .end ();
1568+ }
1569+
1570+ builder .object ("request" )
1571+ .array ("internalExperimentFlags" )
1572+ .end ()
1573+ .value ("useSsl" , true )
1574+ .end ()
1575+ .object ("user" )
1576+ // TODO: provide a way to enable restricted mode with:
1577+ // .value("enableSafetyMode", boolean)
1578+ .value ("lockedSafetyMode" , false )
1579+ .end ()
1580+ .end ();
1581+
1582+ return builder ;
1583+ }
14981584}
0 commit comments