Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call pre-connect urls before gvideo url #1

Merged
merged 1 commit into from
Oct 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ public YoutubeAudioSourceManager(boolean allowSearch, HttpRoutePlanner routePlan
signatureCipherManager = new YoutubeSignatureCipherManager();

HttpRequestModifier requestModifier = request -> {
if(request.getURI().toString().contains("generate_204"))
return;
request.setHeader("x-youtube-client-name", "1");
request.setHeader("x-youtube-client-version", "2.20191008.04.01");
};
Expand Down Expand Up @@ -221,12 +223,12 @@ private AudioItem loadItemOnce(AudioReference reference) {
*/
public AudioItem loadTrackWithVideoId(String videoId, boolean mustExist) {
try (HttpInterface httpInterface = getHttpInterface()) {
JsonBrowser info = getTrackInfoFromMainPage(httpInterface, videoId, mustExist);
if (info == null) {
final YoutubeJsonResponse jsonResponse = getTrackInfoFromMainPage(httpInterface, videoId, mustExist);
if (jsonResponse.getPlayerInfo() == null) {
return AudioReference.NO_TRACK;
}

JsonBrowser args = info.get("args");
JsonBrowser args = jsonResponse.getPlayerInfo().get("args");
boolean useOldFormat = args.get("player_response").isNull();

if (useOldFormat) {
Expand Down Expand Up @@ -380,7 +382,7 @@ private AudioItem loadLinkedPlaylistWithId(String playlistId, String videoId) {
* <code>false</code>.
* @throws IOException On network error.
*/
public JsonBrowser getTrackInfoFromMainPage(HttpInterface httpInterface, String videoId, boolean mustExist) throws IOException {
public YoutubeJsonResponse getTrackInfoFromMainPage(HttpInterface httpInterface, String videoId, boolean mustExist) throws IOException {
String url = getWatchUrl(videoId) + "&pbj=1&hl=en";

try (CloseableHttpResponse response = httpInterface.execute(new HttpGet(url))) {
Expand All @@ -396,10 +398,13 @@ public JsonBrowser getTrackInfoFromMainPage(HttpInterface httpInterface, String
JsonBrowser json = JsonBrowser.parse(responseText);
JsonBrowser playerInfo = null;
JsonBrowser statusBlock = null;
JsonBrowser preConnectUrls = null;

for (JsonBrowser child : json.values()) {
if (child.isMap()) {
if (!child.get("player").isNull()) {
if(!child.get("preconnect").isNull()) {
preConnectUrls = child.get("preconnect");
} else if (!child.get("player").isNull()) {
playerInfo = child.get("player");
} else if (!child.get("playerResponse").isNull()) {
statusBlock = child.get("playerResponse").safeGet("playabilityStatus");
Expand All @@ -413,7 +418,7 @@ public JsonBrowser getTrackInfoFromMainPage(HttpInterface httpInterface, String
throw new RuntimeException("No player info block.");
}

return playerInfo;
return new YoutubeJsonResponse(playerInfo, preConnectUrls);
} catch (Exception e) {
throw new FriendlyException("Received unexpected response from YouTube.", SUSPICIOUS,
new RuntimeException("Failed to parse: " + responseText, e));
Expand Down Expand Up @@ -626,6 +631,32 @@ private static UrlInfo getUrlInfo(String url, boolean retryValidPart) {
}
}

static class YoutubeJsonResponse {
private final JsonBrowser playerInfo;
private final String[] preConnectUrls;

private YoutubeJsonResponse(final JsonBrowser player, final JsonBrowser preConnectUrls) {
this.playerInfo = player;
if(preConnectUrls == null) {
this.preConnectUrls = new String[0];
return;
}
final List<JsonBrowser> entries = preConnectUrls.values();
this.preConnectUrls = new String[entries.size()];
for (int i = 0; i < entries.size(); i++) {
this.preConnectUrls[i] = entries.get(i).as(String.class);
}
}

public JsonBrowser getPlayerInfo() {
return playerInfo;
}

public String[] getPreConnectUrls() {
return preConnectUrls;
}
}

private static class UrlInfo {
private final String path;
private final Map<String, String> parameters;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,16 @@ public class YoutubeAudioTrack extends DelegatedAudioTrack {
.build();

private final YoutubeAudioSourceManager sourceManager;
private final String refererUrl;

/**
* @param trackInfo Track info
* @param sourceManager Source manager which was used to find this track
*/
public YoutubeAudioTrack(AudioTrackInfo trackInfo, YoutubeAudioSourceManager sourceManager) {
super(trackInfo);

this.sourceManager = sourceManager;
this.refererUrl = "https://www.youtube.com/watch?v=" + trackInfo.identifier;
}

@Override
Expand Down Expand Up @@ -126,16 +127,19 @@ private Tuple<FormatWithUrl, Boolean> loadBestFormatWithUrl(HttpInterface httpIn
return new Tuple<>(cachedPlaybackFormat, true);
}

JsonBrowser info = getTrackInfo(httpInterface);
final YoutubeAudioSourceManager.YoutubeJsonResponse jsonResponse = getTrackInfo(httpInterface);

String playerScript = extractPlayerScriptFromInfo(info);
List<YoutubeTrackFormat> formats = loadTrackFormats(info, httpInterface, playerScript);
String playerScript = extractPlayerScriptFromInfo(jsonResponse.getPlayerInfo());
List<YoutubeTrackFormat> formats = loadTrackFormats(jsonResponse.getPlayerInfo(), httpInterface, playerScript);
YoutubeTrackFormat format = findBestSupportedFormat(formats);

URI signedUrl = sourceManager.getCipherManager().getValidUrl(httpInterface, playerScript, format);
FormatWithUrl bestFormat = new FormatWithUrl(format, signedUrl);

playbackFormatCache.put(videoId, bestFormat);

callPreconnectUrls(httpInterface, jsonResponse.getPreConnectUrls());

return new Tuple<>(bestFormat, false);
}

Expand All @@ -149,7 +153,17 @@ public AudioSourceManager getSourceManager() {
return sourceManager;
}

private JsonBrowser getTrackInfo(HttpInterface httpInterface) throws Exception {
private void callPreconnectUrls(final HttpInterface httpInterface, final String[] preConnectUrls) throws IOException {
for (final String url : preConnectUrls) {
final HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("Accept", "image/webp, */*");
httpGet.setHeader("Referer", this.refererUrl);
final CloseableHttpResponse response = httpInterface.execute(httpGet);
response.close();
}
}

private YoutubeAudioSourceManager.YoutubeJsonResponse getTrackInfo(HttpInterface httpInterface) throws Exception {
return sourceManager.getTrackInfoFromMainPage(httpInterface, getIdentifier(), true);
}

Expand Down