2424import dev .lavalink .youtube .track .YoutubeAudioTrack ;
2525import org .apache .http .client .methods .CloseableHttpResponse ;
2626import org .apache .http .client .methods .HttpGet ;
27+ import org .jetbrains .annotations .NotNull ;
28+ import org .jetbrains .annotations .Nullable ;
2729import org .slf4j .Logger ;
2830import org .slf4j .LoggerFactory ;
2931
3941
4042@ SuppressWarnings ("RegExpUnnecessaryNonCapturingGroup" )
4143public class YoutubeAudioSourceManager implements AudioSourceManager {
42- // TODO: consider adding notnull/nullable annotations
4344 // TODO: connect timeout = 16000ms, read timeout = 8000ms (as observed from scraped youtube config)
4445 // TODO: look at possibly scraping jsUrl from WEB config to save a request
4546 // TODO: search providers use cookieless httpinterfacemanagers. should this do the same?
@@ -58,12 +59,11 @@ public class YoutubeAudioSourceManager implements AudioSourceManager {
5859 private static final Pattern mainDomainPattern = Pattern .compile ("^" + PROTOCOL_REGEX + DOMAIN_REGEX + "/.*" );
5960 private static final Pattern shortHandPattern = Pattern .compile ("^" + PROTOCOL_REGEX + "(?:" + DOMAIN_REGEX + "/(?:live|embed|shorts)|" + SHORT_DOMAIN_REGEX + ")/(?<id>.*)" );
6061
62+ protected final HttpInterfaceManager httpInterfaceManager ;
63+ protected final boolean allowSearch ;
64+ protected final Client [] clients ;
6165
62- protected HttpInterfaceManager httpInterfaceManager = HttpClientTools .createDefaultThreadLocalManager ();
63- protected boolean allowSearch ;
64- protected Client [] clients ;
65-
66- protected SignatureCipherManager cipherManager ;
66+ protected final SignatureCipherManager cipherManager ;
6767
6868 public YoutubeAudioSourceManager () {
6969 this (true );
@@ -80,7 +80,7 @@ public YoutubeAudioSourceManager(boolean allowSearch) {
8080 * @param clients The clients to use for track loading. They will be queried in
8181 * the order they are provided.
8282 */
83- public YoutubeAudioSourceManager (Client ... clients ) {
83+ public YoutubeAudioSourceManager (@ NotNull Client ... clients ) {
8484 this (true , clients );
8585 }
8686
@@ -92,7 +92,8 @@ public YoutubeAudioSourceManager(Client... clients) {
9292 * @param clients The clients to use for track loading. They will be queried in
9393 * the order they are provided.
9494 */
95- public YoutubeAudioSourceManager (boolean allowSearch , Client ... clients ) {
95+ public YoutubeAudioSourceManager (boolean allowSearch , @ NotNull Client ... clients ) {
96+ this .httpInterfaceManager = HttpClientTools .createDefaultThreadLocalManager ();
9697 this .allowSearch = allowSearch ;
9798 this .clients = clients == null ? new Client [0 ] : clients ;
9899 this .cipherManager = new SignatureCipherManager ();
@@ -115,7 +116,8 @@ public void setPlaylistPageCount(int count) {
115116 }
116117
117118 @ Override
118- public AudioItem loadItem (AudioPlayerManager manager , AudioReference reference ) {
119+ @ Nullable
120+ public AudioItem loadItem (@ NotNull AudioPlayerManager manager , @ NotNull AudioReference reference ) {
119121 try {
120122 return loadItemOnce (reference );
121123 } catch (FriendlyException exception ) {
@@ -128,11 +130,12 @@ public AudioItem loadItem(AudioPlayerManager manager, AudioReference reference)
128130 }
129131 }
130132
131- public AudioItem loadItemOnce (AudioReference reference ) {
133+ @ Nullable
134+ protected AudioItem loadItemOnce (@ NotNull AudioReference reference ) {
132135 Throwable lastException = null ;
133136
134137 try (HttpInterface httpInterface = httpInterfaceManager .getInterface ()) {
135- Router router = getRouter (reference .identifier , httpInterface );
138+ Router router = getRouter (httpInterface , reference .identifier );
136139
137140 if (router == null ) {
138141 return null ;
@@ -173,7 +176,8 @@ public AudioItem loadItemOnce(AudioReference reference) {
173176 return null ;
174177 }
175178
176- protected Router getRouter (String identifier , HttpInterface httpInterface ) {
179+ @ Nullable
180+ protected Router getRouter (@ NotNull HttpInterface httpInterface , @ NotNull String identifier ) {
177181 if (identifier .startsWith (SEARCH_PREFIX )) {
178182 if (allowSearch ) return (client ) -> client .loadSearch (this , httpInterface , identifier .substring (SEARCH_PREFIX .length ()).trim ());
179183 } else if (identifier .startsWith (MUSIC_SEARCH_PREFIX )) {
@@ -187,7 +191,7 @@ protected Router getRouter(String identifier, HttpInterface httpInterface) {
187191 if ("/watch" .equals (urlInfo .path )) {
188192 String videoId = urlInfo .parameters .get ("v" );
189193
190- if (videoId != null ) return routeFromVideoId (videoId , urlInfo , httpInterface );
194+ if (videoId != null ) return routeFromVideoId (httpInterface , videoId , urlInfo );
191195 } else if ("/playlist" .equals (urlInfo .path )) {
192196 String playlistId = urlInfo .parameters .get ("list" );
193197
@@ -201,7 +205,7 @@ protected Router getRouter(String identifier, HttpInterface httpInterface) {
201205 List <URI > redirects = httpInterface .getContext ().getRedirectLocations ();
202206
203207 if (redirects != null && !redirects .isEmpty ()) {
204- return getRouter (redirects .get (0 ).toString (), httpInterface );
208+ return getRouter (httpInterface , redirects .get (0 ).toString ());
205209 }
206210
207211 throw new FriendlyException ("Unable to process youtube watch_videos link" , SUSPICIOUS ,
@@ -215,20 +219,23 @@ protected Router getRouter(String identifier, HttpInterface httpInterface) {
215219 Matcher shortHandMatcher = shortHandPattern .matcher (identifier );
216220
217221 if (shortHandMatcher .matches ()) {
218- return routeFromVideoId (shortHandMatcher .group ("videoId" ), null , httpInterface );
222+ return routeFromVideoId (httpInterface , shortHandMatcher .group ("videoId" ), null );
219223 }
220224 }
221225 }
222226
223227 return null ;
224228 }
225229
226- protected Router routeFromVideoId (String videoId , UrlInfo urlInfo , HttpInterface httpInterface ) {
230+ @ Nullable
231+ protected Router routeFromVideoId (@ NotNull HttpInterface httpInterface ,
232+ @ NotNull String videoId ,
233+ @ Nullable UrlInfo urlInfo ) {
227234 String trimmedId = videoId .length () > 11 ? videoId .substring (0 , 11 ) : videoId ;
228235
229236 if (!directVideoIdPattern .matcher (trimmedId ).matches ()) {
230237 return Router .none ;
231- } else if (urlInfo .parameters .containsKey ("list" )) {
238+ } else if (urlInfo != null && urlInfo .parameters .containsKey ("list" )) {
232239 String playlistId = urlInfo .parameters .get ("list" );
233240
234241 if (playlistId .startsWith ("RD" )) {
@@ -241,10 +248,12 @@ protected Router routeFromVideoId(String videoId, UrlInfo urlInfo, HttpInterface
241248 return (client ) -> client .loadVideo (this , httpInterface , trimmedId );
242249 }
243250
251+ @ NotNull
244252 public YoutubeAudioTrack buildAudioTrack (AudioTrackInfo trackInfo ) {
245253 return new YoutubeAudioTrack (trackInfo , this );
246254 }
247255
256+ @ NotNull
248257 public SignatureCipherManager getCipherManager () {
249258 return cipherManager ;
250259 }
@@ -254,7 +263,8 @@ public SignatureCipherManager getCipherManager() {
254263 * @param cls The class of the client to return.
255264 * @return The client instance, or null if it's not registered.
256265 */
257- public <T extends Client > T getClient (Class <T > cls ) {
266+ @ Nullable
267+ public <T extends Client > T getClient (@ NotNull Class <T > cls ) {
258268 for (Client client : clients ) {
259269 if (cls .isAssignableFrom (client .getClass ())) {
260270 return cls .cast (client );
@@ -264,14 +274,17 @@ public <T extends Client> T getClient(Class<T> cls) {
264274 return null ;
265275 }
266276
277+ @ NotNull
267278 public Client [] getClients () {
268279 return clients ;
269280 }
270281
282+ @ NotNull
271283 public HttpInterfaceManager getHttpInterfaceManager () {
272284 return httpInterfaceManager ;
273285 }
274286
287+ @ NotNull
275288 public HttpInterface getInterface () {
276289 return httpInterfaceManager .getInterface ();
277290 }
@@ -287,7 +300,8 @@ public void encodeTrack(AudioTrack track, DataOutput output) {
287300 }
288301
289302 @ Override
290- public AudioTrack decodeTrack (AudioTrackInfo trackInfo , DataInput input ) {
303+ @ NotNull
304+ public AudioTrack decodeTrack (@ NotNull AudioTrackInfo trackInfo , @ NotNull DataInput input ) {
291305 return new YoutubeAudioTrack (trackInfo , this );
292306 }
293307
@@ -300,6 +314,7 @@ public void shutdown() {
300314 protected interface Router {
301315 Router none = (unused ) -> AudioReference .NO_TRACK ;
302316
303- AudioItem route (Client client ) throws CannotBeLoaded , IOException ;
317+ @ Nullable
318+ AudioItem route (@ NotNull Client client ) throws CannotBeLoaded , IOException ;
304319 }
305320}
0 commit comments