22
33import com .grack .nanojson .JsonWriter ;
44import com .sedmelluq .discord .lavaplayer .tools .DataFormatTools ;
5- import com .sedmelluq .discord .lavaplayer .tools .ExceptionTools ;
65import com .sedmelluq .discord .lavaplayer .tools .JsonBrowser ;
7- import com .sedmelluq .discord .lavaplayer .tools .io .HttpClientTools ;
86import com .sedmelluq .discord .lavaplayer .tools .io .HttpInterface ;
7+ import dev .lavalink .youtube .ExceptionWithResponseBody ;
98import dev .lavalink .youtube .http .YoutubeHttpContextFilter ;
109import dev .lavalink .youtube .track .format .StreamFormat ;
1110import org .apache .http .HttpEntity ;
12- import org .apache .http .HttpRequest ;
1311import org .apache .http .client .methods .CloseableHttpResponse ;
14- import org .apache .http .client .methods .HttpGet ;
1512import org .apache .http .client .methods .HttpPost ;
1613import org .apache .http .client .utils .URIBuilder ;
1714import org .apache .http .entity .ContentType ;
1815import org .apache .http .entity .StringEntity ;
1916import org .apache .http .util .EntityUtils ;
2017import org .jetbrains .annotations .NotNull ;
21- import org .jetbrains .annotations .Nullable ;
2218import org .slf4j .Logger ;
2319import org .slf4j .LoggerFactory ;
2420
3531public class RemoteCipherManager implements CipherManager {
3632 private static final Logger log = LoggerFactory .getLogger (RemoteCipherManager .class );
3733
38- private final Object cipherLoadLock ;
3934 private final @ NotNull String remoteUrl ;
4035
4136 protected volatile CachedPlayerScript cachedPlayerScript ;
@@ -44,7 +39,6 @@ public class RemoteCipherManager implements CipherManager {
4439 * Create a new remote cipher manager
4540 */
4641 public RemoteCipherManager (@ NotNull String remoteUrl ) {
47- this .cipherLoadLock = new Object ();
4842 this .remoteUrl = remoteUrl ;
4943 }
5044
@@ -65,50 +59,39 @@ public String getRemoteUrl() {
6559 */
6660 @ NotNull
6761 public URI resolveFormatUrl (@ NotNull HttpInterface httpInterface ,
68- @ NotNull String playerScript ,
69- @ NotNull StreamFormat format ) throws IOException {
62+ @ NotNull String playerScript ,
63+ @ NotNull StreamFormat format ) throws IOException {
7064 String signature = format .getSignature ();
7165 String nParameter = format .getNParameter ();
7266 URI initialUrl = format .getUrl ();
7367
7468 URIBuilder uri = new URIBuilder (initialUrl );
7569
7670 if (!DataFormatTools .isNullOrEmpty (signature )) {
77- return getUri (httpInterface , format .getSignature (), format .getSignatureKey (), nParameter , initialUrl , playerScript );
71+ return getUri (configureHttpInterface ( httpInterface ) , format .getSignature (), format .getSignatureKey (), nParameter , initialUrl , playerScript );
7872 }
7973
80- uri .setParameter ("n" , decipherN (httpInterface , nParameter , playerScript ));
74+ uri .setParameter ("n" , decipherN (configureHttpInterface ( httpInterface ) , nParameter , playerScript ));
8175 try {
8276 return uri .build ();
8377 } catch (URISyntaxException f ) {
8478 throw new RuntimeException (f );
8579 }
8680 }
8781
88- private CachedPlayerScript getPlayerScript (@ NotNull HttpInterface httpInterface ) {
89- synchronized (cipherLoadLock ) {
90- try (CloseableHttpResponse response = httpInterface .execute (new HttpGet ("https://www.youtube.com/embed/" ))) {
91- HttpClientTools .assertSuccessWithContent (response , "fetch player script (embed)" );
92-
93- String responseText = EntityUtils .toString (response .getEntity ());
94- String scriptUrl = DataFormatTools .extractBetween (responseText , "\" jsUrl\" :\" " , "\" " );
95-
96- if (scriptUrl == null ) {
97- throw throwWithDebugInfo (log , null , "no jsUrl found" , "html" , responseText );
98- }
99-
100- return (cachedPlayerScript = new CachedPlayerScript (scriptUrl ));
101- } catch (IOException e ) {
102- throw ExceptionTools .toRuntimeException (e );
103- }
104- }
105- }
106-
10782 public CachedPlayerScript getCachedPlayerScript (@ NotNull HttpInterface httpInterface ) {
10883 if (cachedPlayerScript == null || System .currentTimeMillis () >= cachedPlayerScript .expireTimestampMs ) {
109- synchronized (cipherLoadLock ) {
84+ synchronized (this ) {
11085 if (cachedPlayerScript == null || System .currentTimeMillis () >= cachedPlayerScript .expireTimestampMs ) {
111- return getPlayerScript (httpInterface );
86+ try {
87+ return (cachedPlayerScript = getPlayerScript (httpInterface ));
88+ } catch (RuntimeException e ) {
89+ if (e instanceof ExceptionWithResponseBody ) {
90+ throw throwWithDebugInfo (log , null , e .getMessage (), "html" , ((ExceptionWithResponseBody ) e ).getResponseBody ());
91+ }
92+
93+ throw e ;
94+ }
11295 }
11396 }
11497 }
@@ -117,20 +100,17 @@ public CachedPlayerScript getCachedPlayerScript(@NotNull HttpInterface httpInter
117100 }
118101
119102 public String getTimestamp (HttpInterface httpInterface , String sourceUrl ) throws IOException {
120- synchronized (cipherLoadLock ) {
103+ synchronized (this ) {
121104 log .debug ("Timestamp from script {}" , sourceUrl );
122-
123- return getTimestampFromScript (httpInterface , sourceUrl );
105+ return getTimestampFromScript (configureHttpInterface (httpInterface ), sourceUrl );
124106 }
125107 }
126108
127109 private String getRemoteEndpoint (String path ) {
128110 return remoteUrl .endsWith ("/" ) ? remoteUrl + path : remoteUrl + "/" + path ;
129111 }
130112
131-
132113 private String decipherN (HttpInterface httpInterface , String n , String playerScript ) throws IOException {
133- httpInterface .getContext ().setAttribute (YoutubeHttpContextFilter .CIPHER_REQUEST_ATTRIBUTE , true );
134114 HttpPost request = new HttpPost (getRemoteEndpoint ("decrypt_signature" ));
135115
136116 log .debug ("Deciphering N param: {} with script: {}" , n , playerScript );
@@ -154,14 +134,14 @@ private String decipherN(HttpInterface httpInterface, String n, String playerScr
154134 }
155135
156136 JsonBrowser json = JsonBrowser .parse (responseBody );
157-
158137 String returnedN = json .get ("decrypted_n_sig" ).text ();
159138
160139 log .debug ("Received decrypted N: {}" , returnedN );
161140
162141 if (returnedN != null && !returnedN .isEmpty ()) {
163142 return returnedN ;
164143 }
144+
165145 return "" ;
166146 } else {
167147 throw new IOException ("Decryption proxy request failed with status code: " + statusCode + ". Response: " + responseBody );
@@ -170,7 +150,6 @@ private String decipherN(HttpInterface httpInterface, String n, String playerScr
170150 }
171151
172152 private URI getUri (HttpInterface httpInterface , String sig , String sigKey , String nParam , URI initial , String playerScript ) throws IOException {
173- httpInterface .getContext ().setAttribute (YoutubeHttpContextFilter .CIPHER_REQUEST_ATTRIBUTE , true );
174153 HttpPost request = new HttpPost (getRemoteEndpoint ("decrypt_signature" ));
175154
176155 log .debug ("Deciphering N param: {} and Signature: {} with script: {}" , nParam , sig , playerScript );
@@ -231,7 +210,6 @@ private URI getUri(HttpInterface httpInterface, String sig, String sigKey, Strin
231210 }
232211
233212 private String getTimestampFromScript (HttpInterface httpInterface , String playerScript ) throws IOException {
234- httpInterface .getContext ().setAttribute (YoutubeHttpContextFilter .CIPHER_REQUEST_ATTRIBUTE , true );
235213 HttpPost request = new HttpPost (getRemoteEndpoint ("get_sts" ));
236214
237215 log .debug ("Getting timestamp for script: {}" , playerScript );
@@ -263,5 +241,9 @@ private String getTimestampFromScript(HttpInterface httpInterface, String player
263241 }
264242 }
265243
244+ public HttpInterface configureHttpInterface (HttpInterface httpInterface ) {
245+ httpInterface .getContext ().setAttribute (YoutubeHttpContextFilter .REMOTE_CIPHER_REQUEST_ATTRIBUTE , true );
246+ return httpInterface ;
247+ }
266248}
267249
0 commit comments