Skip to content

Commit

Permalink
Merge pull request #29 from kotvertolet/release_0.3.0
Browse files Browse the repository at this point in the history
#28 Fix NPE, implement new callback based extract function
  • Loading branch information
antonyhaman authored Jun 6, 2020
2 parents 42422e9 + f064221 commit 522c897
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 35 deletions.
4 changes: 2 additions & 2 deletions youtubejextractor/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ android {
defaultConfig {
minSdkVersion 19
targetSdkVersion 29
versionCode 4
versionName "0.2.9"
versionCode 5
versionName "0.3.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
lintOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,38 +84,73 @@ public void checkLiveStream() throws YoutubeRequestException, ExtractionExceptio
checkIfStreamsWork(videoData);
}

@Test
public void checkLiveStreamWithoutAdaptiveStreams() throws YoutubeRequestException, ExtractionException {
videoData = youtubeJExtractor.extract("up0fWFqgC6g");
assertTrue(videoData.getVideoDetails().isLiveContent());
assertNotNull(videoData.getStreamingData().getDashManifestUrl());
assertNotNull(videoData.getStreamingData().getHlsManifestUrl());
assertEquals(0, videoData.getStreamingData().getAdaptiveAudioStreams().size());
assertEquals(0, videoData.getStreamingData().getAdaptiveVideoStreams().size());
}

@Test
public void checkMuxedStreamNonEncrypted() throws YoutubeRequestException, ExtractionException {
videoData = youtubeJExtractor.extract("8QyDmvuts9s");
checkIfStreamsWork(videoData);
}

private void checkIfStreamsWork(YoutubeVideoData videoData) throws YoutubeRequestException {
String streamErrorMask = "Stream wasn't processed correctly, stream details:\\n %s";
Response<ResponseBody> responseBody;
if (videoData.getVideoDetails().isLiveContent()) {
responseBody = youtubeSiteNetwork.getStream(videoData.getStreamingData().getDashManifestUrl());
assertNotNull(responseBody);
assertTrue(responseBody.isSuccessful());
responseBody = youtubeSiteNetwork.getStream(videoData.getStreamingData().getHlsManifestUrl());
assertNotNull(responseBody);
assertTrue(responseBody.isSuccessful());
} else {
for (AdaptiveVideoStream adaptiveVideoStream : videoData.getStreamingData().getAdaptiveVideoStreams()) {
responseBody = youtubeSiteNetwork.getStream(adaptiveVideoStream.getUrl());
assertThat(String.format(streamErrorMask, adaptiveVideoStream.toString()), responseBody, is(not(nullValue())));
assertThat(String.format(streamErrorMask, adaptiveVideoStream.toString()), responseBody.isSuccessful(), is(true));
@Test
public void checkCallbackBasedExtractionSuccessful() {
youtubeJExtractor.extract("iIKxyDRjecU", new JExtractorCallback() {
@Override
public void onSuccess(YoutubeVideoData videoData) {
checkIfStreamsWork(videoData);
}
for (AdaptiveAudioStream adaptiveAudioStream : videoData.getStreamingData().getAdaptiveAudioStreams()) {
responseBody = youtubeSiteNetwork.getStream(adaptiveAudioStream.getUrl());
assertThat(String.format(streamErrorMask, adaptiveAudioStream.toString()), responseBody, is(not(nullValue())));
assertThat(String.format(streamErrorMask, adaptiveAudioStream.toString()), responseBody.isSuccessful(), is(true));

@Override
public void onNetworkException(YoutubeRequestException e) {
fail("Network exception occurred");
}

@Override
public void onError(Exception exception) {
fail("Extraction exception occurred");
}
for (MuxedStream muxedStream : videoData.getStreamingData().getMuxedStreams()) {
responseBody = youtubeSiteNetwork.getStream(muxedStream.getUrl());
assertThat(String.format(streamErrorMask, muxedStream.toString()), responseBody, is(not(nullValue())));
assertThat(String.format(streamErrorMask, muxedStream.toString()), responseBody.isSuccessful(), is(true));
});
}

private void checkIfStreamsWork(YoutubeVideoData videoData) {
String streamErrorMask = "Stream wasn't processed correctly, stream details:\\n %s";
Response<ResponseBody> responseBody;
try {
if (videoData.getVideoDetails().isLiveContent()) {
responseBody = youtubeSiteNetwork.getStream(videoData.getStreamingData().getDashManifestUrl());
assertNotNull(responseBody);
assertTrue(responseBody.isSuccessful());
responseBody = youtubeSiteNetwork.getStream(videoData.getStreamingData().getHlsManifestUrl());
assertNotNull(responseBody);
assertTrue(responseBody.isSuccessful());
} else {
for (AdaptiveVideoStream adaptiveVideoStream : videoData.getStreamingData().getAdaptiveVideoStreams()) {
responseBody = youtubeSiteNetwork.getStream(adaptiveVideoStream.getUrl());
assertThat(String.format(streamErrorMask, adaptiveVideoStream.toString()), responseBody, is(not(nullValue())));
assertThat(String.format(streamErrorMask, adaptiveVideoStream.toString()), responseBody.isSuccessful(), is(true));
}
for (AdaptiveAudioStream adaptiveAudioStream : videoData.getStreamingData().getAdaptiveAudioStreams()) {
responseBody = youtubeSiteNetwork.getStream(adaptiveAudioStream.getUrl());
assertThat(String.format(streamErrorMask, adaptiveAudioStream.toString()), responseBody, is(not(nullValue())));
assertThat(String.format(streamErrorMask, adaptiveAudioStream.toString()), responseBody.isSuccessful(), is(true));
}
for (MuxedStream muxedStream : videoData.getStreamingData().getMuxedStreams()) {
responseBody = youtubeSiteNetwork.getStream(muxedStream.getUrl());
assertThat(String.format(streamErrorMask, muxedStream.toString()), responseBody, is(not(nullValue())));
assertThat(String.format(streamErrorMask, muxedStream.toString()), responseBody.isSuccessful(), is(true));
}
}
}
catch (YoutubeRequestException e) {
fail(e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.github.kotvertolet.youtubejextractor;

import com.github.kotvertolet.youtubejextractor.exception.YoutubeRequestException;
import com.github.kotvertolet.youtubejextractor.models.youtube.videoData.YoutubeVideoData;

public interface JExtractorCallback {

void onSuccess(YoutubeVideoData videoData);

void onNetworkException(YoutubeRequestException e);

void onError(Exception exception);
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,39 @@ public YoutubeJExtractor(OkHttpClient client) {
public YoutubeVideoData extract(String videoId) throws ExtractionException, YoutubeRequestException {
try {
LogI(TAG, "Extracting video data from youtube page");
PlayerResponse playerResponse = extractYoutubeVideoData(videoId);
if (areStreamsAreEncrypted(playerResponse)) {
LogI(TAG, "Streams are encrypted, decrypting");
decryptYoutubeStreams(playerResponse);
}
else LogI(TAG, "Streams are not encrypted");
PlayerResponse playerResponse = extractAndPrepareVideoData(videoId);
return new YoutubeVideoData(playerResponse.getVideoDetails(), playerResponse.getRawStreamingData());
} catch (SignatureDecryptionException e) {
throw new ExtractionException(e);
}
}

public void extract(String videoId, JExtractorCallback callback) {
try {
PlayerResponse playerResponse = extractAndPrepareVideoData(videoId);
callback.onSuccess(new YoutubeVideoData(playerResponse.getVideoDetails(), playerResponse.getRawStreamingData()));
}
catch (SignatureDecryptionException | ExtractionException e) {
callback.onError(e);
}
catch (YoutubeRequestException e) {
callback.onNetworkException(e);
}

}

private PlayerResponse extractAndPrepareVideoData(String videoId) throws ExtractionException, YoutubeRequestException, SignatureDecryptionException {
LogI(TAG, "Extracting video data from youtube page");
PlayerResponse playerResponse = extractYoutubeVideoData(videoId);
if (checkIfStreamsAreEncrypted(playerResponse)) {
LogI(TAG, "Streams are encrypted, decrypting");
decryptYoutubeStreams(playerResponse);
}
else LogI(TAG, "Streams are not encrypted");
return playerResponse;
}


private PlayerResponse extractYoutubeVideoData(String videoId) throws ExtractionException, YoutubeRequestException {
PlayerResponse playerResponse;
try {
Expand Down Expand Up @@ -150,7 +171,7 @@ private String getVideoInfoForAgeRestrictedVideo(String videoId) throws Extracti
}
}

private boolean areStreamsAreEncrypted(PlayerResponse playerResponse) throws ExtractionException {
private boolean checkIfStreamsAreEncrypted(PlayerResponse playerResponse) throws ExtractionException {
// Even if a single stream is encrypted it means they all are
RawStreamingData rawStreamingData = playerResponse.getRawStreamingData();
if (rawStreamingData != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ public StreamingData[] newArray(int size) {
@SerializedName("probeUrl")
private String probeUrl;
@Expose
private List<AdaptiveAudioStream> adaptiveAudioStreams;
private List<AdaptiveAudioStream> adaptiveAudioStreams = new ArrayList<>();
@Expose
private List<AdaptiveVideoStream> adaptiveVideoStreams;
private List<AdaptiveVideoStream> adaptiveVideoStreams = new ArrayList<>();

public StreamingData() {
}
Expand All @@ -54,7 +54,10 @@ public StreamingData(RawStreamingData rawStreamingData) {
this.hlsManifestUrl = rawStreamingData.getHlsManifestUrl();
this.probeUrl = rawStreamingData.getProbeUrl();
this.muxedStreams = rawStreamingData.getMuxedStreams();
sortAdaptiveStreamsByType(rawStreamingData.getAdaptiveStreams());
List<AdaptiveStream> adaptiveStreams = rawStreamingData.getAdaptiveStreams();
if (adaptiveStreams != null && adaptiveStreams.size() > 0) {
sortAdaptiveStreamsByType(adaptiveStreams);
}
}

public StreamingData(String expiresInSeconds, String dashManifestUrl, String hlsManifestUrl, List<AdaptiveAudioStream> adaptiveAudioStreams, List<AdaptiveVideoStream> adaptiveVideoStreams) {
Expand Down

0 comments on commit 522c897

Please sign in to comment.